diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..769b266b1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,64 @@ +--- +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: true +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: false +IndentFunctionDeclarationAfterType: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Always +... diff --git a/.cproject b/.cproject index 63cf57632..8f37d4ae1 100644 --- a/.cproject +++ b/.cproject @@ -1,7 +1,5 @@ - - - + @@ -22,12 +20,15 @@ - + + @@ -35,9 +36,14 @@ - - - + + + + + + + + @@ -48,49 +54,10 @@ - - - - - - - make - all - true - true - true - - - make - CFLAGS="-g" - install - true - true - true - - - make - CFLAGS="-g" - install - true - true - true - - - make - all - true - true - true - - - make - all - true - true - true - - + + + + @@ -198,4 +165,42 @@ + + + + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + diff --git a/.git-pre-commit b/.git-pre-commit new file mode 100755 index 000000000..69a71bea9 --- /dev/null +++ b/.git-pre-commit @@ -0,0 +1,51 @@ +#!/bin/bash + +# This hook purpose is to keep coding style consistent between all developers +# It is automatically installed in .git/hooks folder by cmake on first run. + +# From https://github.com/tatsuhiro-t/nghttp2/blob/master/pre-commit + +function invalid-format-detected { + cat git-clang-format.diff + echo "*****************" + echo "$0: Invalid coding style detected (see git-clang-format.diff for issues). Please correct it using one of the following:" + echo "1) Apply patch located at git-clang-format.diff using:" + echo " cd $(git rev-parse --show-toplevel) && $1" + echo "2) Use clang-format to correctly format source code using:" + echo " $2" + echo "3) Reformat these lines manually." + echo "*** Aborting commit.***" + exit 1 +} +function git-clang-format-diffing { + format_diff=$(which git-clang-format) + format_diff_options="--style=file" + + #only diffing commited files, ignored staged one + $format_diff $format_diff_options --diff $(git --no-pager diff --cached --name-status | grep -v '^D' | cut -f2) > git-clang-format.diff + + if ! grep -q -E '(no modified files to format|clang-format did not modify any files)' git-clang-format.diff; then + invalid-format-detected "git apply git-clang-format.diff" "clang-format $format_diff_options -i " + fi +} + +function clang-format-diff-diffing { + format_diff=$(find /usr/bin/ -name 'clang-format-diff*' -type f | tail -n1) + format_diff_options="-style file" + + git diff-index --cached --diff-filter=ACMR -p HEAD -- | $format_diff $format_diff_options -p1 > git-clang-format.diff + if [ -s git-clang-format.diff ]; then + invalid-format-detected "patch -p0 < git-clang-format.diff" "${format_diff/-diff/} $format_diff_options -i " + fi +} + +set -e +if which git-clang-format &>/dev/null; then + git-clang-format-diffing $@ +elif [ ! -z "$(find /usr/bin/ /usr/local/bin/ /opt/bin/ -name 'clang-format-diff*' -type f 2>/dev/null)" ]; then + # Warning! We need at least version 1.6... + clang-format-diff-diffing $@ +else + echo "$0: Please install clang-format (coding style checker) - could not find git-clang-format nor clang-format-diff in PATH. Skipping code verification..." + exit 0 +fi diff --git a/.gitignore b/.gitignore index df1c80316..36ee91daf 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ Specfile .anjuta_sym_db.db gtk-glade/version_date.h share/linphone.desktop +share/audio-assistant.desktop Debug/ build/macos/Info-linphone.plist coreapi/help/Doxyfile @@ -52,4 +53,42 @@ coreapi/help/registration coreapi/test_ecc coreapi/test_lsd gtk/version_date.h +specs.c +*.orig +*.rej +*.kdev4 +*.lo +*.la +*.swp +.deps +.libs +coreapi/test_numbers +coreapi/help/notify +share/fresh-rootca.pem +share/certdata.txt +tester/liblinphone_tester +tools/lp-gen-wrappers +tools/lpc2xml_test +tools/xml2lpc_test +coreapi/help/filetransfer +tester/receive_file.dump +tester/tmp.db +.DS_Store +Linphone.app +*.dmg +tester/linphone*.log +tester/linphone_log.txt +.tx/linphone-gtk.linphonedesktopin/ +po/linphone.pot +.tx/linphone-gtk.audio-assistantdesktopin/ +tester/linphone_log.gz.txt +tools/auto_answer +tools/lp-autoanswer +build/macos/pkg-distribution.xml +tester/record_for_lc_*.wav +tester/record-call_with_file_player.wav +tester/ZIDCache*.xml +tester/stereo-record.wav +.dirstamp +git-clang-format.diff 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/.tx/config b/.tx/config new file mode 100644 index 000000000..0b35698f1 --- /dev/null +++ b/.tx/config @@ -0,0 +1,20 @@ +[main] +host = https://www.transifex.com +minimum_perc = 1 + +[linphone-gtk.linphonepot] +file_filter = po/.po +source_file = po/linphone.pot +source_lang = en +type = PO + +[linphone-gtk.linphonedesktopin] +source_file = share/linphone.desktop.in +source_lang = en +type = DESKTOP + +[linphone-gtk.audio-assistantdesktopin] +source_file = share/audio-assistant.desktop.in +source_lang = en +type = DESKTOP + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..56329f10b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,270 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +cmake_minimum_required(VERSION 3.0) +project(LINPHONE C CXX) + + +set(LINPHONE_MAJOR_VERSION "3") +set(LINPHONE_MINOR_VERSION "8") +set(LINPHONE_MICRO_VERSION "5") +set(LINPHONE_VERSION "${LINPHONE_MAJOR_VERSION}.${LINPHONE_MINOR_VERSION}.${LINPHONE_MICRO_VERSION}") +set(LINPHONE_SO_VERSION "7") + +file(GLOB LINPHONE_PO_FILES RELATIVE "${CMAKE_SOURCE_DIR}/po" "${CMAKE_SOURCE_DIR}/po/*.po") +string(REGEX REPLACE "([a-zA-Z_]+)\\.po" "\\1" LINPHONE_ALL_LANGS_LIST "${LINPHONE_PO_FILES}") +string(REPLACE ";" " " LINPHONE_ALL_LANGS "${LINPHONE_ALL_LANGS_LIST}") + +include(CMakeDependentOption) + +option(ENABLE_STATIC "Build static library (default is shared library)." NO) +option(ENABLE_CONSOLE_UI "Turn on or off compilation of console interface." YES) +option(ENABLE_DATE "Use build date in internal version number." NO) +option(ENABLE_DOC "Enable documentation generation with Doxygen." YES) +option(ENABLE_GTK_UI "Turn on or off compilation of gtk interface." YES) +option(ENABLE_LDAP "Enable LDAP support." NO) +option(ENABLE_MSG_STORAGE "Turn on compilation of message storage." YES) +cmake_dependent_option(ENABLE_NOTIFY "Enable libnotify support." YES "ENABLE_GTK_UI" NO) +option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO) +option(ENABLE_TOOLS "Turn on or off compilation of tools." YES) +option(ENABLE_TUNNEL "Turn on compilation of tunnel support." NO) +option(ENABLE_TUTORIALS "Enable compilation of tutorials." YES) +option(ENABLE_UNIT_TESTS "Enable compilation of unit tests." YES) +option(ENABLE_UPNP "Build with uPnP support." YES) +option(ENABLE_VIDEO "Build with video support." YES) +cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENABLE_GTK_UI" NO) +option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO) +option(ENABLE_NLS "Build with internationalisation support" YES) + + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(CheckSymbolExists) +include(CMakePushCheckState) + +set(MSVC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/MSVC") +if(MSVC) + list(APPEND CMAKE_REQUIRED_INCLUDES "${MSVC_INCLUDE_DIR}") + + if(ENABLE_GTK_UI) + if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/intltool_win32.zip") + message(STATUS "Installing intltool") + file(DOWNLOAD http://ftp.acc.umu.se/pub/GNOME/binaries/win32/intltool/0.40/intltool_0.40.4-1_win32.zip "${CMAKE_CURRENT_BINARY_DIR}/intltool_win32.zip" SHOW_PROGRESS) + execute_process( + COMMAND "${CMAKE_COMMAND}" "-E" "tar" "x" "${CMAKE_CURRENT_BINARY_DIR}/intltool_win32.zip" + WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}" + ) + endif() + if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/gtk+-bundle_win32.zip") + message(STATUS "Installing GTK") + file(DOWNLOAD http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip "${CMAKE_CURRENT_BINARY_DIR}/gtk+-bundle_win32.zip" SHOW_PROGRESS) + execute_process( + COMMAND "${CMAKE_COMMAND}" "-E" "tar" "x" "${CMAKE_CURRENT_BINARY_DIR}/gtk+-bundle_win32.zip" + WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}" + ) + endif() + endif() +endif() + +find_package(BelleSIP REQUIRED) +find_package(Mediastreamer2 REQUIRED) +find_package(XML2 REQUIRED) +find_package(Zlib) +if(ENABLE_UNIT_TESTS) + find_package(CUnit) + if(CUNIT_FOUND) + cmake_push_check_state(RESET) + list(APPEND CMAKE_REQUIRED_INCLUDES ${CUNIT_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CUNIT_LIBRARIES}) + check_symbol_exists("CU_get_suite" "CUnit/CUnit.h" HAVE_CU_GET_SUITE) + check_symbol_exists("CU_curses_run_tests" "CUnit/CUnit.h" HAVE_CU_CURSES) + cmake_pop_check_state() + else() + message(WARNING "Could not find the cunit library!") + set(ENABLE_UNIT_TESTS OFF CACHE BOOL "Enable compilation of unit tests." FORCE) + endif() +endif() +if(ENABLE_TUNNEL) + find_package(Tunnel) + if(NOT TUNNEL_FOUND) + message(WARNING "Could not find the tunnel library!") + set(ENABLE_TUNNEL OFF CACHE BOOL "Enable tunnel support." FORCE) + endif() +endif() +if(ENABLE_MSG_STORAGE) + find_package(Sqlite3 REQUIRED) +endif() +if(ENABLE_NOTIFY) + find_package(Notify) + if(NOTIFY_FOUND) + set(HAVE_NOTIFY4 1) + else() + message(WARNING "Could not find the notify library!") + set(ENABLE_NOTIFY OFF CACHE BOOL "Enable libnotify support." FORCE) + endif() +endif() +if(ENABLE_GTK_UI) + if(WIN32) + set(GTK2_ADDITIONAL_SUFFIXES "../lib/glib-2.0/include" "../lib/gtk-2.0/include") + endif() + find_package(GTK2 2.18 REQUIRED gtk) + if(ENABLE_ASSISTANT AND GTK2_VERSION VERSION_LESS 2.22) + message(WARNING "You need at least GTK 2.22 to enable the assistant") + set(ENABLE_ASSISTANT OFF CACHE BOOL "Turn on assistant compiling." FORCE) + endif() +endif() +if(ENABLE_ASSISTANT) + set(BUILD_WIZARD 1) +endif() +if(ENABLE_NLS) + find_package(Gettext REQUIRED) + find_package(Intl REQUIRED) + include_directories(${INTL_INCLUDE_DIRS}) +endif() + +if(UNIX AND NOT APPLE) + include(CheckIncludeFiles) + check_include_files(libudev.h HAVE_LIBUDEV_H) +endif() + +include_directories( + include/ + coreapi/ + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/coreapi/ + ${BELLESIP_INCLUDE_DIRS} + ${MEDIASTREAMER2_INCLUDE_DIRS} + ${XML2_INCLUDE_DIRS} +) +if(ZLIB_FOUND) + include_directories(${ZLIB_INCLUDE_DIRS}) + set(HAVE_ZLIB 1) +endif() +if(SQLITE3_FOUND) + include_directories(${SQLITE3_INCLUDE_DIRS}) + add_definitions("-DMSG_STORAGE_ENABLED") +endif() +if(ENABLE_TUNNEL) + include_directories(${TUNNEL_INCLUDE_DIRS}) +endif() +if(ENABLE_DEBUG_LOGS) + add_definitions("-DDEBUG") +endif() +if(MSVC) + include_directories(${MSVC_INCLUDE_DIR}) +endif() +if(INTL_FOUND) + set(HAVE_INTL 1) + include_directories(${INTL_INCLUDE_DIRECTORIES}) +endif() + +add_definitions("-DIN_LINPHONE") + + +if(MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wuninitialized -Wdeclaration-after-statement -fno-strict-aliasing -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wuninitialized -Werror") + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments -Wno-array-bounds") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -Wno-array-bounds") + endif() + if(APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unknown-warning-option -Wno-tautological-compare -Wno-unused-function") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=unknown-warning-option -Wno-tautological-compare -Wno-unused-function") + endif() +endif() + + +set(GETTEXT_PACKAGE "linphone") +if(ENABLE_RELATIVE_PREFIX) + set(LINPHONE_DATA_DIR ".") +else() + set(LINPHONE_DATA_DIR "${CMAKE_INSTALL_PREFIX}") +endif() +set(LINPHONE_PLUGINS_DIR "${LINPHONE_DATA_DIR}/lib/liblinphone/plugins") +if(WIN32) + set(LINPHONE_CONFIG_DIR "Linphone") +endif() +set(PACKAGE_LOCALE_DIR "${LINPHONE_DATA_DIR}/share/locale") +set(PACKAGE_DATA_DIR "${LINPHONE_DATA_DIR}/share") +set(PACKAGE_SOUND_DIR "${LINPHONE_DATA_DIR}/share/sounds/linphone") +set(PACKAGE_RING_DIR "${PACKAGE_SOUND_DIR}/rings") +set(PACKAGE_FREEDESKTOP_DIR "${PACKAGE_DATA_DIR}/applications") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/config.h PROPERTIES GENERATED ON) +add_definitions(-DHAVE_CONFIG_H) + + +if(ENABLE_VIDEO) + add_definitions(-DVIDEO_ENABLED) +endif() + + +add_subdirectory(coreapi) +add_subdirectory(share) +if(ENABLE_CONSOLE_UI) + add_subdirectory(console) +endif() +if(ENABLE_GTK_UI) + add_subdirectory(gtk) + add_subdirectory(pixmaps) + add_subdirectory(po) +endif() +if(ENABLE_TOOLS) + add_subdirectory(tools) +endif() +if(ENABLE_UNIT_TESTS) + add_subdirectory(tester) +endif() + + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfigVersion.cmake" + VERSION ${LINPHONE_VERSION} + COMPATIBILITY AnyNewerVersion +) +export(EXPORT LinphoneTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/LinphoneTargets.cmake" + NAMESPACE BelledonneCommunications:: +) +configure_file(cmake/LinphoneConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfig.cmake" + @ONLY +) + +set(ConfigPackageLocation lib/cmake/Linphone) +install(EXPORT LinphoneTargets + FILE LinphoneTargets.cmake + NAMESPACE BelledonneCommunications:: + DESTINATION ${ConfigPackageLocation} +) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/LinphoneConfigVersion.cmake" + DESTINATION ${ConfigPackageLocation} +) diff --git a/COPYING b/COPYING index d60c31a97..365b8c279 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 @@ -338,3 +338,107 @@ proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. + + +------------------------------------------------------------------------------- + + +------------------------------------------------------- +About The Cisco-Provided Binary of OpenH264 Video Codec +------------------------------------------------------- + +Cisco provides this program under the terms of the BSD license. + +Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio +License from MPEG LA, at no cost to you, provided that the requirements and +conditions shown below in the AVC/H.264 Patent Portfolio sections are met. + +As with all AVC/H.264 codecs, you may also obtain your own patent license from +MPEG LA or from the individual patent owners, or proceed at your own risk. +Your rights from Cisco under the BSD license are not affected by this choice. + +For more information on the OpenH264 binary licensing, please see the OpenH264 +FAQ found at http://www.openh264.org/faq.html#binary + +A corresponding source code to this binary program is available under the same +BSD terms, which can be found at http://www.openh264.org + +----------- +BSD License +----------- + +Copyright © 2014 Cisco Systems, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------- +AVC/H.264 Patent Portfolio License Notice +----------------------------------------- + +The binary form of this Software is distributed by Cisco under the AVC/H.264 +Patent Portfolio License from MPEG LA, and is subject to the following +requirements, which may or may not be applicable to your use of this software: + +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE +PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE +REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD +(“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER +ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER +LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR +ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE +HTTP://WWW.MPEGLA.COM + +Accordingly, please be advised that content providers and broadcasters using +AVC/H.264 in their service may be required to obtain a separate use license +from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 +LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla + +--------------------------------------------- +AVC/H.264 Patent Portfolio License Conditions +--------------------------------------------- + +In addition, the Cisco-provided binary of this Software is licensed under +Cisco's license from MPEG LA only if the following conditions are met: + +1. The Cisco-provided binary is separately downloaded to an end user’s device, +and not integrated into or combined with third party software prior to being +downloaded to the end user’s device; + +2. The end user must have the ability to control (e.g., to enable, disable, or +re-enable) the use of the Cisco-provided binary; + +3. Third party software, in the location where end users can control the use of +the Cisco-provided binary, must display the following text: + + "OpenH264 Video Codec provided by Cisco Systems, Inc." + +4. Any third-party software that makes use of the Cisco-provided binary must +reproduce all of the above text, as well as this last condition, in the EULA +and/or in another location where licensing information is to be presented to +the end user. + + + + v1.0 + diff --git a/Makefile.am b/Makefile.am index f871d46a8..007dc5dbf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,9 +4,11 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts tools + coreapi console gtk share scripts tools tester include +GITVERSION=`cd $(top_srcdir) && git describe --always || echo $(VERSION)` + ACLOCAL_FLAGS=-I$(top_srcdir)/m4 @@ -20,11 +22,11 @@ OPTIONAL_SOUNDS=\ INSTALLDIR=$(abs_top_builddir)/linphone-install INSTALLDIR_WITH_PREFIX=$(INSTALLDIR)/$(prefix) -ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(VERSION).zip +ZIPFILE=$(abs_top_builddir)/$(PACKAGE)-win32-$(GITVERSION).zip ZIP_EXCLUDED=include lib \ $(OPTIONAL_SOUNDS) -SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-$(VERSION).zip +SDK_ZIPFILE=$(abs_top_builddir)/lib$(PACKAGE)-win32-sdk-$(GITVERSION).zip SDK_EXCLUDED= \ bin/linphone.exe \ lib/*.la \ @@ -37,7 +39,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)` @@ -51,7 +53,7 @@ PACKAGE_BUNDLE_FILE=$(top_srcdir)/build/macos/$(PACKAGE).bundle EXTRA_DIST = BUGS \ README.arm \ README.mingw \ - README.macos \ + README.macos.md \ autogen.sh \ linphone.spec \ linphone.spec.in \ @@ -90,10 +92,6 @@ rpm-novideo: rpm-base #a zip containing win32 binaries, suitable to generate an installer -if BUILD_ZRTP -WINBINDIST_FILES+=./bin/libzrtpcpp.dll ./bin/msys-1.0.dll ./bin/msys-crypto-1.0.0.dll -endif - if BUILD_TUNNEL WINBINDIST_FILES+=./bin/libtunnel-0.dll endif @@ -101,31 +99,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) @@ -164,14 +164,23 @@ filelist: zip fi \ done +### LOCALIZATION + +pull-transifex: + tx pull -af + +push-transifex: + $(MAKE) -C po update-po + tx push -s -f --no-interactive + ### WINDOWS setup.exe: filelist cp $(ISS_SCRIPT) $(INSTALLDIR_WITH_PREFIX)/. cd $(INSTALLDIR_WITH_PREFIX) && \ - $(ISCC) $(ISS_SCRIPT) - mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-$(VERSION)-setup.exe + $(ISCC) $(ISS_SCRIPT) + mv $(INSTALLDIR_WITH_PREFIX)/Output/setup.exe $(PACKAGE)-setup-$(GITVERSION).exe rm -rf $(INSTALLDIR_WITH_PREFIX)/Output rm -f $(INSTALLDIR_WITH_PREFIX)/$(PACKAGE_WIN32_FILELIST) rm -f $(INSTALLDIR_WITH_PREFIX)/$(ISS_SCRIPT) @@ -199,16 +208,15 @@ Portfile-devel: $(top_srcdir)/scripts/Portfile-devel.tmpl dist ### MAC MACAPPNAME=Linphone.app -MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip +MACAPPZIP=$(PACKAGE)-$(GITVERSION).app.zip +MACAPPDMG=$(PACKAGE)-$(GITVERSION).dmg +MACAPPPKG=$(PACKAGE)-$(GITVERSION).pkg BUNDLEPREFIX=./ BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME) -LIBICONV_HACK=$(top_builddir)/build/macos/libiconv.2.dylib +#a path prefix where additional libs can be cherry-picked by the bundler. +LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX=/usr/local -$(LIBICONV_HACK): - cd $(top_builddir)/build/macos && \ - wget http://download-mirror.savannah.gnu.org/releases/linphone/misc/libiconv.2.dylib - -bundle: $(LIBICONV_HACK) +Linphone.app: rm -rf $(INSTALLDIR) $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) @@ -216,13 +224,36 @@ bundle: $(LIBICONV_HACK) LINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \ LIBLINPHONE_INSTALL_PREFIX=$(INSTALLDIR_WITH_PREFIX) \ MS2_PLUGINS_INSTALL_PREFIX=$(prefix) \ + LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX=$(LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX) \ gtk-mac-bundler $(PACKAGE_BUNDLE_FILE) printf "[Pango]\nModuleFiles=./etc/pango/pango.modules\n" \ > $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig - sed -e 's:@executable_path/../Resources:../..:g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules - cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/. + sed -e 's:@executable_path.*/::g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules + patch -R ${BUNDLEDIR}/Contents/Resources/share/themes/Quartz/gtk-2.0/gtkrc ${srcdir}/build/macos/quartz-theme-gtkrc.patch + rm -f ${BUNDLEDIR}/Contents/Resources/lib/libopenh264* + +bundle: $(MACAPPNAME) cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd - + cd $(BUNDLEDIR)/.. && rm -f $(MAXAPPDMG) && hdiutil create $(MACAPPDMG) -srcfolder $(MACAPPNAME) -ov && cd - + +signed-bundle: $(MACAPPNAME) + codesign --deep -s "$(BUNDLE_SIGNING_ID)" $(BUNDLEDIR) + cd $(BUNDLEDIR)/.. && rm -f $(MAXAPPDMG) && hdiutil create $(MACAPPDMG) -srcfolder $(MACAPPNAME) -ov && cd - + +pkg: $(MACAPPNAME) + rm -rf ./packaging + mkdir -p ./packaging + cp ${srcdir}/COPYING ./packaging + cp ${srcdir}/pixmaps/linphone.png ./packaging + pkgbuild --install-location /Applications --scripts ${srcdir}/build/macos/pkg-scripts --component $(MACAPPNAME) ./packaging/linphone.pkg + productbuild --resources . --distribution ${srcdir}/build/macos/pkg-distribution.xml --package-path ./packaging $(MACAPPPKG) + +signed-pkg: pkg + mv $(MACAPPPKG) $(MACAPPPKG).tmp + productsign --sign "$(BUNDLE_SIGNING_ID)" $(MACAPPPKG).tmp $(MACAPPPKG) + rm -f $(MACAPPPKG).tmp + ### ### CLEAN @@ -230,6 +261,10 @@ 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 + +.PHONY: $(MACAPPNAME) pkg + + diff --git a/NEWS b/NEWS index 413970e6a..385b7831a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,121 @@ -linphone-3.xxx -- +linphone-3.8.5 -- June 30th, 2015 + * Fix bug about status icon on MacOSX. Attention request worked only once + * Fix crash at the end of the audio assistant + * Fix crash when configuring a remote provisioning + * Fix regression in the codec view. Codec which are not usable because + bandwidth limits are to low were not greyed anymore + * Fix language selection on Windows and MacOSX + * Add translation for 'Arabic' and 'Turkish' items in the language selection + list + +linphone-3.8.4 -- June 9th, 2015 + * Add a built-in XMLRPC client. Linphone does not depend on libsoup anymore + +linphone-3.8.3 -- June 4th, 2015 + * Fix status icons on all platforms (Windows, MacOS, non-KDE Linux desktop environment) + +linphone-3.8.2 -- May 7th, 2015 + Application level improvements: + * add support of the StatusNotifierItem standard to display a status icon on KDE5 + * auto-answering can be set through the preferences panel + * bug fixes + + Liblinphone level improvements: + * fix audio bug with opus codec + * fix ICE corner case not properly handled and resulting bad final ice status + * update SO version to 7 (it should have been done in 3.8.0) + * bug fixes + +linphone-3.8.1 -- March 31th, 2015 + Application level improvements: + * Auto-answer ability + * Improvement of UI appearance on Mac OSX + * Bug fixes + +linphone-3.8.0 -- March 11th, 2015 + Application level improvements: + * The video window has now controls in order to switch fullscreen mode and terminate call. + * The out of call video preview feature (to test camera) is moved into the settings and is no longer linked to the in-call video preview feature. + * Add an assistant to help users to set audio/video parameters + * Some ergonomics improvments (checkbox to set random port for UDP and TCP, ...) + * Lots of updated translations. Arabic translation has been added + * Experimental feature: play an MKV file by drag-and-dropping it on the video call window + + Liblinphone level improvements: + * Support for RTP/AVPF (RFC4585) for video streams, allowing fast transmission error recovery with VP8 codec only. + * API enhancements, most objects can be ref-counted. + * Add some getter funtctions to the call information API + * Add a function in the API to accept early-media calls + * Add a function to set the SIP transport timeout + * Add a function to change adaptive rate algorithm at runtime + * Add support of file transfer + * Call video recording feature, in mkv format (H264 streams only for the moment) + * Call playing feature: play an MKV file and send the audio/video stream through a call + * Local player API. Play WAV and MKV file and display video on a specified window display + * A wrapper for Python has been made + * Support of Wake Locks on Android + * Support of multicast IP addresses + * Support of incoming UPDATEs within dialog (RFC3311) + * Support of SRTP by using packages from GNU/Linux distributions + +linphone-3.7.0 -- February 20th, 2014 + Application level improvements: + * It is now possible to configure multiple proxy accounts with different transports (UDP, TCP, TLS) + * can work with IPv6 and IPv4 simultaneously + * User can choose video rendering method on Linux + * Video HD formats support added, leveraging on multiple cores for encoding if available + * Keyboard can be used for DTMF input + * Faster and higly responsive UI thanks to fully asynchronous operation of the liblinphone. + * Addon of opus codec + * Possibility to specify a remote provisionning http URI for configuration + * LDAP search integration for Linux and MacOSX + * is-composing notification in chat area + + Liblinphone level improvements thanks to new "belle-sip" SIP stack: + * multiple SIP transports simultaneously now allowed + * IP dual stack: can use IPv6 and IPv4 simultaneously + * fully asynchronous behavior: no more lengthly DNS or connections + * +sip.instance parameter (RFC5626) + * 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) + * Better handling of sips scheme in URIs. + * Messaging: support of is-composing (RFC3994) + * Call transfer fixes in error cases + * Add API for managing SIP SUBSCRIBES/NOTIFY/PUBLISH (linphonecore/event.h) + * bugfixes + + Requires: mediastreamer2 = 2.10.0, ortp = 0.23.0, belle-sip = 1.3.0 + +linphone-3.6.1 -- June 17, 2013 + * fix memory leak with some video cameras on windows. + + Requires: mediastreamer2 = 2.9.1 and ortp = 0.22.0 + +linphone-3.6.0 -- May 27, 2013 + UI: + * new friend list and chat messaging UI + * enhanced call history + * call and conference audio recording + * persistent chat history + * DSCP settings for SIP and RTP + * display of call statistics (when clicking on the quality indicator bar) + core: + * ICE for efficient RTP exchange * fix bug in zRTP support (upgrade required) - * + * call recording + * uPnP + * call statistics + * adaptive bitrate control improvements + * faster call quality indicator feedback + * DSCP settings for SIP and RTP + * detailed call statistics feedback API + + Requires: mediastreamer2 = 2.9.0 and ortp = 0.22.0 + linphone-3.5.2 -- February 22, 2012 * updated oRTP to 0.20.0 diff --git a/README b/README index 05b0b1dcb..7e0b97524 100644 --- a/README +++ b/README @@ -2,36 +2,70 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. ******************Building linphone *********************************** -- you need at least: - - libosip2>=3.0.3 - - libeXosip2>=3.0.3 - - speex>=1.2.0 (including libspeexdsp part) - - libreadline (optional: for convenient command line in linphonec) - + gsm codec (gsm source package or libgsm-dev or gsm-devel) (optional) - + if you want to gtk/glade interface: - - gtk>=2.16.0 - + if you want video support: - - SDL>=1.2.10 - - libavcodec (ffmpeg) - - libswscale (part of ffmpeg too) for better scaling performance - - theora (optional) - + if you want uPnP support: - - libupnp -with their corresponding -dev or -devel package if you don't use source packages. +- Install build time dependencies + - libtool + - intltool + +- you need at least: + - belle-sip>=1.3.0 + - speex>=1.2.0 (including libspeexdsp part) + - libxml2 + + + if you want the gtk/glade interface: + - libgtk >=2.16.0 + + if you want video support: + - libvpx (VP8 codec) + - libavcodec (ffmpeg) + - libswscale (part of ffmpeg too) for better scaling performance + - libxv (x11 video extension) + - libgl1-mesa (OpenGL API -- GLX development files) + - libglew (OpenGL Extension Wrangler library) + - libv4l (Video for linux) + - libx11 (x11) + - theora (optional) + + gsm codec (gsm source package or libgsm-dev or gsm-devel) (optional) + + libreadline (optional: for convenient command line in linphonec) + + libsqlite3 (optional : for a local history of chat messages) + + if you want uPnP support (optional): + - libupnp (version 1.6 branch (not patched with 18-url-upnpstrings.patch)) + + Here is the command line to get these dependencies installed for Ubuntu && Debian + + $ sudo apt-get install libtool intltool libgtk2.0-dev libspeexdsp-dev \ +libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev \ +libglew1.6-dev libv4l-dev libxml2-dev + + + for optional library + $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev \ +libsqlite3-dev libupnp4-dev libsrtp-dev + + + Install zrtp (optional), for unbreakable call encryption + $ git clone git://git.linphone.org:bzrtp + $ cd bzrtp && ./autogen.sh && ./configure && make + $ sudo make install + +- Compile linphone + + $ ./autogen.sh + $ ./configure + $ make && sudo make install + $ sudo ldconfig + + For windows compilation see README.mingw. For macOS X, see README.macos -******************************** notes for developers: ***************************** +******************************** Notes for developers ***************************** Here is a short description of the content of the source tree. -- oRTP/ is a poweful implementation of the RTP protocol. See the oRTP/README for more details. - It is used by the mediastreamer to send and receive streams to the network. +- oRTP/ is a poweful implementation of the RTP protocol. See the oRTP/README for more details. + It is used by mediastreamer2 to send and receive streams to the network. -- mediastreamer2/ is one of the important part of linphone. It is a framework library for audio +- mediastreamer2/ is one of the important part of linphone. It is a framework for audio and video processing. It contains several objects for grabing audio and video and outputing it (through rtp, to file). It contains also codec objects to compress audio and video streams. @@ -46,6 +80,6 @@ Here is a short description of the content of the source tree. * linphonec.c is the main file for the console version of linphone. * sipomatic.c / sipomatic.h contains the code for sipomatic, the test program that auto-answer to linphone calls. * shell.c (program name: linphonecsh) is a small utilities to send interactive commands to a running linphonec daemon. - + - share/ contains translation, documentation, rings and hello sound files. diff --git a/README.macos b/README.macos deleted file mode 100644 index 1648a3135..000000000 --- a/README.macos +++ /dev/null @@ -1,88 +0,0 @@ -********************************** -* Compiling linphone on macos X * -********************************** - -You need: - - Xcode (download from apple or using appstore application) - - Macports: http://www.macports.org/ - Download and install macports using its user friendly installer. - -- Install build time dependencies - $ port install automake autoconf libtool intltool - -- Install some linphone dependencies with macports - $ port install speex - $ port install libosip2 # WARNING: currently outdated in macport - $ port install libeXosip2 #WARNING: currently outdated in macport - $ port install ffmpeg-devel - $ port install libvpx - $ port install readline - -- Install srtp (optional) for call encryption - $ port install srtp - If that fails, get from source: - $ git clone git://git.linphone.org/srtp.git - $ cd srtp && autoconf && ./configure --prefix=/opt/local && make libsrtp.a - $ sudo make install - -- Install zrtpcpp (optional), for unbreakable call encryption - $ port install cmake - $ git clone git://git.linphone.org/zrtpcpp.git - $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make - $ sudo make install - -- Install gtk. It is recommended to use the quartz backend for better integration. - $ port install gtk2 +quartz +no_x11 - $ port install ige-mac-integration - $ port install hicolor-icon-theme - -- Compile and install the tunnel - -If you got the source code from git, run ./autogen.sh first - -Then or otherwise, do: - - $ ./configure --prefix=/opt/local && make && sudo make install - - -- Compile linphone - -If you got the source code from git, run ./autogen.sh first. - -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 - -Install to /opt/local - - $ sudo make install - -Done. - -If you want to generate a portable bundle, then install gtk-mac-bundler. -Use git: - $ git clone https://github.com/jralls/gtk-mac-bundler.git - $ cd gtk-mac-bundler && make install - $ export PATH=$PATH:~/.local/bin - #make this dummy charset.alias file for the bundler to be happy: - $ sudo touch touch /opt/local/lib/charset.alias - -Then run, inside linphone source tree: - 1. Run configure as told before but with "--enable-relativeprefix" appended. - - $ make - $ make bundle - -The resulting bundle is located in linphone build directory, together with a zipped version. - -For a better appearance, you can install the gtk-quartz-engine (a gtk theme) that make gtk application more similar to other mac applications (but not perfect). - - $ git clone https://github.com/jralls/gtk-quartz-engine.git - $ cd gtk-quartz-engine - $ autoreconf -i - $ ./configure --prefix=/opt/local && make - $ sudo make install - -Generate a new bundle to have it included. - - diff --git a/README.macos.md b/README.macos.md new file mode 100644 index 000000000..5e34f88ad --- /dev/null +++ b/README.macos.md @@ -0,0 +1,194 @@ +# Linphone on MacOS X + +## Build prerequisite + +* Xcode (download from apple or using appstore application) +* [Java SE](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or openJDK + This is required to generate a C sourcefile from SIP grammar using [antlr3](http://www.antlr3.org/) generator. +* [HomeBrew](http://brew.sh) or [Macports](http://www.macports.org/). + +### Dependencies + +#### Using MacPorts + +##### Multiple MacOS version support + +In order to enable generation of bundle for older MacOS version, it is recommended to: + + Edit `/opt/local/etc/macports/macports.conf` to add the following line: + + > macosx_deployment_target 10.7 + > buildfromsource always + + +##### Linphone library (liblinphone) + + sudo port install automake autoconf libtool pkgconfig intltool wget cunit \ + antlr3 speex readline sqlite3 openldap libupnp \ + ffmpeg-devel -gpl2 + +##### Linphone UI (GTK version) + +Install `GTK`. It is recommended to use the `quartz` backend for better integration. + + sudo port install gtk2 +quartz +no_x11 + sudo port install gtk-osx-application +no_python + sudo port install hicolor-icon-theme + +#### Using HomeBrew + +##### Linphone library (liblinphone) + + brew install intltool libtool wget pkg-config automake libantlr3.4c \ + homebrew/versions/antlr3 gettext speex ffmpeg readline libvpx opus + ln -s /usr/local/bin/glibtoolize /usr/local/bin/libtoolize + brew link --force gettext + #readline is required from linphonec.c otherwise compilation will fail + brew link readline --force + +##### Linphone UI (GTK version) + + brew install cairo --without-x11 + brew install gtk+ --without-x11 + brew install gtk-mac-integration hicolor-icon-theme + +### Building Linphone + +The next pieces need to be compiled manually. + +* To ensure compatibility with multiple MacOS versions it is recommended to do: + + export MACOSX_DEPLOYMENT_TARGET=10.7 + export LDFLAGS="-Wl,-headerpad_max_install_names" + +* (MacPorts only) Install libantlr3c (library used by belle-sip for parsing) + + git clone -b linphone git://git.linphone.org/antlr3.git + cd antlr3/runtime/C + ./autogen.sh + ./configure --disable-static --prefix=/opt/local && make + sudo make install + +* Install polarssl (encryption library used by belle-sip) + + git clone git://git.linphone.org/polarssl.git + cd polarssl + ./autogen.sh && ./configure --prefix=/opt/local && make + sudo make install + +* Install libvpx (Must be manualy build because the macport recipe does not support 'macosx_deployment_target') + + git clone https://chromium.googlesource.com/webm/libvpx -b v1.3.0 + cd libvpx + ./configure --prefix=/opt/local \ + --target=x86_64-darwin10-gcc \ + --enable-error-concealment \ + --enable-multithread \ + --enable-realtime-only \ + --enable-spatial-resampling \ + --enable-vp8 \ + --disable-vp9 \ + --enable-libs \ + --disable-install-docs \ + --disable-debug-libs \ + --disable-examples \ + --disable-unit-tests \ + --as=yasm + 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 + +* (Optional) Install srtp for call encryption + + git clone git://git.linphone.org/srtp.git + cd srtp && autoconf && ./configure --prefix=/opt/local && make libsrtp.a + sudo make install + +* (Optional) Install zrtp, for unbreakable call encryption + + git clone git://git.linphone.org/bzrtp.git + cd bzrtp && ./autogen.sh && ./configure --prefix=/opt/local && make + sudo make install + +* (Optional) Install gsm codec + + git clone git://git.linphone.org/gsm.git + cd gsm + make CCFLAGS="$CFLAGS -c -O2 -DNeedFunctionPrototypes=1" + sudo make install INSTALL_ROOT=/opt/local GSM_INSTALL_INC=/opt/local/include + +* (Optional, proprietary extension only) Compile and install the tunnel library + If you got the source code from git, run `./autogen.sh` first. + Then or otherwise, do: + + ./configure --prefix=/opt/local && make && sudo make install + +* Compile Linphone + If you got the source code from git, run `./autogen.sh` first. + Then or otherwise, : + + PKG_CONFIG_PATH=/opt/local/lib/pkgconfig ./configure --prefix=/opt/local --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make + +* Install on the system + + sudo make install + + You are done. + +### Generate portable bundle + +If you want to generate a portable bundle, then install `gtk-mac-bundler`: + + git clone https://github.com/jralls/gtk-mac-bundler.git + cd gtk-mac-bundler + git checkout 6e2ed855aaeae43c29436c342ae83568573b5636 + make install + export PATH=$PATH:~/.local/bin + # make this dummy charset.alias file for the bundler to be happy: + sudo touch /opt/local/lib/charset.alias + # set writing right for owner on the libssl and libcrypto libraries in order gtk-mac-bundler + # be able to rewrite their rpath + sudo chmod u+w /opt/local/lib/libssl.1.0.0.dylib /opt/local/lib/libcrypto.1.0.0.dylib + +The bundler file in `build/MacOS/linphone.bundle` expects some plugins to be installed in `/opt/local/lib/mediastreamer/plugins`. +If you don't need plugins, remove or comment out this line from the bundler file: + + + ${prefix:ms2plugins}/lib/mediastreamer/plugins/*.*.so + + +If using HomeBrew, this is not working yet. However you will at least need to: + + brew install shared-mime-info glib-networking hicolor-icon-theme + update-mime-database /usr/local/share/mime + + And modify also: + + /usr/local + +Then run, inside Linphone source tree configure as told before but with `--enable-relativeprefix` appended. + + make && make bundle + +The resulting bundle is located in Linphone build directory, together with a zipped version. + +* For a better appearance, you can install `gtk-quartz-engine` (a GTK theme) that makes GTK application more similar to other Mac applications (but not perfect). + sudo port install gnome-common + git clone https://github.com/jralls/gtk-quartz-engine.git + cd gtk-quartz-engine + ./autogen.sh + ./configure --prefix=/opt/local CFLAGS="$CFLAGS -Wno-error" && make + sudo make install + +Generate a new bundle to have it included. + + + + + diff --git a/README.mingw b/README.mingw index 42b130f33..6f5414753 100644 --- a/README.mingw +++ b/README.mingw @@ -1,19 +1,22 @@ Software to install ******************* -Download lastest mingw-get-inst.exe from http://www.mingw.org -Run mingw-get-inst.exe. Choose "download lastest catalogues". -In the feature list, select: -* C compiler -* C++ compiler -* Mingw developer toolkit -Let the installer fetch and install everything. +Download lastest mingw-get-setup.exe from http://www.mingw.org +Run mingw-get-setup.exe. +In the package list, select and install: +* mingw-developer-toolkit +* mingw32-base +* mingw32-gcc-g++ +* mingw32-pthreads-w32 +* msys-base +* msys-zip +* msys-unzip +* msys-wget -In mingw shell, run +For more information: +http://www.mingw.org/wiki/Getting_Started -mingw-get install msys-zip -mingw-get install msys-unzip -mingw-get install msys-wget +In mingw shell (also refered as msys), run mkdir -p /opt/perl/bin cp /bin/perl /opt/perl/bin/. @@ -26,7 +29,8 @@ 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 gtk+-2.24.10 win32 _bundle_ from http://www.gtk.org, direct link: +http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip Install all these three package in /: @@ -37,121 +41,184 @@ unzip #Install GTK+ Outcrop theme, the one used by linphone for distribution. cd /share/themes -wget http://art.gnome.org/download/themes/gtk2/1122/GTK2-Outcrop.tar.gz +wget ftp://ftp.gnome.org/mirror/gnome.org/teams/art.gnome.org/themes/gtk2/GTK2-Outcrop.tar.gz tar -xvzf GTK2-Outcrop.tar.gz #To get the translations working, remove from C:/MinGW/lib : libintl.a libintl.la libintl.dll.a -* Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable. +* Download and install Inno Setup Compiler (required only if you run +'make setup.exe'). Add it to your windows Path environment variable. -Get Linphone source code -************************ - -Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. -Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. - -It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example -c:\sources\ -Within msys-git bash, do -cd /c/sources -git clone git://git.linphone.org/linphone.git --recursive +* Install msys-git from (http://msysgit.github.io/). During installation you +are asked to make a choice about how line endings are treated by git. Choose +"Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY +IMPORTANT. OTHERS BREAK AUTOMAKE. -Building -******** +General rules for compilation +***************************** -WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del to start the windows system monitor, - you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu. -Kill it. Don't know what it is, but once killed, windows runs normally. +* It is recommended that you create a directory somewhere with a path without + any spaces or ~ characters, for example c:\sources\. This is the place where + source code must be compiled. +* git commands (to retrieve source code) must be performed within msys-git + terminal. +* all other commands (configure, autogen.sh, make) must be done within the + mingw shell (msys). In both msys and msys-git windows, change into the + directory you created for sources: + cd /c/sources -#Compile and install tunnel (optional, available under proprietary licensing) +* make sure pkg-config works by adding this env variable to your terminal: + export PKG_CONFIG_PATH=/usr/lib/pkgconfig -cd tunnel && ./autogen.sh && ./configure --prefix=/usr --enable-shared --disable-static && make && make install +Building belle-sip +****************** + * make sure that java version 1.6 is available in the PATH. java-1.7 will + not work with antlr generator. + * download the sources with msys-git shell using the following command: + $ git clone git://git.linphone.org/belle-sip.git + * compile and install + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install -#Build linphone itself: -#run autogen.sh after a git checkout or update +Building Linphone +***************** -./autogen.sh + * download the sources using the following command: + $ git clone git://git.linphone.org/linphone.git --recursive -./configure --prefix=/opt/linphone --enable-shared --disable-static -#note: in order to use the tunnel, append --enable-tunnel to the configure line above. + * compile + #always run autogen.sh after a git checkout or update + $ ./autogen.sh -#compile: + $ ./configure --prefix=/usr --enable-shared --disable-static + #note: in order to use the tunnel (commercial extension), append + #--enable-tunnel to the configure line above. -make + $ make + $ make install -#now install to /opt/linphone, required for compilation of plugins. + #Option: make a portable binary zip of linphone + $ make zip -make install + #additionally you can make binary installer if you have Inno Setup 5 + installed in its default path -#make a binary zip of linphone + $ make setup.exe + #now you're done, you have a fresh linphone windows installer in the + current directory. -make zip +Building plugins (optional) +*************************** -#additionally you can make binary installer if you have Inno Setup 5 installed in its default path - -make setup.exe - -#now you're done, you have a fresh linphone windows installer in the current directory. - - - -#build plugins -cd mediastreamer2/plugins/msx264 -./autogen.sh -PKG_CONFIG_PATH=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static -#make a binary zip of this plugin -make zip -#or make an installer -make setup.exe - -#the buddylookup plugin enables lookup of buddies in a remote database using xml-rpc over http/https. -cd coreapi/plugins/buddylookup -./autogen.sh -PKG_CONFIG_PATH=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static -make -#make a binary zip of this plugin -make zip + This the example for msx264 (H264 plugin), the same applies for other + linphone plugins. + $ git clone git://git.linphone.org/msx264.git + $ cd msx264 + $ ./autogen.sh + $ PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static + #make a binary zip of this plugin + $ make zip + #or make an installer + $ make setup.exe ****************************************************** * Notes about linphone-deps generation * ****************************************************** -Linphone-deps is a collection of linphone dependencies, that are for some of them difficult -to find as windows binaries. -These notes are useful if you want to upgrade part of the software that is included in the -linphone-deps packages. +Linphone-deps is a collection of linphone dependencies, that are for some of +them difficult to find as windows binaries. These notes are useful if you want +to upgrade part of the software that is included in the linphone-deps packages. List of software included in linphone-deps: -libosip2 (compiled) -libeXosip2 (compiled) -libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg) +antlr3c (compiled) +bzrtp (compiled) +polarssl (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) libsoup (compiled) +libsqlite3 (compiled) 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. +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 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 bzrtp + * download the sources with msys-git shell using the following command: + $ git clone git://git.linphone.org/bzrtp.git + * compile and install + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install + +- building sqlite3 + * download the sources on the following website: + http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz) + + * install: + ./configure + make && make install DESTDIR=/home//sqlite3-install + then copy the content of ~/sqlite3-install/usr/local/ into linphone-deps/. - building ffmpeg ./configure --enable-shared --disable-static --enable-memalign-hack --extra-cflags="-fno-common" --enable-gpl && make make install DESTDIR=/home//ffmpeg-install Copy to ~/ffmpeg-install/usr/local/* to linphone-deps/. - Copy also all *.dll.a files from the build tree to lib/ directort of linphone-deps. These are the implibs necessary to link a program against the dlls. + Copy also all *.dll.a files from the build tree to lib/ directort of + linphone-deps. These are the implibs necessary to link a program against the + dlls. -- building libxml2: the binaries found on the internet are generated with MSVC++, and for obscure reason they are not suitable for building libsoup +- building libxml2: the binaries found on the internet are generated with + MSVC++, and for obscure reason they are not suitable for building libsoup (that requires libxml2). ./configure --enable-shared --disable-static && make && make install DESTDIR=/home//libxml2-install copy ~/libxml2-install/usr/local/* into linphone-deps/. + - building x264: * download yasm normal version windows executable from yasm project page: @@ -169,12 +236,14 @@ When running "make install DESTDIR=", somepath must be absolute and sh - add to linphone-deps - building libsoup (only required for buddylookup plugin) - - download source from gnome ftp (warning: at the time of the writing only version 2.26.x can compile with the - glib version supplied in the gtk-bundle, 2.27 requires a new version of glib) + - download source from gnome ftp (warning: at the time of the writing + only version 2.26.x can compile with the glib version supplied in the + gtk-bundle, 2.27 requires a new version of glib) - uncompress libgnutls zip in / - make sure you have libxml2 installed in / - - apply a bugfix patch (fix gnutls support on windows, completely broken otherwise). The patch - is in linphone-deps/src, apply it this way: + - apply a bugfix patch (fix gnutls support on windows, completely + broken otherwise). The patch is in linphone-deps/src, apply it this + way: cd libsoup-2.26.* cd libsoup patch -p0 < libsoup-gnutls-bugfix.patch diff --git a/README.zrtp b/README.zrtp deleted file mode 100644 index c71c8d2d7..000000000 --- a/README.zrtp +++ /dev/null @@ -1,94 +0,0 @@ -ZRTP guide - -== Downloads == -- SRTP -http://sourceforge.net/projects/srtp/ -or "apt-get source libsrtp0" on Debian - -- ZRTP (libzrtpcpp-2.0) -http://www.gnutelephony.org/index.php/GNU_ZRTP - - -== Patch libzrtpcpp == -Index: src/ZIDFile.cpp -=================================================================== ---- src/ZIDFile.cpp (révision 754) -+++ src/ZIDFile.cpp (copie de travail) -@@ -78,10 +78,11 @@ - - // create save file name, rename and re-open - // if rename fails, just unlink old ZID file and create a brand new file -- // just a little inconnvenience for the user, need to verify new SAS -+ // just a little inconvenience for the user, need to verify new SAS - std::string fn = std::string(name) + std::string(".save"); - if (rename(name, fn.c_str()) < 0) { -- unlink(name); -+ // unlink(name); - createZIDFile(name); - return; - } -Index: src/libzrtpcpp/ZrtpCallback.h -=================================================================== ---- src/libzrtpcpp/ZrtpCallback.h (révision 754) -+++ src/libzrtpcpp/ZrtpCallback.h (copie de travail) -@@ -27,7 +27,7 @@ - - #include - #include --#include -+//#include - #include - - /** -Index: src/libzrtpcpp/ZIDRecord.h -=================================================================== ---- src/libzrtpcpp/ZIDRecord.h (révision 754) -+++ src/libzrtpcpp/ZIDRecord.h (copie de travail) -@@ -33,7 +33,7 @@ - - #include - #include --#include -+//#include - - #define IDENTIFIER_LEN 12 - #define RS_LENGTH 32 -Index: CMakeLists.txt -=================================================================== ---- CMakeLists.txt (révision 754) -+++ CMakeLists.txt (copie de travail) -@@ -124,11 +124,15 @@ - if(CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-Wno-long-long -Wno-char-subscripts) - add_definitions(-Wall -ansi -pedantic) -+ add_definitions(-DNEW_STDCPP) - endif() - - add_subdirectory(src) --add_subdirectory(demo) - -+if (enable_ccrtp) -+ add_subdirectory(demo) -+endif() -+ - if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/package/) - MESSAGE(STATUS "package dir not found") - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/) - - - -== Create simlinks or move folders == -submodules/external/srtp -> path_to_your_srtp_source -submodules/external/libzrtpcpp -> path_to_your_patched_zrtpcpp_source - - - -== Compilation for Android == -ndk-build BUILD_GPLV3_ZRTP=1 -j5 - - -== Compilation for Desktop version == -First ortp: ./autogen.sh && ./configure --enable-zrtp && make -j5 && sudo make install -Then mediastreamer2: ./autogen.sh && ./configure && make -j5 && sudo make install -Finally linphone: ./autogen.sh && ./configure --enable-external-ortp && make -j5 && sudo make install - diff --git a/TODO b/TODO index 1452a7c00..8e18e5491 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,7 @@ hot stuff: * ice support * run a user given command upon incoming calls -* SIP/TLS and SRTP +* SIP/TLS low priority: ------------- diff --git a/autogen.sh b/autogen.sh index 3bb716755..b245167ec 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,11 @@ #!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +THEDIR=`pwd` +cd $srcdir + #AM_VERSION="1.10" if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then # automake-1.10 (recommended) is not available on Fedora 8 @@ -10,25 +16,31 @@ else AUTOMAKE=automake-${AM_VERSION} fi -if test -f /opt/local/bin/glibtoolize ; then - # darwin - LIBTOOLIZE=/opt/local/bin/glibtoolize -else - LIBTOOLIZE=libtoolize -fi +LIBTOOLIZE="libtoolize" +for lt in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do + if test -x /usr/bin/$lt ; then + LIBTOOLIZE=$lt ; break + fi + if test -x /usr/local/bin/$lt ; then + LIBTOOLIZE=$lt ; break + fi + if test -x /opt/local/bin/$lt ; then + LIBTOOLIZE=$lt ; break + fi +done + if test -d /opt/local/share/aclocal ; then - ACLOCAL_ARGS="-I /opt/local/share/aclocal" + ACLOCAL_ARGS="-I /opt/local/share/aclocal" fi if test -d /share/aclocal ; then - ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal" + ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal" fi -if test -f /opt/local/bin/intltoolize ; then - #darwin - INTLTOOLIZE=/opt/local/bin/intltoolize -else - #on mingw, it is important to invoke intltoolize with an absolute path to avoid a bug +INTLTOOLIZE=$(which intltoolize) + +#workaround for mingw bug in intltoolize script. +if test "$INTLTOOLIZE" = "/bin/intltoolize" ; then INTLTOOLIZE=/usr/bin/intltoolize fi @@ -42,12 +54,24 @@ autoheader $AUTOMAKE --force-missing --add-missing --copy autoconf -if [ -x oRTP/autogen.sh ]; then - echo "Generating build scripts in oRTP..." - ( cd oRTP && ./autogen.sh ) +set +x + +#install git pre-commit hooks if possible +if [ -d .git/hooks ] && [ ! -f .git/hooks/pre-commit ]; then + cp .git-pre-commit .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit fi -if [ -x mediastreamer2/autogen.sh ]; then - echo "Generating build scripts in mediastreamer2..." - ( cd mediastreamer2 && ./autogen.sh ) +if [ "$srcdir" = "." ]; then + if [ -x oRTP/autogen.sh ]; then + echo "Generating build scripts in oRTP..." + ( cd oRTP && ./autogen.sh ) + fi + + if [ -x mediastreamer2/autogen.sh ]; then + echo "Generating build scripts in mediastreamer2..." + ( cd mediastreamer2 && ./autogen.sh ) + fi fi + +cd $THEDIR diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk deleted file mode 100644 index d0c87b4f8..000000000 --- a/build/android/Android-no-neon.mk +++ /dev/null @@ -1,46 +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 := liblinphonearmv5 -endif - -include $(BUILD_SHARED_LIBRARY) - -$(call import-module,android/cpufeatures) - - diff --git a/build/android/Android.mk b/build/android/Android.mk index 7fb75d0a4..9dfd049fa 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -23,26 +23,265 @@ 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 := \ + account_creator.c \ + address.c \ + authentication.c \ + bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_call_transfer.c \ + bellesip_sal/sal_op_events.c \ + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_sdp.c \ + buffer.c \ + callbacks.c \ + call_log.c \ + call_params.c \ + chat.c \ + conference.c \ + content.c \ + ec-calibrator.c \ + enum.c \ + event.c \ + friend.c \ + info.c \ + linphonecall.c \ + linphonecore.c \ + linphonecore_jni.cc \ + linphone_tunnel_config.c \ + localplayer.c \ + lpc2xml.c \ + lime.c \ + lpconfig.c \ + message_storage.c \ + misc.c \ + offeranswer.c \ + player.c \ + presence.c \ + proxy.c \ + quality_reporting.c \ + remote_provisioning.c \ + sal.c \ + siplogin.c \ + sipsetup.c \ + xml2lpc.c \ + xml.c \ + xmlrpc.c \ + vtables.c + +ifndef LIBLINPHONE_VERSION +LIBLINPHONE_VERSION = "Devel" +endif + +LOCAL_CFLAGS += \ + -D_BYTE_ORDER=_LITTLE_ENDIAN \ + -DORTP_INET6 \ + -DINET6 \ + -DENABLE_TRACE \ + -DHAVE_CONFIG_H \ + -DLIBLINPHONE_VERSION=\"$(LIBLINPHONE_VERSION)\" \ + -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ + -DUSE_BELLESIP \ + -DHAVE_ZLIB + +LOCAL_CFLAGS += -DIN_LINPHONE + +ifeq ($(_BUILD_VIDEO),1) +LOCAL_CFLAGS += -DVIDEO_ENABLED +ifeq ($(BUILD_X264),1) +LOCAL_CFLAGS += -DHAVE_X264 +endif +ifeq ($(BUILD_OPENH264),1) +LOCAL_CFLAGS += -DHAVE_OPENH264 +endif +endif + +ifeq ($(BUILD_CONTACT_HEADER),1) +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)/../mediastreamer2/src/audiofilters/ \ + $(LOCAL_PATH)/../../belle-sip/include \ + $(LOCAL_PATH)/../../../gen \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 \ + $(LOCAL_PATH)/../../externals/polarssl/include + +LOCAL_LDLIBS += -llog -ldl -lz + +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_CODEC2),1) +LOCAL_CFLAGS += -DHAVE_CODEC2 +LOCAL_STATIC_LIBRARIES += libcodec2 libmscodec2 +endif + +ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00) +LOCAL_CFLAGS += -DHAVE_WEBRTC +LOCAL_STATIC_LIBRARIES += libmswebrtc +endif +ifneq ($(BUILD_WEBRTC_AECM),0) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_aecm \ + libwebrtc_apm_utility \ + libwebrtc_spl \ + libwebrtc_system_wrappers +ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_aecm_neon \ + libwebrtc_spl_neon +endif +endif +ifneq ($(BUILD_WEBRTC_ISAC),0) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_isacfix \ + libwebrtc_spl +ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_isacfix_neon \ + libwebrtc_spl_neon +endif +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 +ifeq ($(BUILD_OPENH264),1) +LOCAL_STATIC_LIBRARIES += \ + libmsopenh264 \ + libopenh264 +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 ($(BUILD_ILBC), 1) +ifneq ($(TARGET_ARCH_ABI),armeabi) +LOCAL_CFLAGS += -DHAVE_ILBC=1 +LOCAL_STATIC_LIBRARIES += libmsilbc +endif +endif + +LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) +LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) +LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) +LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS) + + +ifeq ($(BUILD_ZRTP),1) + LOCAL_STATIC_LIBRARIES += libbzrtp +endif + +ifeq ($(BUILD_SRTP),1) + LOCAL_STATIC_LIBRARIES += libsrtp +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 + libffmpeg-linphone endif LOCAL_MODULE := liblinphone +LOCAL_MODULE_FILENAME := liblinphone-$(TARGET_ARCH_ABI) include $(BUILD_SHARED_LIBRARY) +LOCAL_CPPFLAGS=$(LOCAL_CFLAGS) +LOCAL_CFLAGS += -Wdeclaration-after-statement + $(call import-module,android/cpufeatures) - -ifeq ($(BUILD_REMOTE_PROVISIONING),1) - -include $(linphone-root-dir)/submodules/linphone/build/android/xml2lpc.mk -include $(linphone-root-dir)/submodules/linphone/build/android/lpc2xml.mk - -endif diff --git a/build/android/common.mk b/build/android/common.mk deleted file mode 100644 index 9fd68d779..000000000 --- a/build/android/common.mk +++ /dev/null @@ -1,197 +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 - -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_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..d1532d47a 100644 --- a/build/android/config.h +++ b/build/android/config.h @@ -10,9 +10,6 @@ /* Define if wizard enabled */ /* #undef BUILD_WIZARD */ -/* Tells whether localisation is possible */ -/* #undef ENABLE_NLS */ - /* Defined when using gsm at nonstandard rates */ /* #undef ENABLE_NONSTANDARD_GSM */ @@ -38,19 +35,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. */ @@ -60,7 +57,7 @@ /* #undef HAVE_GETIFADDRS */ /* Tells wheter localisation is possible */ -/* #undef HAVE_GETTEXT */ +/* #undef HAVE_INTL */ /* Define to 1 if you have the `get_current_dir_name' function. */ #define HAVE_GET_CURRENT_DIR_NAME 1 @@ -153,7 +150,7 @@ /* #undef LINPHONE_CONFIG_DIR */ /* path of liblinphone plugins, not mediastreamer2 plugins */ -/* #undef LINPHONE_PLUGINS_DIR */ +/* #undef LINPHONE_PLUGINS_DIR */ /* Linphone's version number */ /* #undef LINPHONE_VERSION */ @@ -205,11 +202,14 @@ /* #undef VERSION */ /* defined if video support is available */ -/* #undef VIDEO_ENABLED */ +/* #undef VIDEO_ENABLED */ /* Tell whether RSVP support should be compiled. */ /* #undef VINCENT_MAURY_RSVP */ +/* Defined when LIME support is compiled */ +#define HAVE_LIME 1 + /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD diff --git a/build/android/liblinphone_gitversion.h b/build/android/liblinphone_gitversion.h deleted file mode 100644 index 50e8a106e..000000000 --- a/build/android/liblinphone_gitversion.h +++ /dev/null @@ -1 +0,0 @@ -#define LIBLINPHONE_GIT_VERSION "unknown" diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk new file mode 100644 index 000000000..8395df144 --- /dev/null +++ b/build/android/liblinphone_tester.mk @@ -0,0 +1,53 @@ +LOCAL_PATH := $(call my-dir)/../../tester + +common_SRC_FILES := \ + common/bc_tester_utils.c \ + accountmanager.c \ + call_tester.c \ + dtmf_tester.c \ + eventapi_tester.c \ + flexisip_tester.c \ + liblinphone_tester.c \ + log_collection_tester.c \ + message_tester.c \ + multi_call_tester.c \ + offeranswer_tester.c \ + player_tester.c \ + presence_tester.c \ + proxy_config_tester.c \ + quality_reporting_tester.c \ + register_tester.c \ + remote_provisioning_tester.c \ + setup_tester.c \ + stun_tester.c \ + tester.c \ + tunnel_tester.c \ + upnp_tester.c \ + multicast_call_tester.c \ + +common_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../coreapi \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include \ + $(LOCAL_PATH)/common + + +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 -DBC_CONFIG_FILE=\"config.h\" +LOCAL_LDLIBS := -llog -lz + +ifeq ($(BUILD_MATROSKA), 1) +LOCAL_CFLAGS += -DHAVE_MATROSKA -DHAVE_ZLIB +endif + +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 f7858f94d..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 = \ - libxml2 \ - liblinphone \ - -LOCAL_MODULE := liblpc2xml - -include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk deleted file mode 100644 index 32bfb38c3..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 = \ - libxml2 \ - liblinphone \ - -LOCAL_MODULE := libxml2lpc - -include $(BUILD_SHARED_LIBRARY) diff --git a/build/macos/Info-linphone.plist.in b/build/macos/Info-linphone.plist.in index b9cde78a9..cd148bb84 100644 --- a/build/macos/Info-linphone.plist.in +++ b/build/macos/Info-linphone.plist.in @@ -25,7 +25,9 @@ NSHumanReadableCopyright Copyright 2011 Belledonne Communications LSMinimumSystemVersion - 10.4 + 10.7 + NSAppSleepDisabled + YES diff --git a/build/macos/Makefile.am b/build/macos/Makefile.am index e90eb2ffe..bff44fefc 100644 --- a/build/macos/Makefile.am +++ b/build/macos/Makefile.am @@ -1,3 +1,7 @@ -EXTRA_DIST=linphone.bundle environment.sh Info-linphone.plist.in - +EXTRA_DIST= \ + linphone.bundle \ + environment.sh \ + Info-linphone.plist.in \ + pkg-scripts/postinstall \ + pkg-distribution.xml.in diff --git a/build/macos/environment.sh b/build/macos/environment.sh index 8d34ca02c..fae264e0e 100644 --- a/build/macos/environment.sh +++ b/build/macos/environment.sh @@ -1,4 +1,26 @@ -export EXTRA_ARGS="--workdir $bundle_res" -export GIO_EXTRA_MODULES="$bundle_res/lib/gio/modules" +#export EXTRA_ARGS="--workdir $bundle_res" +export LINPHONE_WORKDIR="$bundle_res" +export GIO_EXTRA_MODULES="$bundle_lib/gio/modules" +export PANGO_LIBDIR="$bundle_lib" +export PANGO_SYSCONFDIR="$bundle_etc" +#this is very important not to force a shared library path so that native frameworks can find their dependencies by themselves, +#and not be forced to use the few libraries we have in the bundle that have the same name as native libs (ex: libiconv) +export DYLD_LIBRARY_PATH= +#the fucking script of the gtk-mac-bundler resets LANG due to obscure bugs. Set it back. +LANG=`defaults read .GlobalPreferences AppleLocale` + +case "$LANG" in + *.UTF-8) + ;; + *) + if test -d /usr/share/locale/${LANG}.UTF-8 ; then + LANG=${LANG}.UTF-8 + fi + ;; +esac + +export LANG + +echo "LANG is $LANG" \ No newline at end of file diff --git a/build/macos/libiconv-macos.patch b/build/macos/libiconv-macos.patch new file mode 100644 index 000000000..e0654843f --- /dev/null +++ b/build/macos/libiconv-macos.patch @@ -0,0 +1,26 @@ +--- libiconv-1.14.orig/lib/iconv.c 2013-03-14 16:30:50.000000000 +0100 ++++ libiconv-1.14/lib/iconv.c 2013-03-15 10:24:38.000000000 +0100 +@@ -607,4 +607,23 @@ + strong_alias (libiconv_close, iconv_close) + #endif + ++#undef iconv_open ++#undef iconv ++#undef iconv_close ++ ++LIBICONV_DLL_EXPORTED iconv_t iconv_open (const char* tocode, const char* fromcode){ ++ return libiconv_open(tocode,fromcode); ++} ++ ++LIBICONV_DLL_EXPORTED size_t iconv (iconv_t icd, ++ ICONV_CONST char* * inbuf, size_t *inbytesleft, ++ char* * outbuf, size_t *outbytesleft){ ++ return libiconv(icd,inbuf,inbytesleft,outbuf,outbytesleft); ++} ++ ++LIBICONV_DLL_EXPORTED int iconv_close (iconv_t icd){ ++ return libiconv_close(icd); ++} ++ ++ + #endif diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 6985bfb29..8109ff6cb 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 + + ${env:LINPHONE_ADDITIONAL_DEPENDENCIES_PREFIX} ${prefix}/lib/gio/modules/libgiognutls.so @@ -100,6 +104,15 @@ want to copy in to the bundle. The "dest" attribute is optional, as usual. Bundler will find all translations of that library/program under the indicated directory and copy them.--> + + ${prefix:linphone}/share/locale + + + ${prefix}/share/locale + + + ${prefix}/share/locale + ${prefix}/share/locale @@ -119,6 +132,11 @@ ${prefix:linphone}/share/pixmaps/linphone + + ${prefix:linphone}/share/images + + + @@ -153,6 +171,10 @@ ${prefix:linphone}/share/sounds/linphone/ringback.wav + + + ${prefix:linphone}/share/sounds/linphone/incoming_chat.wav + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/Assets/Logo.png b/build/windows10/liblinphone-tester/Assets/Logo.png new file mode 100644 index 000000000..ecfbad551 Binary files /dev/null and b/build/windows10/liblinphone-tester/Assets/Logo.png differ diff --git a/build/windows10/liblinphone-tester/Assets/SmallLogo.png b/build/windows10/liblinphone-tester/Assets/SmallLogo.png new file mode 100644 index 000000000..ecfbad551 Binary files /dev/null and b/build/windows10/liblinphone-tester/Assets/SmallLogo.png differ diff --git a/build/windows10/liblinphone-tester/Assets/SplashScreen.png b/build/windows10/liblinphone-tester/Assets/SplashScreen.png new file mode 100644 index 000000000..0d83a7980 Binary files /dev/null and b/build/windows10/liblinphone-tester/Assets/SplashScreen.png differ diff --git a/build/windows10/liblinphone-tester/Assets/WideLogo.scale-100.png b/build/windows10/liblinphone-tester/Assets/WideLogo.scale-100.png new file mode 100644 index 000000000..85fd4db8f Binary files /dev/null and b/build/windows10/liblinphone-tester/Assets/WideLogo.scale-100.png differ diff --git a/build/windows10/liblinphone-tester/DataModel/UnitTestDataSource.cs b/build/windows10/liblinphone-tester/DataModel/UnitTestDataSource.cs new file mode 100644 index 000000000..a5bc5bdc3 --- /dev/null +++ b/build/windows10/liblinphone-tester/DataModel/UnitTestDataSource.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using liblinphone_tester_runtime_component; +using System.Collections.ObjectModel; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using System.ComponentModel; +using Windows.UI; +using Windows.UI.Xaml.Documents; +using Windows.UI.Core; + +namespace liblinphone_tester.DataModel +{ + public class OutputTrace + { + public OutputTrace(String lev, String msg) + { + Level = lev; + Msg = msg; + } + + public String Level { get; private set; } + public String Msg { get; private set; } + } + + public class UnitTestSuite + { + public UnitTestSuite(string name) + { + Name = name; + Cases = new ObservableCollection(); + Selected = false; + } + + public string Name { get; private set; } + public bool Selected + { + get { return Cases.All(x => x.Selected); } + set + { + foreach (UnitTestCase c in Cases) + { + c.Selected = value; + } + } + } + public ObservableCollection Cases { get; private set; } + } + + public enum UnitTestCaseState + { + NotRun, + Success, + Failure + } + + public class UnitTestCase : INotifyPropertyChanged + { + public UnitTestCase(UnitTestSuite suite, string name) + { + _suite = new WeakReference(suite); + Name = name; + Selected = false; + State = UnitTestCaseState.NotRun; + Traces = new ObservableCollection(); + } + + public UnitTestSuite Suite + { + get { return _suite.Target as UnitTestSuite; } + } + public string Name { get; private set; } + public bool Selected + { + get { return _selected; } + set + { + _selected = value; + RaisePropertyChanged("Selected"); + } + } + public UnitTestCaseState State + { + get { return _state; } + set + { + _state = value; + RaisePropertyChanged("State"); + } + } + public ObservableCollection Traces + { + get { return _traces; } + set + { + _traces = value; + RaisePropertyChanged("Traces"); + } + } + public CoreDispatcher Dispatcher { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string name) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(name)); + } + } + + private WeakReference _suite; + private bool _selected; + private UnitTestCaseState _state; + private ObservableCollection _traces; + } + + public sealed class UnitTestDataSource + { + private static UnitTestDataSource _unitTestDataSource = new UnitTestDataSource(); + private ObservableCollection _suites = new ObservableCollection(); + + public ObservableCollection Suites + { + get { return this._suites; } + } + + public static IEnumerable GetSuites(LibLinphoneTester tester) + { + return _unitTestDataSource.FillSuites(tester); + } + + private IEnumerable FillSuites(LibLinphoneTester tester) + { + if (this.Suites.Count != 0) return this.Suites; + for (int i = 0; i < tester.nbTestSuites(); i++) + { + UnitTestSuite suite = new UnitTestSuite(tester.testSuiteName(i)); + for (int j = 0; j < tester.nbTests(suite.Name); j++) + { + suite.Cases.Add(new UnitTestCase(suite, tester.testName(suite.Name, j))); + } + this.Suites.Add(suite); + } + return this.Suites; + } + } + + public sealed class UnitTestCaseStateToSymbolConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parametr, string language) + { + if (!value.GetType().Equals(typeof(UnitTestCaseState))) + { + throw new ArgumentException("Only UnitTestCaseState is supported"); + } + if (targetType.Equals(typeof(Symbol))) + { + switch ((UnitTestCaseState)value) + { + case UnitTestCaseState.Success: + return Symbol.Like; + case UnitTestCaseState.Failure: + return Symbol.Dislike; + case UnitTestCaseState.NotRun: + default: + return Symbol.Help; + } + } + else + { + throw new ArgumentException(string.Format("Unsupported type {0}", targetType.FullName)); + } + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + } + + public sealed class UnitTestCaseStateToSymbolColorConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, string language) + { + if (!value.GetType().Equals(typeof(UnitTestCaseState))) + { + throw new ArgumentException("Only UnitTestCaseState is supported"); + } + if (targetType.Equals(typeof(Brush))) + { + switch ((UnitTestCaseState)value) + { + case UnitTestCaseState.Success: + return new SolidColorBrush(Colors.ForestGreen); + case UnitTestCaseState.Failure: + return new SolidColorBrush(Colors.IndianRed); + case UnitTestCaseState.NotRun: + default: + return new SolidColorBrush(Colors.LightGray); + } + } + else + { + throw new ArgumentException(string.Format("Unsupported format {0}", targetType.FullName)); + } + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + } + + public sealed class OutputTraceLevelToColorConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, string language) + { + if (!value.GetType().Equals(typeof(String))) + { + throw new ArgumentException("Only String is supported"); + } + if (targetType.Equals(typeof(Brush))) + { + if ((String)value == "Error") + { + return new SolidColorBrush(Colors.IndianRed); + } + else if ((String)value == "Warning") + { + return new SolidColorBrush(Colors.Orange); + } + return new SolidColorBrush(Colors.Black); + } + else + { + throw new ArgumentException(string.Format("Unsupported format {0}", targetType.FullName)); + } + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + } +} diff --git a/build/windows10/liblinphone-tester/MainPage.xaml b/build/windows10/liblinphone-tester/MainPage.xaml new file mode 100644 index 000000000..2cdea219c --- /dev/null +++ b/build/windows10/liblinphone-tester/MainPage.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/windows10/liblinphone-tester/MainPage.xaml.cs b/build/windows10/liblinphone-tester/MainPage.xaml.cs new file mode 100644 index 000000000..005f38891 --- /dev/null +++ b/build/windows10/liblinphone-tester/MainPage.xaml.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; +using liblinphone_tester.DataModel; +using liblinphone_tester_runtime_component; +using System.Threading.Tasks; +using Windows.UI.Core; +using Windows.UI.Xaml.Documents; +using Windows.Storage; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 + +namespace liblinphone_tester +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class MainPage : Page, OutputTraceListener + { + public MainPage() + { + this.InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + LibLinphoneTester.Instance.setWritableDirectory(ApplicationData.Current.LocalFolder); + _suites = UnitTestDataSource.GetSuites(LibLinphoneTester.Instance); + TryAutoLaunch(); + } + + public IEnumerable Suites + { + get { return _suites; } + } + + private IEnumerable _suites; + + private void SelectAll_Click(object sender, RoutedEventArgs e) + { + bool allSelected = Suites.All(x => x.Selected); + foreach (UnitTestSuite suite in Suites) + { + suite.Selected = !allSelected; + } + } + + private void RunSelected_Click(object sender, RoutedEventArgs e) + { + int nbCases = 0; + foreach (UnitTestSuite suite in Suites) + { + foreach (UnitTestCase c in suite.Cases) + { + if (c.Selected) nbCases++; + } + } + if (nbCases == 0) return; + + PrepareRun(nbCases); + + var tup = new Tuple, bool?>(Suites, Verbose.IsChecked); + var t = Task.Factory.StartNew(async (object parameters) => + { + var p = parameters as Tuple, bool?>; + IEnumerable suites = p.Item1; + bool verbose = p.Item2 != null ? (bool)p.Item2 : false; + foreach (UnitTestSuite suite in suites) + { + foreach (UnitTestCase c in suite.Cases) + { + if (c.Selected) + { + await RunUnitTestCase(c, verbose); + } + } + } + }, tup); + } + + private void RunSingle_Click(object sender, RoutedEventArgs e) + { + PrepareRun(1); + + var tup = new Tuple(DisplayedTestCase, Verbose.IsChecked); + var t = Task.Factory.StartNew(async (object parameters) => + { + var p = parameters as Tuple; + UnitTestCase c = p.Item1; + bool verbose = p.Item2 != null ? (bool)p.Item2 : false; + await RunUnitTestCase(c, verbose); + }, tup); + } + + private void PrepareRun(int nbCases) + { + CommandBar.IsEnabled = false; + ProgressIndicator.IsEnabled = true; + ProgressIndicator.Minimum = 0; + ProgressIndicator.Maximum = nbCases; + ProgressIndicator.Value = 0; + LibLinphoneTester.Instance.setOutputTraceListener(this); + } + + private async Task RunUnitTestCase(UnitTestCase c, bool verbose) + { + UnitTestCaseState newState = UnitTestCaseState.NotRun; + await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + RunningTestCase = c; + }); + await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + c.Traces.Clear(); + }); + c.Dispatcher = Dispatcher; + if (LibLinphoneTester.Instance.run(c.Suite.Name, c.Name, verbose)) + { + newState = UnitTestCaseState.Failure; + } + else + { + newState = UnitTestCaseState.Success; + } + await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + c.State = newState; + ProgressIndicator.Value += 1; + if (ProgressIndicator.Value == ProgressIndicator.Maximum) + { + UnprepareRun(); + } + }); + } + + private void UnprepareRun() + { + LibLinphoneTester.Instance.setOutputTraceListener(null); + RunningTestCase = null; + ProgressIndicator.IsEnabled = false; + CommandBar.IsEnabled = true; + } + + private void UnitTestCase_Click(object sender, ItemClickEventArgs e) + { + DisplayedTestCase = (e.ClickedItem as UnitTestCase); + TestResultPage.DataContext = DisplayedTestCase; + TestResultState.Visibility = Visibility.Visible; + TestResultRun.Visibility = Visibility.Visible; + } + + public async void outputTrace(String lev, String msg) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + if (RunningTestCase != null) + { + RunningTestCase.Traces.Add(new OutputTrace(lev, msg)); + } + }); + } + + private async void TryAutoLaunch() + { + try + { + await ApplicationData.Current.LocalFolder.GetFileAsync("autolaunch"); + CommandBar.IsEnabled = false; + ProgressIndicator.IsIndeterminate = true; + ProgressIndicator.IsEnabled = true; + LibLinphoneTester.Instance.runAllToXml(); + if (LibLinphoneTester.Instance.AsyncAction != null) + { + LibLinphoneTester.Instance.AsyncAction.Completed += (asyncInfo, asyncStatus) => { + App.Current.Exit(); + }; + } + } + catch (Exception) { } + } + + private UnitTestCase RunningTestCase; + private UnitTestCase DisplayedTestCase; + } +} diff --git a/build/windows10/liblinphone-tester/Package.appxmanifest b/build/windows10/liblinphone-tester/Package.appxmanifest new file mode 100644 index 000000000..f7f9cb6dd --- /dev/null +++ b/build/windows10/liblinphone-tester/Package.appxmanifest @@ -0,0 +1,49 @@ + + + + + + + + + + liblinphone-tester + Belledonne Communications + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/Properties/AssemblyInfo.cs b/build/windows10/liblinphone-tester/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d4b2a0c81 --- /dev/null +++ b/build/windows10/liblinphone-tester/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 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("liblinphone-tester")] +[assembly: AssemblyDescription("LibLinphone tester for Windows 10")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Belledonne Communications")] +[assembly: AssemblyProduct("liblinphone-tester-windows10")] +[assembly: AssemblyCopyright("Copyright © 2015 Belledonne Communications")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 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 Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/Properties/Default.rd.xml b/build/windows10/liblinphone-tester/Properties/Default.rd.xml new file mode 100644 index 000000000..80a960ce3 --- /dev/null +++ b/build/windows10/liblinphone-tester/Properties/Default.rd.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/liblinphone-tester-runtime-component/liblinphone-tester-runtime-component.vcxproj b/build/windows10/liblinphone-tester/liblinphone-tester-runtime-component/liblinphone-tester-runtime-component.vcxproj new file mode 100644 index 000000000..a66c5e7ed --- /dev/null +++ b/build/windows10/liblinphone-tester/liblinphone-tester-runtime-component/liblinphone-tester-runtime-component.vcxproj @@ -0,0 +1,132 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + {acf5ea95-d647-4d0c-8f97-2cd9aae8a2e0} + + + {74cad9d0-d8ae-4896-b71b-b2d9b48f30aa} + + + {8c1bc968-c5c8-4d4b-9ef3-d6a065fc7c97} + + + {6a18bbb9-08d1-41a8-be57-17fc992cc36f} + + + {b84d5c3b-6de5-49c8-b3dd-5eb67b01a527} + + + {266b769a-c04e-424c-9033-7209f0425bc0} + + + {878cf9d3-9761-479e-a715-a1de9f99cb78} + + + {a34f450d-392d-4660-9618-810bd695b3b0} + + + {9eb3fe8d-2d91-4d29-a3bb-98ddb51d45b7} + + + + {1ce10f06-8fad-437f-b3d7-3b7a8909a190} + WindowsRuntimeComponent + liblinphone-tester-runtime-component + liblinphone_tester_runtime_component + en-US + 14.0 + true + Windows Store + 10 + 10.0.10240.0 + 10.0.10069.0 + + + + DynamicLibrary + true + v140 + + + DynamicLibrary + false + true + v140 + + + + + + + + + + + + false + + + + NotUsing + IN_LINPHONE;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + $(ProjectDir)..\..\..\..\coreapi;$(ProjectDir)..\..\..\..\tester\common;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\oRTP\include;%(AdditionalIncludeDirectories) + + + Console + false + + + + + NotUsing + IN_LINPHONE;_WINRT_DLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + $(ProjectDir)..\..\..\..\coreapi;$(ProjectDir)..\..\..\..\tester\common;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\oRTP\include;%(AdditionalIncludeDirectories) + + + Console + false + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/liblinphone-tester-static/liblinphone-tester-static.vcxproj b/build/windows10/liblinphone-tester/liblinphone-tester-static/liblinphone-tester-static.vcxproj new file mode 100644 index 000000000..80e57dedb --- /dev/null +++ b/build/windows10/liblinphone-tester/liblinphone-tester-static/liblinphone-tester-static.vcxproj @@ -0,0 +1,129 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b6cdf482-7da3-43d4-9b12-70150106c191} + + + {025e28a8-9dfb-4015-ad56-19896aa6cc9b} + + + {88e3c241-eb6f-4c84-80dc-89b8961daf80} + + + {2e56b851-9d8d-40e5-84bb-e4ee63b71d25} + + + {c7139899-d8bc-48a3-a437-6844a8baabef} + + + + {9eb3fe8d-2d91-4d29-a3bb-98ddb51d45b7} + StaticLibrary + liblinphone-tester-static + liblinphone_tester_static + en-US + 14.0 + true + Windows Store + 10 + 10.0.10240.0 + 10.0.10069.0 + + + + StaticLibrary + true + v140 + + + StaticLibrary + false + true + v140 + + + + + + + + + + + + false + + + + NotUsing + false + true + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\tester;$(ProjectDir)..\..\..\..\tester\common;$(ProjectDir)..\..\liblinphone;$(ProjectDir)..\..\..\..\coreapi;$(ProjectDir)..\..\..\..\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\..\sqlite;$(ProjectDir)..\..\..\..\..\zlib;$(ProjectDir)..\..\..\..\..\cunit\build\windows10\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + BC_CONFIG_FILE="config.h";IN_LINPHONE;MSG_STORAGE_ENABLED;VIDEO_ENABLED;HAVE_CU_GET_SUITE;HAVE_ZLIB;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + false + false + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/liblinphone-tester.csproj b/build/windows10/liblinphone-tester/liblinphone-tester.csproj new file mode 100644 index 000000000..7cea98872 --- /dev/null +++ b/build/windows10/liblinphone-tester/liblinphone-tester.csproj @@ -0,0 +1,313 @@ + + + + + Debug + x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5} + AppContainerExe + Properties + liblinphone_tester + liblinphone-tester + en-US + UAP + 10.0.10240.0 + 10.0.10069.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + liblinphone-tester_TemporaryKey.pfx + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + PreserveNewest + + + + + + App.xaml + + + + MainPage.xaml + + + + + + Designer + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + {1ce10f06-8fad-437f-b3d7-3b7a8909a190} + liblinphone-tester-runtime-component + + + + + 14.0 + + + + XCopy /I /Y $(ProjectDir)..\..\..\tester\tester_hosts $(ProjectDir)Assets\ +XCopy /I /Y $(ProjectDir)..\..\..\tester\certificates\altname $(ProjectDir)Assets\certificates\altname +XCopy /I /Y $(ProjectDir)..\..\..\tester\certificates\cn $(ProjectDir)Assets\certificates\cn +XCopy /I /Y $(ProjectDir)..\..\..\tester\images $(ProjectDir)Assets\images +XCopy /I /Y $(ProjectDir)..\..\..\tester\rcfiles $(ProjectDir)Assets\rcfiles +XCopy /I /Y $(ProjectDir)..\..\..\tester\sounds $(ProjectDir)Assets\sounds + + + \ No newline at end of file diff --git a/build/windows10/liblinphone-tester/liblinphone-tester.sln b/build/windows10/liblinphone-tester/liblinphone-tester.sln new file mode 100644 index 000000000..5c6955078 --- /dev/null +++ b/build/windows10/liblinphone-tester/liblinphone-tester.sln @@ -0,0 +1,446 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "liblinphone-tester", "liblinphone-tester.csproj", "{EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblinphone-tester-static", "liblinphone-tester-static\liblinphone-tester-static.vcxproj", "{9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblinphone", "..\liblinphone\liblinphone.vcxproj", "{C7139899-D8BC-48A3-A437-6844A8BAABEF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\windows10\mediastreamer2\mediastreamer2.vcxproj", "{88E3C241-EB6F-4C84-80DC-89B8961DAF80}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ortp", "..\..\..\oRTP\build\windows10\ortp\ortp.vcxproj", "{2E56B851-9D8D-40E5-84BB-E4EE63B71D25}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\build\windows10\srtp\srtp.vcxproj", "{59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml2", "..\..\..\..\build\xml2\xml2.vcxproj", "{2B04DE79-4D33-4405-AC01-C89E0593A71D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\windows10\polarssl\polarssl.vcxproj", "{88768DD9-5110-4AC8-8B0E-41CD7713E1A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\windows10\speex\speex.vcxproj", "{971DD379-1C2D-44D2-9285-FDA556C48176}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\windows10\speexdsp\speexdsp.vcxproj", "{104BF91B-8314-4328-A996-90B8DF6052AF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "..\..\..\..\opus\build\windows10\opus\opus.vcxproj", "{81AF1025-E0EE-4AD6-988D-2EF162778693}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzrtp", "..\..\..\..\bzrtp\build\windows10\bzrtp\bzrtp.vcxproj", "{45C7723D-3107-4906-9633-F43ABE8A7147}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\windows10\gsm\gsm.vcxproj", "{EF1103C7-8AAC-464B-BA31-86B87246FA72}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\windows10\belle-sip\belle-sip.vcxproj", "{B6CDF482-7DA3-43D4-9B12-70150106C191}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "antlr3c", "..\..\..\..\antlr3\runtime\C\build\windows10\antlr3c\antlr3c.vcxproj", "{01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\..\..\zlib\build\windows10\zlib\zlib.vcxproj", "{A34F450D-392D-4660-9618-810BD695B3B0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "..\..\..\..\build\sqlite\sqlite.vcxproj", "{74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblinphone-tester-runtime-component", "liblinphone-tester-runtime-component\liblinphone-tester-runtime-component.vcxproj", "{1CE10F06-8FAD-437F-B3D7-3B7A8909A190}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\windows10\cunit\cunit.vcxproj", "{025E28A8-9DFB-4015-AD56-19896AA6CC9B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\windows10\libmsamr\libmsamr.vcxproj", "{8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows10\libmsilbc\libmsilbc.vcxproj", "{6A18BBB9-08D1-41A8-BE57-17FC992CC36F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\windows10\libmssilk\libmssilk.vcxproj", "{B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\windows10\libmswasapi\libmswasapi.vcxproj", "{266B769A-C04E-424C-9033-7209F0425BC0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswebrtc", "..\..\..\..\mswebrtc\build\windows10\libmswebrtc\libmswebrtc.vcxproj", "{878CF9D3-9761-479E-A715-A1DE9F99CB78}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ilbc", "..\..\..\..\libilbc-rfc3951\build\windows10\ilbc\ilbc.vcxproj", "{995B01AF-C568-453E-9E5F-8AE81FB79B4B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\windows10\opencore_amrnb\opencore_amrnb.vcxproj", "{71A5F1C8-F76D-4297-95AA-75E1C967DC79}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\windows10\opencore_amrwb\opencore_amrwb.vcxproj", "{3CC91899-3E98-49FD-BED5-FA290A9A5C8E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\windows10\vo-amrwbenc\vo-amrwbenc.vcxproj", "{D829672F-3775-4718-A991-1ABC42CBA67C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc", "..\..\..\..\mswebrtc\webrtc\build\windows10\webrtc\webrtc.vcxproj", "{C5895B75-BDCF-406C-B803-9CB954E90F0C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\windows10\libmsbcg729\libmsbcg729.vcxproj", "{ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|ARM.ActiveCfg = Debug|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|ARM.Build.0 = Debug|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|ARM.Deploy.0 = Debug|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x64.ActiveCfg = Debug|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x64.Build.0 = Debug|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x64.Deploy.0 = Debug|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x86.ActiveCfg = Debug|x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x86.Build.0 = Debug|x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Debug|x86.Deploy.0 = Debug|x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|ARM.ActiveCfg = Release|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|ARM.Build.0 = Release|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|ARM.Deploy.0 = Release|ARM + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x64.ActiveCfg = Release|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x64.Build.0 = Release|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x64.Deploy.0 = Release|x64 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x86.ActiveCfg = Release|x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x86.Build.0 = Release|x86 + {EC78E1D3-6FD8-4CAF-8D3F-6F4F97093BE5}.Release|x86.Deploy.0 = Release|x86 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|ARM.ActiveCfg = Debug|ARM + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|ARM.Build.0 = Debug|ARM + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|x64.ActiveCfg = Debug|x64 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|x64.Build.0 = Debug|x64 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|x86.ActiveCfg = Debug|Win32 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Debug|x86.Build.0 = Debug|Win32 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|ARM.ActiveCfg = Release|ARM + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|ARM.Build.0 = Release|ARM + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|x64.ActiveCfg = Release|x64 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|x64.Build.0 = Release|x64 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|x86.ActiveCfg = Release|Win32 + {9EB3FE8D-2D91-4D29-A3BB-98DDB51D45B7}.Release|x86.Build.0 = Release|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|ARM.ActiveCfg = Debug|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|ARM.Build.0 = Debug|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x64.ActiveCfg = Debug|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x64.Build.0 = Debug|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x86.ActiveCfg = Debug|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x86.Build.0 = Debug|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|ARM.ActiveCfg = Release|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|ARM.Build.0 = Release|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x64.ActiveCfg = Release|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x64.Build.0 = Release|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x86.ActiveCfg = Release|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x86.Build.0 = Release|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|ARM.ActiveCfg = Debug|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|ARM.Build.0 = Debug|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x64.ActiveCfg = Debug|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x64.Build.0 = Debug|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x86.ActiveCfg = Debug|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x86.Build.0 = Debug|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|ARM.ActiveCfg = Release|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|ARM.Build.0 = Release|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x64.ActiveCfg = Release|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x64.Build.0 = Release|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x86.ActiveCfg = Release|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x86.Build.0 = Release|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|ARM.ActiveCfg = Debug|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|ARM.Build.0 = Debug|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x64.ActiveCfg = Debug|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x64.Build.0 = Debug|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x86.ActiveCfg = Debug|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x86.Build.0 = Debug|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|ARM.ActiveCfg = Release|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|ARM.Build.0 = Release|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x64.ActiveCfg = Release|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x64.Build.0 = Release|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x86.ActiveCfg = Release|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x86.Build.0 = Release|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|ARM.ActiveCfg = Debug|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|ARM.Build.0 = Debug|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x64.ActiveCfg = Debug|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x64.Build.0 = Debug|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x86.ActiveCfg = Debug|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x86.Build.0 = Debug|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|ARM.ActiveCfg = Release|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|ARM.Build.0 = Release|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x64.ActiveCfg = Release|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x64.Build.0 = Release|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x86.ActiveCfg = Release|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x86.Build.0 = Release|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|ARM.ActiveCfg = Debug|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|ARM.Build.0 = Debug|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x64.ActiveCfg = Debug|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x64.Build.0 = Debug|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x86.ActiveCfg = Debug|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x86.Build.0 = Debug|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|ARM.ActiveCfg = Release|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|ARM.Build.0 = Release|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x64.ActiveCfg = Release|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x64.Build.0 = Release|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x86.ActiveCfg = Release|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x86.Build.0 = Release|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|ARM.ActiveCfg = Debug|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|ARM.Build.0 = Debug|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x64.ActiveCfg = Debug|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x64.Build.0 = Debug|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x86.ActiveCfg = Debug|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x86.Build.0 = Debug|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|ARM.ActiveCfg = Release|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|ARM.Build.0 = Release|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x64.ActiveCfg = Release|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x64.Build.0 = Release|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x86.ActiveCfg = Release|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x86.Build.0 = Release|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|ARM.ActiveCfg = Debug|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|ARM.Build.0 = Debug|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x64.ActiveCfg = Debug|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x64.Build.0 = Debug|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x86.ActiveCfg = Debug|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x86.Build.0 = Debug|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|ARM.ActiveCfg = Release|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|ARM.Build.0 = Release|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x64.ActiveCfg = Release|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x64.Build.0 = Release|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x86.ActiveCfg = Release|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x86.Build.0 = Release|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|ARM.ActiveCfg = Debug|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|ARM.Build.0 = Debug|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x64.ActiveCfg = Debug|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x64.Build.0 = Debug|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x86.ActiveCfg = Debug|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x86.Build.0 = Debug|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|ARM.ActiveCfg = Release|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|ARM.Build.0 = Release|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x64.ActiveCfg = Release|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x64.Build.0 = Release|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x86.ActiveCfg = Release|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x86.Build.0 = Release|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|ARM.ActiveCfg = Debug|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|ARM.Build.0 = Debug|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x64.ActiveCfg = Debug|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x64.Build.0 = Debug|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x86.ActiveCfg = Debug|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x86.Build.0 = Debug|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|ARM.ActiveCfg = Release|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|ARM.Build.0 = Release|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x64.ActiveCfg = Release|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x64.Build.0 = Release|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x86.ActiveCfg = Release|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x86.Build.0 = Release|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|ARM.ActiveCfg = Debug|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|ARM.Build.0 = Debug|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x64.ActiveCfg = Debug|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x64.Build.0 = Debug|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x86.ActiveCfg = Debug|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x86.Build.0 = Debug|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|ARM.ActiveCfg = Release|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|ARM.Build.0 = Release|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x64.ActiveCfg = Release|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x64.Build.0 = Release|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x86.ActiveCfg = Release|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x86.Build.0 = Release|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|ARM.ActiveCfg = Debug|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|ARM.Build.0 = Debug|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x64.ActiveCfg = Debug|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x64.Build.0 = Debug|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x86.ActiveCfg = Debug|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x86.Build.0 = Debug|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|ARM.ActiveCfg = Release|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|ARM.Build.0 = Release|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x64.ActiveCfg = Release|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x64.Build.0 = Release|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x86.ActiveCfg = Release|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x86.Build.0 = Release|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|ARM.ActiveCfg = Debug|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|ARM.Build.0 = Debug|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x64.ActiveCfg = Debug|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x64.Build.0 = Debug|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x86.ActiveCfg = Debug|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x86.Build.0 = Debug|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|ARM.ActiveCfg = Release|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|ARM.Build.0 = Release|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x64.ActiveCfg = Release|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x64.Build.0 = Release|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x86.ActiveCfg = Release|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x86.Build.0 = Release|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|ARM.ActiveCfg = Debug|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|ARM.Build.0 = Debug|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x64.ActiveCfg = Debug|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x64.Build.0 = Debug|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x86.ActiveCfg = Debug|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x86.Build.0 = Debug|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|ARM.ActiveCfg = Release|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|ARM.Build.0 = Release|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x64.ActiveCfg = Release|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x64.Build.0 = Release|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x86.ActiveCfg = Release|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x86.Build.0 = Release|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|ARM.ActiveCfg = Debug|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|ARM.Build.0 = Debug|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x64.ActiveCfg = Debug|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x64.Build.0 = Debug|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x86.ActiveCfg = Debug|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x86.Build.0 = Debug|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|ARM.ActiveCfg = Release|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|ARM.Build.0 = Release|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x64.ActiveCfg = Release|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x64.Build.0 = Release|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x86.ActiveCfg = Release|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x86.Build.0 = Release|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|ARM.ActiveCfg = Debug|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|ARM.Build.0 = Debug|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x64.ActiveCfg = Debug|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x64.Build.0 = Debug|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x86.ActiveCfg = Debug|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x86.Build.0 = Debug|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|ARM.ActiveCfg = Release|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|ARM.Build.0 = Release|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x64.ActiveCfg = Release|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x64.Build.0 = Release|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x86.ActiveCfg = Release|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x86.Build.0 = Release|Win32 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|ARM.ActiveCfg = Debug|ARM + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|ARM.Build.0 = Debug|ARM + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|x64.ActiveCfg = Debug|x64 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|x64.Build.0 = Debug|x64 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|x86.ActiveCfg = Debug|Win32 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Debug|x86.Build.0 = Debug|Win32 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|ARM.ActiveCfg = Release|ARM + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|ARM.Build.0 = Release|ARM + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|x64.ActiveCfg = Release|x64 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|x64.Build.0 = Release|x64 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|x86.ActiveCfg = Release|Win32 + {1CE10F06-8FAD-437F-B3D7-3B7A8909A190}.Release|x86.Build.0 = Release|Win32 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|ARM.ActiveCfg = Debug|ARM + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|ARM.Build.0 = Debug|ARM + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|x64.ActiveCfg = Debug|x64 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|x64.Build.0 = Debug|x64 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|x86.ActiveCfg = Debug|Win32 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Debug|x86.Build.0 = Debug|Win32 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|ARM.ActiveCfg = Release|ARM + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|ARM.Build.0 = Release|ARM + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|x64.ActiveCfg = Release|x64 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|x64.Build.0 = Release|x64 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|x86.ActiveCfg = Release|Win32 + {025E28A8-9DFB-4015-AD56-19896AA6CC9B}.Release|x86.Build.0 = Release|Win32 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|ARM.ActiveCfg = Debug|ARM + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|ARM.Build.0 = Debug|ARM + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|x64.ActiveCfg = Debug|x64 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|x64.Build.0 = Debug|x64 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|x86.ActiveCfg = Debug|Win32 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Debug|x86.Build.0 = Debug|Win32 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|ARM.ActiveCfg = Release|ARM + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|ARM.Build.0 = Release|ARM + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|x64.ActiveCfg = Release|x64 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|x64.Build.0 = Release|x64 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|x86.ActiveCfg = Release|Win32 + {8C1BC968-C5C8-4D4B-9EF3-D6A065FC7C97}.Release|x86.Build.0 = Release|Win32 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|ARM.ActiveCfg = Debug|ARM + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|ARM.Build.0 = Debug|ARM + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|x64.ActiveCfg = Debug|x64 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|x64.Build.0 = Debug|x64 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|x86.ActiveCfg = Debug|Win32 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Debug|x86.Build.0 = Debug|Win32 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|ARM.ActiveCfg = Release|ARM + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|ARM.Build.0 = Release|ARM + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|x64.ActiveCfg = Release|x64 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|x64.Build.0 = Release|x64 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|x86.ActiveCfg = Release|Win32 + {6A18BBB9-08D1-41A8-BE57-17FC992CC36F}.Release|x86.Build.0 = Release|Win32 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|ARM.ActiveCfg = Debug|ARM + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|ARM.Build.0 = Debug|ARM + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|x64.ActiveCfg = Debug|x64 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|x64.Build.0 = Debug|x64 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|x86.ActiveCfg = Debug|Win32 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Debug|x86.Build.0 = Debug|Win32 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|ARM.ActiveCfg = Release|ARM + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|ARM.Build.0 = Release|ARM + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|x64.ActiveCfg = Release|x64 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|x64.Build.0 = Release|x64 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|x86.ActiveCfg = Release|Win32 + {B84D5C3B-6DE5-49C8-B3DD-5EB67B01A527}.Release|x86.Build.0 = Release|Win32 + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|ARM.ActiveCfg = Debug|ARM + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|ARM.Build.0 = Debug|ARM + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|x64.ActiveCfg = Debug|x64 + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|x64.Build.0 = Debug|x64 + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|x86.ActiveCfg = Debug|Win32 + {266B769A-C04E-424C-9033-7209F0425BC0}.Debug|x86.Build.0 = Debug|Win32 + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|ARM.ActiveCfg = Release|ARM + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|ARM.Build.0 = Release|ARM + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|x64.ActiveCfg = Release|x64 + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|x64.Build.0 = Release|x64 + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|x86.ActiveCfg = Release|Win32 + {266B769A-C04E-424C-9033-7209F0425BC0}.Release|x86.Build.0 = Release|Win32 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|ARM.ActiveCfg = Debug|ARM + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|ARM.Build.0 = Debug|ARM + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|x64.ActiveCfg = Debug|x64 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|x64.Build.0 = Debug|x64 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|x86.ActiveCfg = Debug|Win32 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Debug|x86.Build.0 = Debug|Win32 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|ARM.ActiveCfg = Release|ARM + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|ARM.Build.0 = Release|ARM + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|x64.ActiveCfg = Release|x64 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|x64.Build.0 = Release|x64 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|x86.ActiveCfg = Release|Win32 + {878CF9D3-9761-479E-A715-A1DE9F99CB78}.Release|x86.Build.0 = Release|Win32 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|ARM.ActiveCfg = Debug|ARM + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|ARM.Build.0 = Debug|ARM + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|x64.ActiveCfg = Debug|x64 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|x64.Build.0 = Debug|x64 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|x86.ActiveCfg = Debug|Win32 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Debug|x86.Build.0 = Debug|Win32 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|ARM.ActiveCfg = Release|ARM + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|ARM.Build.0 = Release|ARM + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|x64.ActiveCfg = Release|x64 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|x64.Build.0 = Release|x64 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|x86.ActiveCfg = Release|Win32 + {995B01AF-C568-453E-9E5F-8AE81FB79B4B}.Release|x86.Build.0 = Release|Win32 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|ARM.ActiveCfg = Debug|ARM + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|ARM.Build.0 = Debug|ARM + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|x64.ActiveCfg = Debug|x64 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|x64.Build.0 = Debug|x64 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|x86.ActiveCfg = Debug|Win32 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Debug|x86.Build.0 = Debug|Win32 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|ARM.ActiveCfg = Release|ARM + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|ARM.Build.0 = Release|ARM + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|x64.ActiveCfg = Release|x64 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|x64.Build.0 = Release|x64 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|x86.ActiveCfg = Release|Win32 + {71A5F1C8-F76D-4297-95AA-75E1C967DC79}.Release|x86.Build.0 = Release|Win32 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|ARM.ActiveCfg = Debug|ARM + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|ARM.Build.0 = Debug|ARM + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|x64.ActiveCfg = Debug|x64 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|x64.Build.0 = Debug|x64 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|x86.ActiveCfg = Debug|Win32 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Debug|x86.Build.0 = Debug|Win32 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|ARM.ActiveCfg = Release|ARM + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|ARM.Build.0 = Release|ARM + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|x64.ActiveCfg = Release|x64 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|x64.Build.0 = Release|x64 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|x86.ActiveCfg = Release|Win32 + {3CC91899-3E98-49FD-BED5-FA290A9A5C8E}.Release|x86.Build.0 = Release|Win32 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|ARM.ActiveCfg = Debug|ARM + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|ARM.Build.0 = Debug|ARM + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|x64.ActiveCfg = Debug|x64 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|x64.Build.0 = Debug|x64 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|x86.ActiveCfg = Debug|Win32 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Debug|x86.Build.0 = Debug|Win32 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|ARM.ActiveCfg = Release|ARM + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|ARM.Build.0 = Release|ARM + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|x64.ActiveCfg = Release|x64 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|x64.Build.0 = Release|x64 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|x86.ActiveCfg = Release|Win32 + {D829672F-3775-4718-A991-1ABC42CBA67C}.Release|x86.Build.0 = Release|Win32 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|ARM.ActiveCfg = Debug|ARM + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|ARM.Build.0 = Debug|ARM + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|x64.ActiveCfg = Debug|x64 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|x64.Build.0 = Debug|x64 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|x86.ActiveCfg = Debug|Win32 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Debug|x86.Build.0 = Debug|Win32 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|ARM.ActiveCfg = Release|ARM + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|ARM.Build.0 = Release|ARM + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|x64.ActiveCfg = Release|x64 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|x64.Build.0 = Release|x64 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|x86.ActiveCfg = Release|Win32 + {C5895B75-BDCF-406C-B803-9CB954E90F0C}.Release|x86.Build.0 = Release|Win32 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|ARM.ActiveCfg = Debug|ARM + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|ARM.Build.0 = Debug|ARM + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|x64.ActiveCfg = Debug|x64 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|x64.Build.0 = Debug|x64 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|x86.ActiveCfg = Debug|Win32 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Debug|x86.Build.0 = Debug|Win32 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|ARM.ActiveCfg = Release|ARM + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|ARM.Build.0 = Release|ARM + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|x64.ActiveCfg = Release|x64 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|x64.Build.0 = Release|x64 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|x86.ActiveCfg = Release|Win32 + {ACF5EA95-D647-4D0C-8F97-2CD9AAE8A2E0}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/windows10/liblinphone-tester/liblinphone-tester_TemporaryKey.pfx b/build/windows10/liblinphone-tester/liblinphone-tester_TemporaryKey.pfx new file mode 100644 index 000000000..3aeb9f3b9 Binary files /dev/null and b/build/windows10/liblinphone-tester/liblinphone-tester_TemporaryKey.pfx differ diff --git a/build/windows10/liblinphone-tester/project.json b/build/windows10/liblinphone-tester/project.json new file mode 100644 index 000000000..e3b2dba25 --- /dev/null +++ b/build/windows10/liblinphone-tester/project.json @@ -0,0 +1,19 @@ +{ + "dependencies": { + "Microsoft.ApplicationInsights": "1.0.0", + "Microsoft.ApplicationInsights.PersistenceChannel": "1.0.0", + "Microsoft.ApplicationInsights.WindowsApps": "1.0.0", + "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0" + }, + "frameworks": { + "uap10.0": {} + }, + "runtimes": { + "win10-arm": {}, + "win10-arm-aot": {}, + "win10-x86": {}, + "win10-x86-aot": {}, + "win10-x64": {}, + "win10-x64-aot": {} + } +} \ No newline at end of file diff --git a/build/windows10/liblinphone/liblinphone.sln b/build/windows10/liblinphone/liblinphone.sln new file mode 100644 index 000000000..abfa15a85 --- /dev/null +++ b/build/windows10/liblinphone/liblinphone.sln @@ -0,0 +1,230 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblinphone", "liblinphone.vcxproj", "{C7139899-D8BC-48A3-A437-6844A8BAABEF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\windows10\mediastreamer2\mediastreamer2.vcxproj", "{88E3C241-EB6F-4C84-80DC-89B8961DAF80}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ortp", "..\..\..\oRTP\build\windows10\ortp\ortp.vcxproj", "{2E56B851-9D8D-40E5-84BB-E4EE63B71D25}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\build\windows10\srtp\srtp.vcxproj", "{59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml2", "..\..\..\..\build\xml2\xml2.vcxproj", "{2B04DE79-4D33-4405-AC01-C89E0593A71D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\windows10\polarssl\polarssl.vcxproj", "{88768DD9-5110-4AC8-8B0E-41CD7713E1A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\windows10\speex\speex.vcxproj", "{971DD379-1C2D-44D2-9285-FDA556C48176}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\windows10\speexdsp\speexdsp.vcxproj", "{104BF91B-8314-4328-A996-90B8DF6052AF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "..\..\..\..\opus\build\windows10\opus\opus.vcxproj", "{81AF1025-E0EE-4AD6-988D-2EF162778693}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzrtp", "..\..\..\..\bzrtp\build\windows10\bzrtp\bzrtp.vcxproj", "{45C7723D-3107-4906-9633-F43ABE8A7147}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\windows10\gsm\gsm.vcxproj", "{EF1103C7-8AAC-464B-BA31-86B87246FA72}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\windows10\belle-sip\belle-sip.vcxproj", "{B6CDF482-7DA3-43D4-9B12-70150106C191}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "antlr3c", "..\..\..\..\antlr3\runtime\C\build\windows10\antlr3c\antlr3c.vcxproj", "{01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\..\..\zlib\build\windows10\zlib\zlib.vcxproj", "{A34F450D-392D-4660-9618-810BD695B3B0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "..\..\..\..\build\sqlite\sqlite.vcxproj", "{74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|ARM.ActiveCfg = Debug|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|ARM.Build.0 = Debug|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x64.ActiveCfg = Debug|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x64.Build.0 = Debug|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x86.ActiveCfg = Debug|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Debug|x86.Build.0 = Debug|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|ARM.ActiveCfg = Release|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|ARM.Build.0 = Release|ARM + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x64.ActiveCfg = Release|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x64.Build.0 = Release|x64 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x86.ActiveCfg = Release|Win32 + {C7139899-D8BC-48A3-A437-6844A8BAABEF}.Release|x86.Build.0 = Release|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|ARM.ActiveCfg = Debug|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|ARM.Build.0 = Debug|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x64.ActiveCfg = Debug|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x64.Build.0 = Debug|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x86.ActiveCfg = Debug|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Debug|x86.Build.0 = Debug|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|ARM.ActiveCfg = Release|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|ARM.Build.0 = Release|ARM + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x64.ActiveCfg = Release|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x64.Build.0 = Release|x64 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x86.ActiveCfg = Release|Win32 + {88E3C241-EB6F-4C84-80DC-89B8961DAF80}.Release|x86.Build.0 = Release|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|ARM.ActiveCfg = Debug|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|ARM.Build.0 = Debug|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x64.ActiveCfg = Debug|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x64.Build.0 = Debug|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x86.ActiveCfg = Debug|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Debug|x86.Build.0 = Debug|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|ARM.ActiveCfg = Release|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|ARM.Build.0 = Release|ARM + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x64.ActiveCfg = Release|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x64.Build.0 = Release|x64 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x86.ActiveCfg = Release|Win32 + {2E56B851-9D8D-40E5-84BB-E4EE63B71D25}.Release|x86.Build.0 = Release|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|ARM.ActiveCfg = Debug|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|ARM.Build.0 = Debug|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x64.ActiveCfg = Debug|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x64.Build.0 = Debug|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x86.ActiveCfg = Debug|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Debug|x86.Build.0 = Debug|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|ARM.ActiveCfg = Release|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|ARM.Build.0 = Release|ARM + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x64.ActiveCfg = Release|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x64.Build.0 = Release|x64 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x86.ActiveCfg = Release|Win32 + {59104E4F-A087-442E-ABD4-BCD2A1F0B0FE}.Release|x86.Build.0 = Release|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|ARM.ActiveCfg = Debug|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|ARM.Build.0 = Debug|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x64.ActiveCfg = Debug|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x64.Build.0 = Debug|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x86.ActiveCfg = Debug|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Debug|x86.Build.0 = Debug|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|ARM.ActiveCfg = Release|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|ARM.Build.0 = Release|ARM + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x64.ActiveCfg = Release|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x64.Build.0 = Release|x64 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x86.ActiveCfg = Release|Win32 + {2B04DE79-4D33-4405-AC01-C89E0593A71D}.Release|x86.Build.0 = Release|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|ARM.ActiveCfg = Debug|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|ARM.Build.0 = Debug|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x64.ActiveCfg = Debug|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x64.Build.0 = Debug|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x86.ActiveCfg = Debug|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Debug|x86.Build.0 = Debug|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|ARM.ActiveCfg = Release|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|ARM.Build.0 = Release|ARM + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x64.ActiveCfg = Release|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x64.Build.0 = Release|x64 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x86.ActiveCfg = Release|Win32 + {88768DD9-5110-4AC8-8B0E-41CD7713E1A2}.Release|x86.Build.0 = Release|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|ARM.ActiveCfg = Debug|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|ARM.Build.0 = Debug|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x64.ActiveCfg = Debug|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x64.Build.0 = Debug|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x86.ActiveCfg = Debug|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Debug|x86.Build.0 = Debug|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|ARM.ActiveCfg = Release|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|ARM.Build.0 = Release|ARM + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x64.ActiveCfg = Release|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x64.Build.0 = Release|x64 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x86.ActiveCfg = Release|Win32 + {971DD379-1C2D-44D2-9285-FDA556C48176}.Release|x86.Build.0 = Release|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|ARM.ActiveCfg = Debug|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|ARM.Build.0 = Debug|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x64.ActiveCfg = Debug|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x64.Build.0 = Debug|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x86.ActiveCfg = Debug|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Debug|x86.Build.0 = Debug|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|ARM.ActiveCfg = Release|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|ARM.Build.0 = Release|ARM + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x64.ActiveCfg = Release|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x64.Build.0 = Release|x64 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x86.ActiveCfg = Release|Win32 + {104BF91B-8314-4328-A996-90B8DF6052AF}.Release|x86.Build.0 = Release|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|ARM.ActiveCfg = Debug|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|ARM.Build.0 = Debug|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x64.ActiveCfg = Debug|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x64.Build.0 = Debug|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x86.ActiveCfg = Debug|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Debug|x86.Build.0 = Debug|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|ARM.ActiveCfg = Release|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|ARM.Build.0 = Release|ARM + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x64.ActiveCfg = Release|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x64.Build.0 = Release|x64 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x86.ActiveCfg = Release|Win32 + {81AF1025-E0EE-4AD6-988D-2EF162778693}.Release|x86.Build.0 = Release|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|ARM.ActiveCfg = Debug|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|ARM.Build.0 = Debug|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x64.ActiveCfg = Debug|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x64.Build.0 = Debug|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x86.ActiveCfg = Debug|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Debug|x86.Build.0 = Debug|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|ARM.ActiveCfg = Release|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|ARM.Build.0 = Release|ARM + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x64.ActiveCfg = Release|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x64.Build.0 = Release|x64 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x86.ActiveCfg = Release|Win32 + {45C7723D-3107-4906-9633-F43ABE8A7147}.Release|x86.Build.0 = Release|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|ARM.ActiveCfg = Debug|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|ARM.Build.0 = Debug|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x64.ActiveCfg = Debug|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x64.Build.0 = Debug|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x86.ActiveCfg = Debug|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Debug|x86.Build.0 = Debug|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|ARM.ActiveCfg = Release|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|ARM.Build.0 = Release|ARM + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x64.ActiveCfg = Release|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x64.Build.0 = Release|x64 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x86.ActiveCfg = Release|Win32 + {EF1103C7-8AAC-464B-BA31-86B87246FA72}.Release|x86.Build.0 = Release|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|ARM.ActiveCfg = Debug|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|ARM.Build.0 = Debug|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x64.ActiveCfg = Debug|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x64.Build.0 = Debug|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x86.ActiveCfg = Debug|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Debug|x86.Build.0 = Debug|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|ARM.ActiveCfg = Release|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|ARM.Build.0 = Release|ARM + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x64.ActiveCfg = Release|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x64.Build.0 = Release|x64 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x86.ActiveCfg = Release|Win32 + {B6CDF482-7DA3-43D4-9B12-70150106C191}.Release|x86.Build.0 = Release|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|ARM.ActiveCfg = Debug|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|ARM.Build.0 = Debug|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x64.ActiveCfg = Debug|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x64.Build.0 = Debug|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x86.ActiveCfg = Debug|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Debug|x86.Build.0 = Debug|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|ARM.ActiveCfg = Release|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|ARM.Build.0 = Release|ARM + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x64.ActiveCfg = Release|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x64.Build.0 = Release|x64 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x86.ActiveCfg = Release|Win32 + {01CCCCC9-CA0C-4528-92BC-5B8BE1D02D6D}.Release|x86.Build.0 = Release|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|ARM.ActiveCfg = Debug|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|ARM.Build.0 = Debug|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x64.ActiveCfg = Debug|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x64.Build.0 = Debug|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x86.ActiveCfg = Debug|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Debug|x86.Build.0 = Debug|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|ARM.ActiveCfg = Release|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|ARM.Build.0 = Release|ARM + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x64.ActiveCfg = Release|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x64.Build.0 = Release|x64 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x86.ActiveCfg = Release|Win32 + {A34F450D-392D-4660-9618-810BD695B3B0}.Release|x86.Build.0 = Release|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|ARM.ActiveCfg = Debug|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|ARM.Build.0 = Debug|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x64.ActiveCfg = Debug|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x64.Build.0 = Debug|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x86.ActiveCfg = Debug|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Debug|x86.Build.0 = Debug|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|ARM.ActiveCfg = Release|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|ARM.Build.0 = Release|ARM + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x64.ActiveCfg = Release|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x64.Build.0 = Release|x64 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x86.ActiveCfg = Release|Win32 + {74CAD9D0-D8AE-4896-B71B-B2D9B48F30AA}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/windows10/liblinphone/liblinphone.vcxproj b/build/windows10/liblinphone/liblinphone.vcxproj new file mode 100644 index 000000000..2be93aeb0 --- /dev/null +++ b/build/windows10/liblinphone/liblinphone.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b6cdf482-7da3-43d4-9b12-70150106c191} + + + {74cad9d0-d8ae-4896-b71b-b2d9b48f30aa} + + + {2b04de79-4d33-4405-ac01-c89e0593a71d} + + + {a34f450d-392d-4660-9618-810bd695b3b0} + + + {88e3c241-eb6f-4c84-80dc-89b8961daf80} + + + {2e56b851-9d8d-40e5-84bb-e4ee63b71d25} + + + + {c7139899-d8bc-48a3-a437-6844a8baabef} + DynamicLibrary + liblinphone + liblinphone + en-US + 14.0 + true + Windows Store + 10 + 10.0.10240.0 + 10.0.10069.0 + + + + DynamicLibrary + true + v140 + + + DynamicLibrary + false + true + v140 + + + + + + + + + + + + false + false + + + + NotUsing + false + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\sqlite;$(ProjectDir)..\..\..\..\zlib;%(AdditionalIncludeDirectories) + HAVE_CONFIG_H;HAVE_ZLIB;MSG_STORAGE_ENABLED;VIDEO_ENABLED;IN_LINPHONE;LINPHONE_PLUGINS_DIR="\\linphone\\plugins";_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + false + false + + + version.bat + + + Batch script to get the git version + + + + + + \ No newline at end of file diff --git a/build/windows10/liblinphone/version.bat b/build/windows10/liblinphone/version.bat new file mode 100644 index 000000000..c015636e2 --- /dev/null +++ b/build/windows10/liblinphone/version.bat @@ -0,0 +1,22 @@ +@ECHO off + +SET gitlog= +FOR /f "delims=" %%a IN ('git log -1 "--pretty=format:%%H" ../../../configure.ac') DO SET gitlog=%%a + +IF [%gitlog%] == [] GOTO UnknownGitVersion + +FOR /f "delims=" %%a IN ('git describe --always') DO SET gitdescribe=%%a +GOTO End + +:UnknownGitVersion +SET gitdescribe=unknown + +:End +ECHO #define LIBLINPHONE_GIT_VERSION "%gitdescribe%" > liblinphone_gitversion.h + + +FOR /F "delims=" %%a IN ('findstr /B AC_INIT ..\..\..\configure.ac') DO ( + FOR /F "tokens=1,2,3 delims=[,]" %%1 IN ("%%a") DO ( + ECHO #define LIBLINPHONE_VERSION "%%3" > config.h + ) +) diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj new file mode 100644 index 000000000..3d1ecf83a --- /dev/null +++ b/build/wp8/LibLinphone.vcxproj @@ -0,0 +1,227 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + LibLinphone + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(ProjectDir)..\..\..\belle-sip\include;$(ProjectDir)..\..\oRTP\include;$(ProjectDir)..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tunnel\include;$(ProjectDir)..\..\coreapi;$(ProjectDir)..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\zlib;$(ProjectDir)..\..\..\sqlite\;$(ProjectDir);%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="\\linphone\\plugins";UNICODE;_XKEYCHECK_H;HAVE_ZLIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + belle-sip.lib;mediastreamer2.lib;ws2_32.lib;ortp.lib;gsm.lib;speex.lib;speexdsp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + + + version.bat + + + Batch script to get the git version + + + + + _DEBUG;MSG_STORAGE_ENABLED;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;MSG_STORAGE_ENABLED;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + false + + + + + + + + {1db09afe-fc9b-472e-a746-0e33f8ef8883} + + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} + + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + + + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + + {b16b81a9-bef2-44c9-b603-1065183ae844} + + + {0565952a-ea62-46a2-8261-f5b4b490da42} + + + {a45d63b9-60de-476c-8836-f8eedbe139d0} + + + {59500dd1-b192-4ddf-a402-8a8e3739e032} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + + + {7afac3bb-d97b-4578-b9fe-5e1d2b94ea2f} + + + + + diff --git a/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj new file mode 100644 index 000000000..6bc245f9f --- /dev/null +++ b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj @@ -0,0 +1,160 @@ + + + + + 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 + false + true + v110_wp80 + false + + + + + + + + false + + + + Level4 + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\oRTP\include;$(ProjectDir)..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\wp8\cunit\$(Platform)\$(Configuration);$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + true + ole32.lib;%(IgnoreSpecificDefaultLibraries) + WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration) + + + + + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + true + false + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + {1db09afe-fc9b-472e-a746-0e33f8ef8883} + + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + + {902daf1d-ebf1-4d03-b598-143500a50ab4} + + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} + + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + + + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + + {b16b81a9-bef2-44c9-b603-1065183ae844} + + + {0565952a-ea62-46a2-8261-f5b4b490da42} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + + + + + diff --git a/build/wp8/LibLinphoneTester-native/linphone-tester-native.cpp b/build/wp8/LibLinphoneTester-native/linphone-tester-native.cpp new file mode 100644 index 000000000..941b50916 --- /dev/null +++ b/build/wp8/LibLinphoneTester-native/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/wp8/LibLinphoneTester-native/linphone-tester-native.h b/build/wp8/LibLinphoneTester-native/linphone-tester-native.h new file mode 100644 index 000000000..1839cc481 --- /dev/null +++ b/build/wp8/LibLinphoneTester-native/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); + }; +} diff --git a/build/wp8/LibLinphoneTester-wp8/App.xaml b/build/wp8/LibLinphoneTester-wp8/App.xaml new file mode 100644 index 000000000..ad710fdad --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/App.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/App.xaml.cs b/build/wp8/LibLinphoneTester-wp8/App.xaml.cs new file mode 100644 index 000000000..5052b5a01 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png b/build/wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png new file mode 100644 index 000000000..f7d2e9780 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png b/build/wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png new file mode 100644 index 000000000..7d95d4e08 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png new file mode 100644 index 000000000..e0c59ac01 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png new file mode 100644 index 000000000..e93b89d60 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png new file mode 100644 index 000000000..550b1b5e8 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png new file mode 100644 index 000000000..686e6b53f Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png new file mode 100644 index 000000000..d4b5ede1b Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/empty_rc b/build/wp8/LibLinphoneTester-wp8/Assets/empty_rc new file mode 100644 index 000000000..2fa8c43a3 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Assets/laure_rc b/build/wp8/LibLinphoneTester-wp8/Assets/laure_rc new file mode 100644 index 000000000..54a682401 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc b/build/wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc new file mode 100644 index 000000000..23705a733 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Assets/oldphone.wav b/build/wp8/LibLinphoneTester-wp8/Assets/oldphone.wav new file mode 100644 index 000000000..7e99ecbf4 Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/oldphone.wav differ diff --git a/build/wp8/LibLinphoneTester-wp8/Assets/ringback.wav b/build/wp8/LibLinphoneTester-wp8/Assets/ringback.wav new file mode 100644 index 000000000..21f4b5bfb Binary files /dev/null and b/build/wp8/LibLinphoneTester-wp8/Assets/ringback.wav differ diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj new file mode 100644 index 000000000..4a73fb3b2 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -0,0 +1,175 @@ + + + + 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\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 + + + + + {0565952A-EA62-46A2-8261-F5B4B490DA42} + libmswp8vid + + + {5E94A00B-B14A-4E42-8284-8CB0EF099534} + LibLinphoneTester-native + + + + + + + + Xcopy /I /Y $(ProjectDir)..\..\..\tester\rcfiles\*_rc $(ProjectDir)Assets\ + + \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln new file mode 100644 index 000000000..cf0d4a086 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -0,0 +1,336 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Phone +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}" + ProjectSection(ProjectDependencies) = postProject + {5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}" + ProjectSection(ProjectDependencies) = postProject + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} + {59500DD1-B192-4DDF-A402-8A8E3739E032} = {59500DD1-B192-4DDF-A402-8A8E3739E032} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester-native", "..\LibLinphoneTester-native\LibLinphoneTester-native.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}" + ProjectSection(ProjectDependencies) = postProject + {D22BD217-D0F8-4274-9B3A-F3F35F46482C} = {D22BD217-D0F8-4274-9B3A-F3F35F46482C} + {902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4} + {072FAD20-7007-4DA2-B2E7-16CE2B219F67} = {072FAD20-7007-4DA2-B2E7-16CE2B219F67} + {0565952A-EA62-46A2-8261-F5B4B490DA42} = {0565952A-EA62-46A2-8261-F5B4B490DA42} + {08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142} + {9924AC72-F96C-4E56-94D9-2B025DA43C6B} = {9924AC72-F96C-4E56-94D9-2B025DA43C6B} + {B16B81A9-BEF2-44C9-B603-1065183AE844} = {B16B81A9-BEF2-44C9-B603-1065183AE844} + {36B528F9-FB79-4078-A16B-0A7442581BB7} = {36B528F9-FB79-4078-A16B-0A7442581BB7} + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883} = {1DB09AFE-FC9B-472E-A746-0E33F8EF8883} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\wp8\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\wp8\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\wp8\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\wp8\speex\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\wp8\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}" + ProjectSection(ProjectDependencies) = postProject + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\wp8\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" + ProjectSection(ProjectDependencies) = postProject + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}" + ProjectSection(ProjectDependencies) = postProject + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\wp8\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}" + ProjectSection(ProjectDependencies) = postProject + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} + {018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2} + {7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8} + {88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\wp8\msamr\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\wp8\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\build\wp8\srtp\srtp.vcxproj", "{B4B96BC4-2B72-4964-98E4-7FD048A43363}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswp8vid", "..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj", "{0565952A-EA62-46A2-8261-F5B4B490DA42}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswebrtc", "..\..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj", "{B16B81A9-BEF2-44C9-B603-1065183AE844}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc", "..\..\..\..\mswebrtc\webrtc\build\wp8\webrtc\webrtc.vcxproj", "{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj", "{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "..\..\..\..\opus\build\wp8\opus\opus.vcxproj", "{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 + {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|x86.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.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|x86.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.ActiveCfg = Debug|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.Build.0 = Debug|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.ActiveCfg = Debug|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.Build.0 = Debug|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.ActiveCfg = Release|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.Build.0 = Release|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.ActiveCfg = Release|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.Build.0 = Release|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.ActiveCfg = Debug|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.Build.0 = Debug|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.ActiveCfg = Debug|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.Build.0 = Debug|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.ActiveCfg = Release|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.Build.0 = Release|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.ActiveCfg = Release|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.Build.0 = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.ActiveCfg = Debug|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.Build.0 = Debug|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.ActiveCfg = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.Build.0 = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.ActiveCfg = Release|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.Build.0 = Release|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.ActiveCfg = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.Build.0 = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.ActiveCfg = Debug|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.Build.0 = Debug|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.ActiveCfg = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.Build.0 = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.ActiveCfg = Release|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.Build.0 = Release|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.ActiveCfg = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.Build.0 = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.ActiveCfg = Debug|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.Build.0 = Debug|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.ActiveCfg = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.Build.0 = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.ActiveCfg = Release|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.Build.0 = Release|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.ActiveCfg = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.Build.0 = Release|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.ActiveCfg = Debug|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.Build.0 = Debug|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.ActiveCfg = Debug|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.Build.0 = Debug|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.ActiveCfg = Release|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.Build.0 = Release|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.ActiveCfg = Release|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/wp8/LibLinphoneTester-wp8/LocalizedStrings.cs b/build/wp8/LibLinphoneTester-wp8/LocalizedStrings.cs new file mode 100644 index 000000000..e639982ad --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/MainPage.xaml b/build/wp8/LibLinphoneTester-wp8/MainPage.xaml new file mode 100644 index 000000000..c912857f9 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/MainPage.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/MainPage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/MainPage.xaml.cs new file mode 100644 index 000000000..aa5307968 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml b/build/wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml new file mode 100644 index 000000000..a95523275 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/build/wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs b/build/wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0b87f1f9b --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml b/build/wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml new file mode 100644 index 000000000..7ce78feb0 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs b/build/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs new file mode 100644 index 000000000..991c3a23d --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/Resources/AppResources.resx b/build/wp8/LibLinphoneTester-wp8/Resources/AppResources.resx new file mode 100644 index 000000000..78837dc46 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/TestCasePage.xaml b/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml new file mode 100644 index 000000000..b6f2ea932 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs new file mode 100644 index 000000000..aae5f878b --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/TestResultPage.xaml b/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml new file mode 100644 index 000000000..42f143fa0 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs new file mode 100644 index 000000000..129d2d833 --- /dev/null +++ b/build/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/wp8/LibLinphoneTester-wp8/log.html b/build/wp8/LibLinphoneTester-wp8/log.html new file mode 100644 index 000000000..4fea1c8bb --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/log.html @@ -0,0 +1,34 @@ + + + + + + +

+ + diff --git a/build/wp8/LibLinphone_no_tunnel.vcxproj b/build/wp8/LibLinphone_no_tunnel.vcxproj new file mode 100644 index 000000000..4c31ffbb1 --- /dev/null +++ b/build/wp8/LibLinphone_no_tunnel.vcxproj @@ -0,0 +1,221 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + LibLinphone + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(ProjectDir)..\..\..\belle-sip\include;$(ProjectDir)..\..\oRTP\include;$(ProjectDir)..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tunnel\include;$(ProjectDir)..\..\coreapi;$(ProjectDir)..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\zlib;$(ProjectDir)..\..\..\sqlite\;$(ProjectDir);%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="\\linphone\\plugins";UNICODE;_XKEYCHECK_H;HAVE_ZLIB;HAVE_CONFIG_H;%(PreprocessorDefinitions) + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + belle-sip_no_tunnel.lib;mediastreamer2.lib;ws2_32.lib;ortp.lib;gsm.lib;speex.lib;speexdsp.lib;libxml2.lib;sqlite.lib;zlib.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + + + version.bat + + + Batch script to get the git version + + + + + _DEBUG;MSG_STORAGE_ENABLED;%(PreprocessorDefinitions) + + + true + + + false + + + + + NDEBUG;MSG_STORAGE_ENABLED;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + false + + + + + {1db09afe-fc9b-472e-a746-0e33f8ef8883} + + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} + + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + + + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + + {b16b81a9-bef2-44c9-b603-1065183ae844} + + + {0565952a-ea62-46a2-8261-f5b4b490da42} + + + {a45d63b9-60de-476c-8836-f8eedbe139d0} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + + + {7afac3bb-d97b-4578-b9fe-5e1d2b94ea2f} + + + + + diff --git a/build/wp8/libxml2/install_headers.bat b/build/wp8/libxml2/install_headers.bat new file mode 100644 index 000000000..d33f20c04 --- /dev/null +++ b/build/wp8/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/wp8/libxml2/libxml2.sln b/build/wp8/libxml2/libxml2.sln new file mode 100644 index 000000000..b10b61b6b --- /dev/null +++ b/build/wp8/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.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/wp8/libxml2/libxml2.vcxproj b/build/wp8/libxml2/libxml2.vcxproj new file mode 100644 index 000000000..0e1f21c63 --- /dev/null +++ b/build/wp8/libxml2/libxml2.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + libxml2 + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + 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 + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + $(TargetDir)$(TargetName).lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + + + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/wp8/libxml2/libxml2_port.h b/build/wp8/libxml2/libxml2_port.h new file mode 100644 index 000000000..bde826374 --- /dev/null +++ b/build/wp8/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/wp8/libxml2/xmlversion.h b/build/wp8/libxml2/xmlversion.h new file mode 100644 index 000000000..40c192eba --- /dev/null +++ b/build/wp8/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/build/wp8/version.bat b/build/wp8/version.bat new file mode 100644 index 000000000..55ee42831 --- /dev/null +++ b/build/wp8/version.bat @@ -0,0 +1,22 @@ +@ECHO off + +SET gitlog= +FOR /f "delims=" %%a IN ('git log -1 "--pretty=format:%%H" ../../configure.ac') DO SET gitlog=%%a + +IF [%gitlog%] == [] GOTO UnknownGitVersion + +FOR /f "delims=" %%a IN ('git describe --always') DO SET gitdescribe=%%a +GOTO End + +:UnknownGitVersion +SET gitdescribe=unknown + +:End +ECHO #define LIBLINPHONE_GIT_VERSION "%gitdescribe%" > liblinphone_gitversion.h + + +FOR /F "delims=" %%a IN ('findstr /B AC_INIT ..\..\configure.ac') DO ( + FOR /F "tokens=1,2,3 delims=[,]" %%1 IN ("%%a") DO ( + ECHO #define LIBLINPHONE_VERSION "%%3" > config.h + ) +) diff --git a/build/wp8/zlib/zconf.h b/build/wp8/zlib/zconf.h new file mode 100644 index 000000000..a3a6b54fc --- /dev/null +++ b/build/wp8/zlib/zconf.h @@ -0,0 +1,513 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +/* #undef Z_PREFIX */ +#define Z_HAVE_UNISTD_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/build/wp8/zlib/zlib.sln b/build/wp8/zlib/zlib.sln new file mode 100644 index 000000000..97b0cc6a9 --- /dev/null +++ b/build/wp8/zlib/zlib.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}") = "zlib", "zlib.vcxproj", "{7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}" +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 + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Debug|ARM.ActiveCfg = Debug|ARM + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Debug|ARM.Build.0 = Debug|ARM + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Debug|Win32.ActiveCfg = Debug|Win32 + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Debug|Win32.Build.0 = Debug|Win32 + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Release|ARM.ActiveCfg = Release|ARM + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Release|ARM.Build.0 = Release|ARM + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Release|Win32.ActiveCfg = Release|Win32 + {7AFAC3BB-D97B-4578-B9FE-5E1D2B94EA2F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/wp8/zlib/zlib.vcxproj b/build/wp8/zlib/zlib.vcxproj new file mode 100644 index 000000000..34c9aa46f --- /dev/null +++ b/build/wp8/zlib/zlib.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {7afac3bb-d97b-4578-b9fe-5e1d2b94ea2f} + zlib + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(ProjectDir);$(ProjectDir)..\..\..\..\zlib;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;UNICODE;%(PreprocessorDefinitions) + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + $(TargetDir)$(TargetName).lib + Ws2_32.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\..\..\zlib\win32\zlib.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cmake/FindCUnit.cmake b/cmake/FindCUnit.cmake new file mode 100644 index 000000000..10c1a10b6 --- /dev/null +++ b/cmake/FindCUnit.cmake @@ -0,0 +1,58 @@ +############################################################################ +# FindCUnit.txt +# Copyright (C) 2015 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################ +# +# - Find the CUnit include file and library +# +# CUNIT_FOUND - system has CUnit +# CUNIT_INCLUDE_DIRS - the CUnit include directory +# CUNIT_LIBRARIES - The libraries needed to use CUnit + +include(CheckIncludeFile) +include(CheckLibraryExists) + +set(_CUNIT_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(CUNIT_INCLUDE_DIRS + NAMES CUnit/CUnit.h + HINTS _CUNIT_ROOT_PATHS + PATH_SUFFIXES include +) + +if(CUNIT_INCLUDE_DIRS) + set(HAVE_CUNIT_CUNIT_H 1) +endif() + +find_library(CUNIT_LIBRARIES + NAMES cunit + HINTS ${_CUNIT_ROOT_PATHS} + PATH_SUFFIXES bin lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CUnit + DEFAULT_MSG + CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES +) + +mark_as_advanced(CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES) diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake new file mode 100644 index 000000000..c65317a56 --- /dev/null +++ b/cmake/FindIconv.cmake @@ -0,0 +1,55 @@ +############################################################################ +# FindIconv.cmake +# Copyright (C) 2014 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. +# +############################################################################ +# +# - Find the iconv include file and library +# +# ICONV_FOUND - system has libiconv +# ICONV_INCLUDE_DIRS - the libiconv include directory +# ICONV_LIBRARIES - The libraries needed to use libiconv + +set(_ICONV_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(ICONV_INCLUDE_DIRS + NAMES iconv.h + HINTS _ICONV_ROOT_PATHS + PATH_SUFFIXES include +) + +if(ICONV_INCLUDE_DIRS) + set(HAVE_ICONV_H 1) +endif() + +find_library(ICONV_LIBRARIES + NAMES iconv + HINTS ${_ICONV_ROOT_PATHS} + PATH_SUFFIXES bin lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Iconv + DEFAULT_MSG + ICONV_INCLUDE_DIRS ICONV_LIBRARIES HAVE_ICONV_H +) + +mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES HAVE_ICONV_H) diff --git a/cmake/FindIntl.cmake b/cmake/FindIntl.cmake new file mode 100644 index 000000000..35ec969cd --- /dev/null +++ b/cmake/FindIntl.cmake @@ -0,0 +1,56 @@ +############################################################################ +# FindIntl.cmake +# Copyright (C) 2014 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. +# +############################################################################ +# +# - Find the libintl include file and library +# +# INTL_FOUND - system has libintl +# INTL_INCLUDE_DIRS - the libintl include directory +# INTL_LIBRARIES - The libraries needed to use libintl + +set(_INTL_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(INTL_INCLUDE_DIRS + NAMES libintl.h + HINTS _INTL_ROOT_PATHS + PATH_SUFFIXES include +) + +if(INTL_INCLUDE_DIRS) + set(HAVE_LIBINTL_H 1) +endif() + +set(INTL_ARGS INTL_INCLUDE_DIRS HAVE_LIBINTL_H) +if(NOT UNIX OR APPLE) + find_library(INTL_LIBRARIES + NAMES intl + HINTS ${_INTL_ROOT_PATHS} + PATH_SUFFIXES bin lib + ) + list(APPEND INTL_ARGS INTL_LIBRARIES) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Intl DEFAULT_MSG ${INTL_ARGS}) + +mark_as_advanced(${INTL_ARGS}) diff --git a/cmake/FindNotify.cmake b/cmake/FindNotify.cmake new file mode 100644 index 000000000..a9fb4d978 --- /dev/null +++ b/cmake/FindNotify.cmake @@ -0,0 +1,55 @@ +############################################################################ +# FindNotify.cmake +# Copyright (C) 2014 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. +# +############################################################################ +# +# - Find the notify include file and library +# +# NOTIFY_FOUND - system has libnotify +# NOTIFY_INCLUDE_DIRS - the libnotify include directory +# NOTIFY_LIBRARIES - The libraries needed to use libnotify + +set(_NOTIFY_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(NOTIFY_INCLUDE_DIRS + NAMES libnotify/notify.h + HINTS _NOTIFY_ROOT_PATHS + PATH_SUFFIXES include +) + +if(NOTIFY_INCLUDE_DIRS) + set(HAVE_LIBNOTIFY_NOTIFY_H 1) +endif() + +find_library(NOTIFY_LIBRARIES + NAMES notify + HINTS ${_NOTIFY_ROOT_PATHS} + PATH_SUFFIXES bin lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Notify + DEFAULT_MSG + NOTIFY_INCLUDE_DIRS NOTIFY_LIBRARIES HAVE_LIBNOTIFY_NOTIFY_H +) + +mark_as_advanced(NOTIFY_INCLUDE_DIRS NOTIFY_LIBRARIES HAVE_LIBNOTIFY_NOTIFY_H) diff --git a/cmake/FindSqlite3.cmake b/cmake/FindSqlite3.cmake new file mode 100644 index 000000000..7cab06bd1 --- /dev/null +++ b/cmake/FindSqlite3.cmake @@ -0,0 +1,55 @@ +############################################################################ +# FindSqlite3.cmake +# Copyright (C) 2014 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. +# +############################################################################ +# +# - Find the sqlite3 include file and library +# +# SQLITE3_FOUND - system has sqlite3 +# SQLITE3_INCLUDE_DIRS - the sqlite3 include directory +# SQLITE3_LIBRARIES - The libraries needed to use sqlite3 + +set(_SQLITE3_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(SQLITE3_INCLUDE_DIRS + NAMES sqlite3.h + HINTS _SQLITE3_ROOT_PATHS + PATH_SUFFIXES include +) + +if(SQLITE3_INCLUDE_DIRS) + set(HAVE_SQLITE3_H 1) +endif() + +find_library(SQLITE3_LIBRARIES + NAMES sqlite3 + HINTS ${_SQLITE3_ROOT_PATHS} + PATH_SUFFIXES bin lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Sqlite3 + DEFAULT_MSG + SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES HAVE_SQLITE3_H +) + +mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES HAVE_SQLITE3_H) diff --git a/cmake/FindXML2.cmake b/cmake/FindXML2.cmake new file mode 100644 index 000000000..9d0eebe14 --- /dev/null +++ b/cmake/FindXML2.cmake @@ -0,0 +1,55 @@ +############################################################################ +# FindXML2.txt +# Copyright (C) 2015 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################ +# +# - Find the libxml2 include file and library +# +# XML2_FOUND - system has libxml2 +# XML2_INCLUDE_DIRS - the libxml2 include directory +# XML2_LIBRARIES - The libraries needed to use libxml2 + +set(_XML2_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(XML2_INCLUDE_DIRS + NAMES libxml/xmlreader.h + HINTS _XML2_ROOT_PATHS + PATH_SUFFIXES include/libxml2 +) + +if(XML2_INCLUDE_DIRS) + set(HAVE_LIBXML_XMLREADER_H 1) +endif() + +find_library(XML2_LIBRARIES + NAMES xml2 + HINTS ${_XML2_ROOT_PATHS} + PATH_SUFFIXES bin lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XML2 + DEFAULT_MSG + XML2_INCLUDE_DIRS XML2_LIBRARIES +) + +mark_as_advanced(XML2_INCLUDE_DIRS XML2_LIBRARIES) diff --git a/cmake/FindZlib.cmake b/cmake/FindZlib.cmake new file mode 100644 index 000000000..3a0935f76 --- /dev/null +++ b/cmake/FindZlib.cmake @@ -0,0 +1,68 @@ +############################################################################ +# FindZlib.txt +# Copyright (C) 2015 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################ +# +# - Find the zlib include file and library +# +# ZLIB_FOUND - system has zlib +# ZLIB_INCLUDE_DIRS - the zlib include directory +# ZLIB_LIBRARIES - The libraries needed to use zlib + +set(_ZLIB_ROOT_PATHS + ${CMAKE_INSTALL_PREFIX} +) + +find_path(ZLIB_INCLUDE_DIRS + NAMES zlib.h + HINTS _ZLIB_ROOT_PATHS + PATH_SUFFIXES include +) + +if(ZLIB_INCLUDE_DIRS) + set(HAVE_ZLIB_H 1) +endif() + +if(ENABLE_STATIC) + if(IOS) + set(_ZLIB_STATIC_NAMES z) + else() + set(_ZLIB_STATIC_NAMES zstatic zlibstatic zlibstaticd) + endif() + find_library(ZLIB_LIBRARIES + NAMES ${_ZLIB_STATIC_NAMES} + HINTS ${_ZLIB_ROOT_PATHS} + PATH_SUFFIXES bin lib + ) +else() + find_library(ZLIB_LIBRARIES + NAMES z zlib zlibd + HINTS ${_ZLIB_ROOT_PATHS} + PATH_SUFFIXES bin lib + ) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Zlib + DEFAULT_MSG + ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES HAVE_ZLIB_H +) + +mark_as_advanced(ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES HAVE_ZLIB_H) diff --git a/cmake/LinphoneConfig.cmake.in b/cmake/LinphoneConfig.cmake.in new file mode 100644 index 000000000..d7aa6cc22 --- /dev/null +++ b/cmake/LinphoneConfig.cmake.in @@ -0,0 +1,51 @@ +############################################################################ +# LinphoneConfig.cmake +# Copyright (C) 2015 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################ +# +# Config file for the belle-sip package. +# It defines the following variables: +# +# LINPHONE_FOUND - system has linphone +# LINPHONE_INCLUDE_DIRS - the linphone include directory +# LINPHONE_LIBRARIES - The libraries needed to use linphone +# LINPHONE_CPPFLAGS - The compilation flags needed to use linphone +# LINPHONE_LDFLAGS - The linking flags needed to use linphone + +include("${CMAKE_CURRENT_LIST_DIR}/LinphoneTargets.cmake") +find_package(Mediastreamer2 REQUIRED) +find_package(BelleSIP REQUIRED) +if(@ENABLE_TUNNEL@) + find_package(Tunnel) +endif() + +get_filename_component(LINPHONE_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(LINPHONE_INCLUDE_DIRS "${LINPHONE_CMAKE_DIR}/../../../include") +set(LINPHONE_LIBRARIES BelledonneCommunications::linphone) +set(LINPHONE_LDFLAGS @LINK_FLAGS@) +list(APPEND LINPHONE_INCLUDE_DIRS ${MEDIASTREAMER2_INCLUDE_DIRS} ${BELLESIP_INCLUDE_DIRS}) +list(APPEND LINPHONE_LIBRARIES ${MEDIASTREAMER2_LIBRARIES} ${BELLESIP_LIBRARIES}) +set(LINPHONE_CPPFLAGS "${MEDIASTREAMER2_CPPFLAGS}") +set(LINPHONE_LDFLAGS "${MEDIASTREAMER2_LDFLAGS} ${BELLESIP_LDFLAGS}") +if(TUNNEL_FOUND) + list(APPEND LINPHONE_INCLUDE_DIRS ${TUNNEL_INCLUDE_DIRS}) + list(APPEND LINPHONE_LIBRARIES ${TUNNEL_LIBRARIES}) +endif() +set(LINPHONE_FOUND 1) diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 000000000..35d7e2ac9 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,46 @@ +/*************************************************************************** +* config.h.cmake +* Copyright (C) 2014 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. +* +****************************************************************************/ + +#define LINPHONE_MAJOR_VERSION ${LINPHONE_MAJOR_VERSION} +#define LINPHONE_MINOR_VERSION ${LINPHONE_MINOR_VERSION} +#define LINPHONE_MICRO_VERSION ${LINPHONE_MICRO_VERSION} +#define LINPHONE_VERSION "${LINPHONE_VERSION}" +#define LIBLINPHONE_VERSION "${LINPHONE_VERSION}" + +#define LINPHONE_ALL_LANGS "${LINPHONE_ALL_LANGS}" + +#define LINPHONE_PLUGINS_DIR "${LINPHONE_PLUGINS_DIR}" +#define LINPHONE_CONFIG_DIR "${LINPHONE_CONFIG_DIR}" + +#define GETTEXT_PACKAGE "${GETTEXT_PACKAGE}" + +#define PACKAGE_LOCALE_DIR "${PACKAGE_LOCALE_DIR}" +#define PACKAGE_DATA_DIR "${PACKAGE_DATA_DIR}" +#define PACKAGE_SOUND_DIR "${PACKAGE_SOUND_DIR}" + +#cmakedefine BUILD_WIZARD +#cmakedefine HAVE_NOTIFY4 +#cmakedefine HAVE_ZLIB 1 +#cmakedefine HAVE_CU_GET_SUITE 1 +#cmakedefine HAVE_CU_CURSES 1 +#cmakedefine HAVE_LIBUDEV_H 0 +#cmakedefine ENABLE_NLS 1 diff --git a/configure.ac b/configure.ac index 43efbff30..191c7fd7d 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.5.99.0],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.8.5],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) @@ -17,33 +17,40 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION} fi -LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface +LIBLINPHONE_SO_CURRENT=7 dnl increment this number when you add/change/remove an interface LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface 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) AC_MSG_NOTICE([$PACKAGE_NAME-$PACKAGE_VERSION A full featured audio/video sip phone.]) AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)]) -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([1.9 tar-pax subdir-objects]) AC_SUBST([LIBTOOL_DEPS]) 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 do not 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 AC_CHECK_PROGS(MD5SUM,[md5sum md5]) AM_CONDITIONAL(HAVE_MD5SUM,test -n $MD5SUM) +ios_found=no + case $target in *mingw32ce) CFLAGS="$CFLAGS -D_WIN32_WCE -DORTP_STATIC -D_WIN32_WINNT=0x0501" @@ -53,36 +60,48 @@ case $target in mingwce_found=yes ;; *mingw*) + dnl Workaround for mingw, whose compiler does not check in /usr/include ... + CPPFLAGS="$CPPFLAGS -I/usr/include" + LDFLAGS="$LDFLAGS -L/usr/lib" CFLAGS="$CFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501 " CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501" LIBS="$LIBS -lws2_32" 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 + armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin|aarch64-apple-darwin|*-apple-darwin.ios) + CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 " + LIBS="$LIBS -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation" ios_found=yes ;; x86_64-apple-darwin*|i686-apple-darwin*) MSPLUGINS_CFLAGS="" dnl use macport installation - ACLOCAL_MACOS_FLAGS="-I /opt/local/share/aclocal" + AS_IF([test -d "/opt/local/share/aclocal"], [ACLOCAL_MACOS_FLAGS="-I /opt/local/share/aclocal"]) build_macos=yes ;; esac +AM_CONDITIONAL(BUILD_IOS, test x$ios_found = xyes) + 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]) @@ -113,13 +132,13 @@ AC_CONFIG_COMMANDS([libtool-hacking], dnl Add the languages which your application supports here. PKG_PROG_PKG_CONFIG -ALL_LINGUAS="fr it de ja es pl cs nl sv pt_BR hu ru zh_CN nb_NO zh_TW he" +ALL_LINGUAS=$(cd po && echo *.po | sed 's/\.po//g') AC_SUBST(ALL_LINGUAS) AC_DEFINE_UNQUOTED(LINPHONE_ALL_LANGS, "$ALL_LINGUAS", [All supported languages]) if test "$mingw_found" != "yes" ; then dnl gettext macro does not work properly under mingw. And we want to use the one provided by GTK. - + dnl AM_GNU_GETTEXT pollutes CPPFLAGS: workaround this. CPPFLAGS_save=$CPPFLAGS AM_GNU_GETTEXT([external]) @@ -127,28 +146,79 @@ 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(HAVE_INTL,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) AC_CHECK_FUNCS([get_current_dir_name strndup stpcpy] ) AC_ARG_ENABLE(x11, - [AS_HELP_STRING([--disable-x11], [Disable X11 support (default=no)])], + [AS_HELP_STRING([--disable-x11], [Disable X11 support (default=yes for MacOSX, no otherwise)])], [case "${enableval}" in yes) enable_x11=true ;; no) enable_x11=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-x11) ;; esac], - [enable_x11=true] + [case "$target_os" in + *darwin*) enable_x11=false ;; #disable x11 on MacOS by default + *) enable_x11=true ;; + esac] ) +dnl conditional build of LDAP support +AC_ARG_ENABLE(ldap, + [AS_HELP_STRING([--enable-ldap], [Enables LDAP support (default=no)])], + [case "${enableval}" in + yes) enable_ldap=true ;; + no) enable_ldap=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ldap) ;; + esac], + [enable_ldap=false] +) + +if test "$enable_ldap" = "true"; then + PKG_CHECK_MODULES(LDAP, [openldap],[found_ldap=yes], [found_ldap=no]) + if test "$found_ldap" = "no"; then + AC_CHECK_LIB(ldap,ldap_initialize, [LDAP_LIBS="-lldap -llber"], + [AC_MSG_ERROR([You need libldap for LDAP support])] + ) + AC_CHECK_HEADERS(ldap.h, [foo=bar], [AC_MSG_ERROR( [ldap.h not found] ) ] ) + found_ldap=yes + fi + + PKG_CHECK_MODULES(SASL, [libsasl2],[found_sasl=yes],[found_sasl=no] ) + + if test "$found_sasl" = "no"; then + AC_CHECK_LIB(sasl2, sasl_client_init , [SASL_LIBS="-lsasl2"], + [AC_MSG_ERROR([You need SASL for LDAP support] ) ] + ) + AC_CHECK_HEADERS(sasl/sasl.h,foo=bar, [AC_MSG_ERROR([sasl/sasl.h not found])]) + found_sasl=yes + fi + + AC_SUBST(LDAP_CFLAGS) + AC_SUBST(LDAP_LIBS) + + AC_SUBST(SASL_CFLAGS) + AC_SUBST(SASL_LIBS) + + if test "$found_ldap$found_sasl" = "yesyes"; then + AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) + else + AC_MSG_ERROR([Cannot use LDAP due to previous errors]) + fi + +fi + +AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) + dnl conditionnal build of console interface. AC_ARG_ENABLE(console_ui, [AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])], @@ -183,7 +253,12 @@ AC_ARG_ENABLE(upnp, ) if test "$build_upnp" != "false" ; then - PKG_CHECK_MODULES([LIBUPNP], [libupnp], [build_upnp=true], + PKG_CHECK_MODULES([LIBUPNP], [libupnp], + [if pkg-config --atleast-version=1.6 "libupnp < 1.7"; then + build_upnp=true + else + AC_MSG_ERROR([libupnp >= 1.6 < 1.5 required.]) + fi], [if test "$build_upnp" == "true" ; then AC_MSG_ERROR([libupnp not found.]) else @@ -198,21 +273,53 @@ 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.]) +dnl check zlib +AC_ARG_ENABLE(zlib, + [AS_HELP_STRING([--disable-zlib], [Disable ZLib support])], + [case "${enableval}" in + yes) build_zlib=true ;; + no) build_zlib=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-zlib) ;; + esac], + [build_zlib=auto] +) +if test "$build_zlib" != "false" ; then + PKG_CHECK_MODULES(ZLIB, [zlib], [found_zlib=yes], [found_zlib=no]) + if test "x$found_zlib" = "xno" ; then + AC_CHECK_LIB(z, inflate, + [AC_CHECK_HEADER([zlib.h], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1230) + // compile error + #endif + ]],[])], + [found_zlib=yes])])]) + if test "x$found_zlib" = "xno" ; then + AC_MSG_NOTICE([zlib library and headers not found]) else - build_tools=false - fi] - ) + AC_DEFINE( HAVE_ZLIB, 1, [ZLIB support] ) + ZLIB_LIBS='-lz' + AC_SUBST(ZLIB_LIBS) + fi + else + AC_MSG_NOTICE([ZLIB found]) + AC_DEFINE( HAVE_ZLIB, 1, [ZLIB support] ) + fi +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) if test "$build_tools" != "false" ; then build_tools=true - AC_DEFINE(BUILD_TOOLS, 1, [Define if tools enabled] ) + AC_DEFINE(BUILD_TOOLS, 1, [Define if tools enabled] ) fi dnl conditionnal build of gtk interface. @@ -229,13 +336,24 @@ AC_ARG_ENABLE(gtk_ui, if test "$gtk_ui" = "true" ; then PKG_CHECK_MODULES(LIBGTK, gtk+-2.0 >= 2.18.0 gthread-2.0) if test "$enable_x11" = "false" ; then - PKG_CHECK_MODULES(LIBGTKMAC,[ige-mac-integration >= 0.9.7 ]) + PKG_CHECK_MODULES(LIBGTKMAC,[gtk-mac-integration >= 2.0.1], [found_gtkmac=true], [found_gtkmac=false]) + if test "$found_gtkmac" != "true" ; then + dnl for newest macports, the name changed. + PKG_CHECK_MODULES(LIBGTKMAC,[gtk-mac-integration-gtk2 >= 2.0.1], [found_gtkmac=true], [found_gtkmac=false]) + fi + if test "$found_gtkmac" != "true" ; then + AC_MSG_ERROR([gtk-mac-integration not found. Please install gtk-osx-application package.]) + fi AC_DEFINE([HAVE_GTK_OSX],[1],[Defined when gtk osx is used]) fi + + PKG_CHECK_MODULES(LIBGLIB, [glib-2.0 >= 2.26.0], [build_status_notifier=yes], [build_status_notifier=no]) else echo "GTK interface compilation is disabled." fi +AM_CONDITIONAL([BUILD_STATUS_NOTIFIER], [test "$build_status_notifier" = "yes"]) + AC_ARG_ENABLE(notify, [AS_HELP_STRING([--enable-notify=[yes/no]], [Enable libnotify support (default=yes)])], [case "${enableval}" in @@ -265,7 +383,6 @@ if test "$gtk_ui" = "true" ; then AC_DEFINE([HAVE_NOTIFY1],[1],[NOTIFY1 support]) esac else - NotifyNotification *n; echo "Libnotify support is disabled." fi fi @@ -351,6 +468,25 @@ AC_ARG_ENABLE(debug, esac], [debug_enabled=no] ) +AS_CASE([$debug_enabled], + [yes],[ + CFLAGS="$CFLAGS -g -O0 -DDEBUG" + CXXFLAGS="$CXXFLAGS -g -O0 -DDEBUG" + OBJCFLAGS="$OBJCFLAGS -g -O0 -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, @@ -382,13 +518,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 @@ -407,7 +536,14 @@ if test "$relativeprefix" = "yes" ; then fi dnl Set PACKAGE_LOCALE_DIR in config.h. -DATADIRNAME=share +case "$target_os" in + *qnx*) + DATADIRNAME=app/native/assets + ;; + *) + DATADIRNAME=share + ;; +esac AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR, "${package_prefix}/${DATADIRNAME}/locale",[Defines the place where locales can be found]) AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${package_prefix}/${DATADIRNAME}",[Defines the place where data are found]) @@ -419,39 +555,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 - -dnl check exosip support of DSCP in exosip -AC_MSG_CHECKING([for DSCP support in exosip]) -AC_TRY_COMPILE([#include ], - [int dscp=0;eXosip_set_option(EXOSIP_OPT_SET_DSCP,&dscp);], - has_exosip_dscp=yes, - has_exosip_dscp=no -) -AC_MSG_RESULT($has_exosip_dscp) -if test "$has_exosip_dscp" = "yes" ; then - AC_DEFINE( HAVE_EXOSIP_DSCP, 1, [Define if exosip dscp available] ) -fi - - if test "$console_ui" = "true" ; then dnl check gnu readline LP_CHECK_READLINE @@ -477,7 +580,7 @@ fi dnl conditionnal build of video support AC_ARG_ENABLE(video, - [AS_HELP_STRING([--enable-video], [Turn on video support compiling])], + [AS_HELP_STRING([--enable-video], [Turn on video support compiling (default=yes)])], [case "${enableval}" in yes) video=true ;; no) video=false ;; @@ -493,10 +596,10 @@ AC_ARG_WITH(ffmpeg, ) if test "$video" = "true"; then - + if test "$enable_x11" = "true"; then AC_CHECK_HEADERS(X11/Xlib.h) - if test "$build_macos" = "yes"; then + if test "$build_macos" = "yes"; then X11_LIBS="-L/usr/X11/lib -lX11" else AC_CHECK_LIB(X11,XUnmapWindow, X11_LIBS="-lX11") @@ -516,6 +619,7 @@ AC_ARG_ENABLE(alsa, [alsa=true] ) +dnl this options are just for passing to mediastreamer2 subproject AC_ARG_ENABLE(zrtp, [AS_HELP_STRING([--enable-zrtp], [Turn on zrtp support])], [case "${enableval}" in @@ -526,17 +630,81 @@ AC_ARG_ENABLE(zrtp, [zrtp=false] ) - -AC_ARG_ENABLE(portaudio, - [AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])], +dnl this options are just for passing to mediastreamer2 subproject +AC_ARG_ENABLE(dtls, + [AS_HELP_STRING([--enable-dtls], [Turn on srtp-dtls support - requires polarssl > 1.4])], [case "${enableval}" in - yes) portaudio=true ;; - no) portaudio=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; + yes) dtls=true ;; + no) dtls=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-dtls) ;; esac], - [portaudio=false] + [dtls=false] ) +AC_ARG_ENABLE(g729bCN, + [AS_HELP_STRING([--enable-g729bCN], [Turn on or off usage of G729AnnexB in RFC3389 implementation of Comfort Noise Payload (default=no)])], + [case "${enableval}" in + yes) g729bCN=true ;; + no) g729bCN=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-g729bCN) ;; + esac], + [g729bCN=false] +) + +dnl Polarssl lib is requested for Lime +AC_ARG_WITH( polarssl, + [ --with-polarssl Set prefix where polarssl can be found (ex:/usr, /usr/local)[[default=PREFIX or /usr if NONE]] ], + [ polarssl_prefix=${withval}],[ if test "$prefix" != "NONE"; then + polarssl_prefix=${prefix} + else + polarssl_prefix="/usr" + fi ]) + +found_polarssl=no + +if test "$polarssl_prefix" != "none" ; then + if test "$polarssl_prefix" != "/usr" ; then + POLARSSL_CFLAGS="-I${polarssl_prefix}/include" + POLARSSL_LIBS="-L${polarssl_prefix}/lib" + fi + POLARSSL_LIBS="$POLARSSL_LIBS -lpolarssl" + + CPPFLAGS_save=$CPPFLAGS + LIBS_save=$LIBS + + CPPFLAGS="$CPPFLAGS $POLARSSL_CFLAGS" + LIBS="$LIBS $POLARSSL_LIBS" + AC_CHECK_HEADERS(polarssl/gcm.h, + [found_polarssl=yes; AC_MSG_NOTICE([polarssl usable])], + [POLARSSL_CFLAGS="" + POLARSSL_LIBS=""]) + CPPFLAGS=$CPPFLAGS_save + LIBS=$LIBS_save +fi + +dnl check for Lime support, need polarssl version >= 1.3 (with gcm.h) +AC_ARG_ENABLE(lime, + [AS_HELP_STRING([--enable-lime], [Turn on or off compilation of Instant Messaging Encryption (default=auto)])], + [case "${enableval}" in + yes) lime=true ;; + no) lime=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-lime) ;; + esac], + [lime=false] +) + +if test "$lime" != "false" ; then + if test "x$found_polarssl" != "xyes" ; then + if test "$lime" = "true" ; then + AC_MSG_ERROR("LIME requires POLARSSL in version >= 1.3") + fi + lime=false + else + AC_DEFINE(HAVE_LIME, 1, [Defined when LIME support is compiled]) + lime=true + fi +fi + dnl build console if required AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) @@ -546,7 +714,6 @@ AM_CONDITIONAL(ARMBUILD, test x$use_arm_toolchain = xyes) dnl compilation of gtk user interface AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] ) AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes ) -AM_CONDITIONAL(BUILD_ZRTP, test x$zrtp = xtrue) dnl check getenv AH_TEMPLATE([HAVE_GETENV]) @@ -571,16 +738,6 @@ AC_ARG_ENABLE(assistant, [build_wizard=check] ) -dnl check libsoup (needed for wizard) -if test "$build_wizard" != "false" ; then - PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26],[], - [if test "$build_wizard" = "true" ; then - AC_MSG_ERROR([Could not found libsoup, assistant cannot be compiled.]) - else - build_wizard=false - fi] - ) -fi if test "$build_wizard" != "false" ; then PKG_CHECK_MODULES(LIBGTKWIZARD, [gtk+-2.0 >= 2.22.0],[], [if test "$build_wizard" = "true" ; then @@ -590,12 +747,10 @@ if test "$build_wizard" != "false" ; then fi] ) fi -AC_SUBST(LIBSOUP_CFLAGS) -AC_SUBST(LIBSOUP_LIBS) AM_CONDITIONAL(BUILD_WIZARD, test x$build_wizard != xfalse) if test "$build_wizard" != "false" ; then build_wizard=true - AC_DEFINE(BUILD_WIZARD, 1, [Define if wizard enabled] ) + AC_DEFINE(BUILD_WIZARD, 1, [Define if wizard enabled] ) fi AC_CHECK_HEADERS(libudev.h) @@ -607,89 +762,45 @@ AC_CHECK_LIB(udev,udev_new) AC_ARG_ENABLE(strict, - AC_HELP_STRING([--enable-strict], [Build with stricter options (gcc only) @<:@yes@:>@]), + AC_HELP_STRING([--enable-strict], [Build with stricter options @<:@yes@:>@]), [strictness="${enableval}"], [strictness=yes] ) -STRICT_OPTIONS="-Wall " +STRICT_OPTIONS="-Wall -Wuninitialized" +STRICT_OPTIONS_CC="-Wdeclaration-after-statement " +STRICT_OPTIONS_CXX="" +#for clang + +case $CC in + *clang*) + STRICT_OPTIONS="$STRICT_OPTIONS -Qunused-arguments " + #disabled due to wrong optimization false positive with small string + #(cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35903) + STRICT_OPTIONS="$STRICT_OPTIONS -Wno-array-bounds " + ;; +esac +# because Darwin's gcc is actually clang, we need to check it... +case "$target_os" in + *darwin*) + STRICT_OPTIONS="$STRICT_OPTIONS -Wno-error=unknown-warning-option -Qunused-arguments -Wno-tautological-compare -Wno-unused-function " + #disabled due to wrong optimization false positive with small string + #(cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35903) + STRICT_OPTIONS="$STRICT_OPTIONS -Wno-array-bounds " + ;; +esac if test "$strictness" = "yes" ; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror" CFLAGS="$CFLAGS -fno-strict-aliasing" fi AC_SUBST(STRICT_OPTIONS) +AC_SUBST(STRICT_OPTIONS_CC) +AC_SUBST(STRICT_OPTIONS_CXX) top_srcdir=`dirname $0` -AC_ARG_ENABLE([external-mediastreamer], - [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, - [enable_external_mediastreamer=no] -) - -AS_CASE($enable_external_mediastreamer, - [yes], - [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer]) - MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`], - [no], - [AC_CONFIG_SUBDIRS( mediastreamer2 ) - MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 - MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" - MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la" -dnl need to temporary change quotes to allow square brackets - changequote(<<, >>) - MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` - changequote([, ]) - MS2_DIR=mediastreamer2], - [AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])] -) - -AC_SUBST(MEDIASTREAMER_CFLAGS) -AC_SUBST(MEDIASTREAMER_LIBS) -AC_SUBST([MS2_VERSION]) -AC_SUBST([MS2_DIR]) - - - -AC_ARG_ENABLE(tunnel, - [AS_HELP_STRING([--enable-tunnel=[yes/no]], [Turn on compilation of tunnel support (default=no)])], - [case "${enableval}" in - yes) enable_tunnel=true ;; - no) enable_tunnel=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-tunnel) ;; - esac], - [enable_tunnel=false] -) -AM_CONDITIONAL(BUILD_TUNNEL, test x$enable_tunnel = xtrue) -if test x$enable_tunnel = xtrue; then - PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.3) - TUNNEL_CFLAGS+="-DTUNNEL_ENABLED" - AC_SUBST(TUNNEL_CFLAGS) - AC_SUBST(TUNNEL_LIBS) -fi - - -dnl check for db2html (docbook) to generate html user manual -AC_CHECK_PROG(have_sgmltools, sgmltools, yes, no) -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" - -if test x$mingw_found = xyes ; then - LINPHONE_LIBS="$LINPHONE_LIBS $OSIP_LIBS" -fi -AC_SUBST(LINPHONE_CFLAGS) -AC_SUBST(LINPHONE_LIBS) - -AC_DEFINE_UNQUOTED(LINPHONE_VERSION, "$PACKAGE_VERSION", [Linphone\'s version number]) - -AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plugins" ,[path of liblinphone plugins, not mediastreamer2 plugins]) -LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins" -AC_SUBST(LINPHONE_PLUGINS_DIR) - AC_ARG_ENABLE(external-ortp, [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], [case "${enableval}" in @@ -701,7 +812,7 @@ AC_ARG_ENABLE(external-ortp, ) if test "$external_ortp" = 'true'; then - PKG_CHECK_MODULES([ORTP], [ortp]) + PKG_CHECK_MODULES([ORTP], [ortp >= 0.24.0]) ORTP_VERSION=`$PKG_CONFIG --modversion ortp` else AC_CONFIG_SUBDIRS( oRTP ) @@ -723,38 +834,209 @@ AC_SUBST(ORTP_LIBS) AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) -AC_ARG_ENABLE(tests_enabled, +AC_ARG_ENABLE([external-mediastreamer], + [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, + [enable_external_mediastreamer=no] +) + +AS_CASE($enable_external_mediastreamer, + [yes], + [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer >= 2.11.0]) + MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`], + [no], + [AC_CONFIG_SUBDIRS( mediastreamer2 ) + MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 + MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" + MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la" +dnl need to temporary change quotes to allow square brackets + changequote(<<, >>) + MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` + changequote([, ]) + MS2_DIR=mediastreamer2], + [AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])] +) + +AC_SUBST(MEDIASTREAMER_CFLAGS) +AC_SUBST(MEDIASTREAMER_LIBS) +AC_SUBST([MS2_VERSION]) +AC_SUBST([MS2_DIR]) + + +AC_ARG_ENABLE(tunnel, + [AS_HELP_STRING([--enable-tunnel=[yes/no]], [Turn on compilation of tunnel support (default=no)])], + [case "${enableval}" in + yes) enable_tunnel=true ;; + no) enable_tunnel=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-tunnel) ;; + esac], + [enable_tunnel=false] +) +AM_CONDITIONAL(BUILD_TUNNEL, test x$enable_tunnel = xtrue) +if test x$enable_tunnel = xtrue; then + PKG_CHECK_MODULES(TUNNEL, tunnel >= 0.3.3) + AC_DEFINE(TUNNEL_ENABLED,1,[Tells tunnel extension is built-in]) +fi + +AC_ARG_ENABLE(msg-storage, + [AS_HELP_STRING([--enable-msg-storage=[yes/no]], [Turn on compilation of message storage (default=auto)])], + [case "${enableval}" in + yes) enable_msg_storage=true ;; + no) enable_msg_storage=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-msg-storage) ;; + esac], + [enable_msg_storage=auto] +) + +if test x$enable_msg_storage != xfalse; then + PKG_CHECK_MODULES(SQLITE3,[sqlite3 >= 3.6.0],[found_sqlite=yes],[found_sqlite=no]) + if test "$found_sqlite" = "no"; then + dnl Check the lib presence in case the PKG-CONFIG version is not found + AC_CHECK_LIB(sqlite3, sqlite3_open, [SQLITE3_LIBS+=" -lsqlite3 "; found_sqlite=yes], [foo=bar]) + fi + if test "$found_sqlite" = "yes"; then + SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED" + if test "$build_macos" = "yes" -o "$ios_found" = "yes"; then + SQLITE3_LIBS+=" -liconv" + fi + enable_msg_storage=true + else + if test x$enable_msg_storage = xtrue; then + AC_MSG_ERROR([sqlite3, required for message storage, not found]) + fi + enable_msg_storage=false + fi + + AC_SUBST(SQLITE3_CFLAGS) + AC_SUBST(SQLITE3_LIBS) +fi + +AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue) + +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.4.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) +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" + +AC_SUBST(LINPHONE_CFLAGS) +AC_SUBST(LINPHONE_LIBS) + +AC_DEFINE_UNQUOTED(LINPHONE_VERSION, "$PACKAGE_VERSION", [Linphone\'s version number]) + +AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plugins" ,[path of liblinphone plugins, not mediastreamer2 plugins]) +LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins" +AC_SUBST(LINPHONE_PLUGINS_DIR) + + + +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_get_suite,[ + AC_DEFINE(HAVE_CU_GET_SUITE,1,[defined when CU_get_suite is available]) + ],[foo=bar],[$CUNIT_LIBS]) + + 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 dnl ################################################## -AC_PATH_PROG(DOXYGEN,doxygen,false) -AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false) +AC_ARG_ENABLE(documentation, + [AS_HELP_STRING([--enable-documentation], [Documentation generation using doxygen (default=yes)])], + [case "${enableval}" in + yes) documentation_enabled=yes;; + no) documentation_enabled=no;; + *) AC_MSG_ERROR("Bad value for --enable-documentation");; + esac], + [documentation_enabled=yes] +) +if test "$documentation_enabled" = "yes" ; then + AC_CHECK_PROG(DOXYGEN,doxygen,doxygen,false) +else + DOXYGEN=false +fi +AM_CONDITIONAL(HAVE_DOXYGEN, test "$DOXYGEN" != "false") -AC_CONFIG_FILES([ +AC_CONFIG_FILES([ Makefile build/Makefile build/macos/Makefile build/macos/Info-linphone.plist + build/macos/pkg-distribution.xml m4/Makefile po/Makefile.in pixmaps/Makefile + include/Makefile coreapi/Makefile coreapi/help/Makefile coreapi/help/Doxyfile + tester/Makefile gtk/Makefile console/Makefile share/Makefile @@ -766,6 +1048,7 @@ AC_CONFIG_FILES([ share/xml/Makefile share/linphone.pc share/linphone.desktop + share/audio-assistant.desktop scripts/Makefile tools/Makefile linphone.spec @@ -780,12 +1063,17 @@ printf "* %-30s %s\n" "Video support" $video printf "* %-30s %s\n" "GTK interface" $gtk_ui printf "* %-30s %s\n" "Account assistant" $build_wizard printf "* %-30s %s\n" "Console interface" $console_ui -printf "* %-30s %s\n" "Tools" $build_tools -printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp +printf "* %-30s %s\n" "Tools" $build_tools +printf "* %-30s %s\n" "Message storage" $enable_msg_storage +printf "* %-30s %s\n" "IM encryption" $lime printf "* %-30s %s\n" "uPnP support" $build_upnp +printf "* %-30s %s\n" "LDAP support" $enable_ldap +printf "* %-30s %s\n" "ZLIB support" $found_zlib +printf "* %-30s %s\n" "Documentation" $documentation_enabled 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/CMakeLists.txt b/console/CMakeLists.txt new file mode 100644 index 000000000..328fdbcf2 --- /dev/null +++ b/console/CMakeLists.txt @@ -0,0 +1,53 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +set(LINPHONEC_SOURCE_FILES + linphonec.c + linphonec.h + commands.c +) +set(LINPHONECSH_SOURCE_FILES + shell.c +) + +add_executable(linphonec ${LINPHONEC_SOURCE_FILES}) +target_link_libraries(linphonec linphone) + +if(WIN32) + add_executable(linphoned WIN32 ${LINPHONEC_SOURCE_FILES}) + target_link_libraries(linphoned linphone) +endif() + +add_executable(linphonecsh ${LINPHONECSH_SOURCE_FILES}) +target_link_libraries(linphonecsh linphone) + +set(INSTALL_TARGETS linphonec linphonecsh) +if(WIN32) + list(APPEND INSTALL_TARGETS linphoned) +endif() + +install(TARGETS ${INSTALL_TARGETS} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) diff --git a/console/Makefile.am b/console/Makefile.am index 82ce998e5..482948329 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -3,18 +3,19 @@ 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) \ + $(STRICT_OPTIONS_CC) \ + $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(VIDEO_CFLAGS) \ $(READLINE_CFLAGS) \ - $(OSIP_CFLAGS) \ - $(ORTP_CFLAGS) \ - $(MEDIASTREAMER_CFLAGS) + $(SQLITE3_CFLAGS) \ + $(LIBXML2_CFLAGS) if BUILD_CONSOLE @@ -25,10 +26,13 @@ bin_PROGRAMS+=linphoned endif linphonec_SOURCES=linphonec.c linphonec.h commands.c -linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) +linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) $(BELLESIP_CFLAGS) linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(READLINE_LIBS) \ - $(X11_LIBS) + $(SQLITE3_LIBS) \ + $(X11_LIBS) \ + $(BELLESIP_LIBS) \ + $(LIBXML2_LIBS) if BUILD_WIN32 #special build of linphonec to detach from the windows console diff --git a/console/commands.c b/console/commands.c index 22b09a5a6..f50ed4886 100644 --- a/console/commands.c +++ b/console/commands.c @@ -28,7 +28,6 @@ #include #ifndef _WIN32_WCE #include -#include #endif /*_WIN32_WCE*/ #include #include @@ -38,6 +37,7 @@ #ifndef WIN32 #include +#include #endif #define AUDIO 0 @@ -45,7 +45,7 @@ /*************************************************************************** * - * Forward declarations + * Forward declarations * ***************************************************************************/ @@ -97,6 +97,7 @@ static int lpc_cmd_camera(LinphoneCore *lc, char *args); static int lpc_cmd_video_window(LinphoneCore *lc, char *args); static int lpc_cmd_preview_window(LinphoneCore *lc, char *args); static int lpc_cmd_snapshot(LinphoneCore *lc, char *args); +static int lpc_cmd_preview_snapshot(LinphoneCore *lc, char *args); static int lpc_cmd_vfureq(LinphoneCore *lc, char *arg); #endif static int lpc_cmd_states(LinphoneCore *lc, char *args); @@ -149,6 +150,15 @@ static LPC_COMMAND commands[] = { "'help '\t: displays specific help for command.\n" "'help advanced'\t: shows advanced commands.\n" }, + { "answer", lpc_cmd_answer, "Answer a call", + "'answer' : Answer the current incoming call\n" + "'answer ' : Answer the call with given id\n" + }, + { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", + "'autoanswer' \t: show current autoanswer mode\n" + "'autoanswer enable'\t: enable autoanswer mode\n" + "'autoanswer disable'\t: disable autoanswer mode\n" + }, { "call", lpc_cmd_call, "Call a SIP uri or number", #ifdef VIDEO_ENABLED "'call [options]' \t: initiate a call to the specified destination.\n" @@ -161,83 +171,24 @@ static LPC_COMMAND commands[] = { }, { "calls", lpc_cmd_calls, "Show all the current calls with their id and status.", NULL - }, + }, + { "call-logs", lpc_cmd_call_logs, "Calls history", NULL + }, +#ifdef VIDEO_ENABLED + { "camera", lpc_cmd_camera, "Send camera output for current call.", + "'camera on'\t: allow sending of local camera video to remote end.\n" + "'camera off'\t: disable sending of local camera's video to remote end.\n" + }, +#endif { "chat", lpc_cmd_chat, "Chat with a SIP uri", "'chat \"message\"' " ": send a chat message \"message\" to the specified destination." - }, - { "terminate", lpc_cmd_terminate, "Terminate a call", - "'terminate' : Terminate the current call\n" - "'terminate ' : Terminate the call with supplied id\n" - "'terminate ' : Terminate all the current calls\n" - }, - { "answer", lpc_cmd_answer, "Answer a call", - "'answer' : Answer the current incoming call\n" - "'answer ' : Answer the call with given id\n" - }, - { "pause", lpc_cmd_pause, "pause a call", - "'pause' : pause the current call\n"}, - { "resume", lpc_cmd_resume, "resume a call", - "'resume' : resume the unique call\n" - "'resume ' : hold off the call with given id\n"}, - { "transfer", lpc_cmd_transfer, - "Transfer a call to a specified destination.", - "'transfer ' : transfers the current active call to the destination sip-uri\n" - "'transfer ': transfers the call with 'id' to the destination sip-uri\n" - "'transfer --to-call ': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n" }, { "conference", lpc_cmd_conference, "Create and manage an audio conference.", "'conference add : join the call with id 'call id' into the audio conference." "'conference rm : remove the call with id 'call id' from the audio conference." }, - { "mute", lpc_cmd_mute_mic, - "Mute microphone and suspend voice transmission."}, -#ifdef VIDEO_ENABLED - { "camera", lpc_cmd_camera, "Send camera output for current call.", - "'camera on'\t: allow sending of local camera video to remote end.\n" - "'camera off'\t: disable sending of local camera's video to remote end.\n"}, -#endif - { "unmute", lpc_cmd_unmute_mic, - "Unmute microphone and resume voice transmission."}, - { "playbackgain", lpc_cmd_playback_gain, - "Adjust playback gain."}, - { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL }, - - { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", - "'autoanswer' \t: show current autoanswer mode\n" - "'autoanswer enable'\t: enable autoanswer mode\n" - "'autoanswer disable'\t: disable autoanswer mode��\n"}, - { "proxy", lpc_cmd_proxy, "Manage proxies", - "'proxy list' : list all proxy setups.\n" - "'proxy add' : add a new proxy setup.\n" - "'proxy remove ' : remove proxy setup with number index.\n" - "'proxy use ' : use proxy with number index as default proxy.\n" - "'proxy unuse' : don't use a default proxy.\n" - "'proxy show ' : show configuration and status of the proxy numbered by index.\n" - "'proxy show default' : show configuration and status of the default proxy.\n" - }, - { "soundcard", lpc_cmd_soundcard, "Manage soundcards", - "'soundcard list' : list all sound devices.\n" - "'soundcard show' : show current sound devices configuration.\n" - "'soundcard use ' : select a sound device.\n" - "'soundcard use files' : use .wav files instead of soundcard\n" - }, - { "webcam", lpc_cmd_webcam, "Manage webcams", - "'webcam list' : list all known devices.\n" - "'webcam use ' : select a video device.\n" - }, - { "ipv6", lpc_cmd_ipv6, "Use IPV6", - "'ipv6 status' : show ipv6 usage status.\n" - "'ipv6 enable' : enable the use of the ipv6 network.\n" - "'ipv6 disable' : do not use ipv6 network." - }, - { "nat", lpc_cmd_nat, "Set nat address", - "'nat' : show nat settings.\n" - "'nat ' : set nat address.\n" - }, - { "stun", lpc_cmd_stun, "Set stun server address", - "'stun' : show stun settings.\n" - "'stun ' : set stun server address.\n" + { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL }, { "firewall", lpc_cmd_firewall, "Set firewall policy", "'firewall' : show current firewall policy.\n" @@ -247,7 +198,6 @@ static LPC_COMMAND commands[] = { "'firewall ice' : use ice.\n" "'firewall upnp' : use uPnP IGD.\n" }, - { "call-logs", lpc_cmd_call_logs, "Calls history", NULL }, { "friend", lpc_cmd_friend, "Manage friends", "'friend list []' : list friends.\n" "'friend call ' : call a friend.\n" @@ -256,18 +206,79 @@ static LPC_COMMAND commands[] = { " there. Don't use '<' '>' around .\n" "'friend delete ' : remove friend, 'all' removes all\n" }, + { "ipv6", lpc_cmd_ipv6, "Use IPV6", + "'ipv6 status' : show ipv6 usage status.\n" + "'ipv6 enable' : enable the use of the ipv6 network.\n" + "'ipv6 disable' : do not use ipv6 network." + }, + { "mute", lpc_cmd_mute_mic, + "Mute microphone and suspend voice transmission." + }, + { "nat", lpc_cmd_nat, "Set nat address", + "'nat' : show nat settings.\n" + "'nat ' : set nat address.\n" + }, + { "pause", lpc_cmd_pause, "pause a call", + "'pause' : pause the current call\n" + }, { "play", lpc_cmd_play, "play a wav file", "This command has two roles:\n" "Plays a file instead of capturing from soundcard - only available in file mode (see 'help soundcard')\n" "Specifies a wav file to be played to play music to far end when putting it on hold (pause)\n" "'play ' : play a wav file." }, + { "playbackgain", lpc_cmd_playback_gain, + "Adjust playback gain." + }, + { "proxy", lpc_cmd_proxy, "Manage proxies", + "'proxy list' : list all proxy setups.\n" + "'proxy add' : add a new proxy setup.\n" + "'proxy remove ' : remove proxy setup with number index.\n" + "'proxy use ' : use proxy with number index as default proxy.\n" + "'proxy unuse' : don't use a default proxy.\n" + "'proxy show ' : show configuration and status of the proxy numbered by index.\n" + "'proxy show default' : show configuration and status of the default proxy.\n" + }, { "record", lpc_cmd_record, "record to a wav file", "This feature is available only in file mode (see 'help soundcard')\n" "'record ' : record into wav file." }, - { "quit", lpc_cmd_quit, "Exit linphonec", NULL }, - { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL } + { "resume", lpc_cmd_resume, "resume a call", + "'resume' : resume the unique call\n" + "'resume ' : hold off the call with given id\n" + }, + { "soundcard", lpc_cmd_soundcard, "Manage soundcards", + "'soundcard list' : list all sound devices.\n" + "'soundcard show' : show current sound devices configuration.\n" + "'soundcard use ' : select a sound device.\n" + "'soundcard use files' : use .wav files instead of soundcard\n" + }, + { "stun", lpc_cmd_stun, "Set stun server address", + "'stun' : show stun settings.\n" + "'stun ' : set stun server address.\n" + }, + { "terminate", lpc_cmd_terminate, "Terminate a call", + "'terminate' : Terminate the current call\n" + "'terminate ' : Terminate the call with supplied id\n" + "'terminate ' : Terminate all the current calls\n" + }, + { "transfer", lpc_cmd_transfer, + "Transfer a call to a specified destination.", + "'transfer ' : transfers the current active call to the destination sip-uri\n" + "'transfer ': transfers the call with 'id' to the destination sip-uri\n" + "'transfer --to-call ': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n" + }, + { "unmute", lpc_cmd_unmute_mic, + "Unmute microphone and resume voice transmission." + }, + { "webcam", lpc_cmd_webcam, "Manage webcams", + "'webcam list' : list all known devices.\n" + "'webcam use ' : select a video device.\n" + }, + { "quit", lpc_cmd_quit, "Exit linphonec", NULL + }, + { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL + } }; @@ -291,7 +302,8 @@ static LPC_COMMAND advanced_commands[] = { { "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute, "Set the rtp_no_xmit_on_audio_mute configuration parameter", " If set to 1 then rtp transmission will be muted when\n" - " audio is muted , otherwise rtp is always sent."}, + " audio is muted , otherwise rtp is always sent." + }, #ifdef VIDEO_ENABLED { "vwindow", lpc_cmd_video_window, "Control video display window", "'vwindow show': shows video window\n" @@ -312,20 +324,25 @@ static LPC_COMMAND advanced_commands[] = { { "snapshot", lpc_cmd_snapshot, "Take a snapshot of currently received video stream", "'snapshot ': take a snapshot and records it in jpeg format into the supplied path\n" }, - { "vfureq", lpc_cmd_vfureq, "Request the other side to send VFU for the current call"}, + { "preview-snapshot", lpc_cmd_preview_snapshot, "Take a snapshot of currently captured video stream", + "'preview-snapshot ': take a snapshot and records it in jpeg format into the supplied path\n" + }, + { "vfureq", lpc_cmd_vfureq, "Request the other side to send VFU for the current call" +}, #endif { "states", lpc_cmd_states, "Show internal states of liblinphone, registrations and calls, according to linphonecore.h definitions", "'states global': shows global state of liblinphone \n" "'states calls': shows state of calls\n" "'states proxies': shows state of proxy configurations" }, - { "register", lpc_cmd_register, "Register in one line to a proxy" , "register "}, + { "register", lpc_cmd_register, "Register in one line to a proxy" , "register " +}, { "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL }, - { "status", lpc_cmd_status, "Print various status information", + { "status", lpc_cmd_status, "Print various status information", "'status register' \t: print status concerning registration\n" "'status autoanswer'\t: tell whether autoanswer mode is enabled\n" "'status hook' \t: print hook status\n" }, - { "ports", lpc_cmd_ports, "Network ports configuration", + { "ports", lpc_cmd_ports, "Network ports configuration", "'ports' \t: prints current used ports.\n" "'ports sip '\t: Sets the sip port.\n" }, { "param", lpc_cmd_param, "parameter set or read as normally given in .linphonerc", @@ -365,7 +382,7 @@ static LPC_COMMAND advanced_commands[] = { /*************************************************************************** * - * Public interface + * Public interface * ***************************************************************************/ @@ -476,7 +493,7 @@ linphonec_command_generator(const char *text, int state) /*************************************************************************** * - * Command handlers + * Command handlers * ***************************************************************************/ @@ -497,7 +514,7 @@ lpc_cmd_help(LinphoneCore *lc, char *arg) commands[i].help); i++; } - + linphonec_out("---------------------------\n"); linphonec_out("Type 'help ' for more details or\n"); linphonec_out(" 'help advanced' to list additional commands.\n"); @@ -511,17 +528,17 @@ lpc_cmd_help(LinphoneCore *lc, char *arg) i=0; while (advanced_commands[i].help) { - linphonec_out("%10.10s\t%s\n", advanced_commands[i].name, + linphonec_out("%20.20s\t%s\n", advanced_commands[i].name, advanced_commands[i].help); i++; } - + linphonec_out("---------------------------\n"); linphonec_out("Type 'help ' for more details.\n"); return 1; } - + cmd=lpc_find_command(arg); if ( !cmd ) { @@ -558,10 +575,12 @@ lpc_cmd_call(LinphoneCore *lc, char *args) opt2=strstr(args,"--early-media"); if (opt1){ opt1[0]='\0'; + while(--opt1 > args && opt1[0]==' ') opt1[0]='\0'; linphone_call_params_enable_video (cp,FALSE); } if (opt2){ opt2[0]='\0'; + while(--opt2 > args && opt2[0]==' ') opt2[0]='\0'; linphone_call_params_enable_early_media_sending(cp,TRUE); } if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) ) @@ -577,7 +596,7 @@ lpc_cmd_call(LinphoneCore *lc, char *args) return 1; } -static int +static int lpc_cmd_calls(LinphoneCore *lc, char *args){ const MSList *calls = linphone_core_get_calls(lc); if(calls) @@ -597,6 +616,7 @@ lpc_cmd_chat(LinphoneCore *lc, char *args) char *arg1 = args; char *arg2 = NULL; char *ptr = args; + LinphoneChatRoom *cr; if (!args) return 0; @@ -613,10 +633,8 @@ lpc_cmd_chat(LinphoneCore *lc, char *args) /* missing one parameter */ return 0; } - LinphoneChatRoom *cr = linphone_core_create_chat_room(lc,arg1); + cr = linphone_core_get_chat_room_from_uri(lc,arg1); linphone_chat_room_send_message(cr,arg2); - linphone_chat_room_destroy(cr); - return 1; } @@ -692,7 +710,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) } return 1; } - + if(strcmp(args,"all")==0){ linphonec_out("We are going to stop all the calls.\n"); linphone_core_terminate_all_calls(lc); @@ -709,7 +727,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) return 1; } return 0; - + } static int @@ -852,7 +870,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) { linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall); } - else if (strcmp(args,"upnp")==0) + else if (strcmp(args,"upnp")==0) { linphone_core_set_firewall_policy(lc,LinphonePolicyUseUpnp); } @@ -930,7 +948,7 @@ lpc_friend_name(char **args, char **name) *args = ++end; } else { *name = strsep(args, " "); - + if (NULL == *args) { /* Means there was no separator */ fprintf(stderr, "Either name or address is missing\n"); return 0; @@ -960,7 +978,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) args+=4; if ( ! *args ) return 0; friend_num = strtol(args, NULL, 10); -#ifndef _WIN32_WCE +#ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); return 0; @@ -978,11 +996,11 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) if (!strncmp(args, "all", 3)) { friend_num = -1; - } + } else { friend_num = strtol(args, NULL, 10); -#ifndef _WIN32_WCE +#ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); return 0; @@ -1022,7 +1040,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 +1100,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 +1128,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 */ @@ -1410,7 +1429,7 @@ static int lpc_cmd_pause(LinphoneCore *lc, char *args){ } static int lpc_cmd_resume(LinphoneCore *lc, char *args){ - + if(linphone_core_in_call(lc)) { linphonec_out("There is already a call in process pause or stop it first"); @@ -1449,7 +1468,7 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ } } return 0; - + } static int lpc_cmd_conference(LinphoneCore *lc, char *args){ @@ -1513,7 +1532,7 @@ linphonec_proxy_add(LinphoneCore *lc) continue; } - cfg=linphone_proxy_config_new(); + cfg=linphone_core_create_proxy_config(lc); if (linphone_proxy_config_set_server_addr(cfg,clean)<0) { linphonec_out("Invalid sip address (sip:sip.domain.tld).\n"); @@ -1595,7 +1614,7 @@ linphonec_proxy_add(LinphoneCore *lc) */ if ( enable_register==TRUE ) { - long int expires=0; + int expires=0; while (1) { char *input=linphonec_readline("Specify register expiration time" @@ -1607,15 +1626,10 @@ linphonec_proxy_add(LinphoneCore *lc) return; } - expires=strtol(input, (char **)NULL, 10); - if ( expires == LONG_MIN || expires == LONG_MAX ) - { - linphonec_out("Invalid value: %s\n", strerror(errno)); - free(input); - continue; - } + expires=atoi(input); + if (expires==0) expires=600; - 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); @@ -1658,7 +1672,7 @@ linphonec_proxy_add(LinphoneCore *lc) } /* - * Final confirmation + * Final confirmation */ while (1) { @@ -1741,12 +1755,12 @@ linphonec_proxy_list(LinphoneCore *lc) const MSList *proxies; int n; int def=linphone_core_get_default_proxy(lc,NULL); - + proxies=linphone_core_get_proxy_config_list(lc); for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){ if (n==def) linphonec_out("****** Proxy %i - this is the default one - *******\n",n); - else + else linphonec_out("****** Proxy %i *******\n",n); linphonec_proxy_display((LinphoneProxyConfig*)proxies->data); } @@ -1788,7 +1802,7 @@ linphonec_friend_display(LinphoneFriend *fr) { LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr)); char *str; - + linphonec_out("name: %s\n", linphone_address_get_display_name(uri)); linphone_address_set_display_name(uri,NULL); str=linphone_address_as_string(uri); @@ -1852,7 +1866,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; } @@ -1873,7 +1887,7 @@ linphonec_friend_delete(LinphoneCore *lc, int num) } } - if (-1 == num) + if (-1 == num) { unsigned int i; for (i = 0 ; i < n ; i++) @@ -1899,26 +1913,26 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ char passwd[512]; LinphoneProxyConfig *cfg; const MSList *elem; - + if (!args) - { - /* it means that you want to register the default proxy */ - LinphoneProxyConfig *cfg=NULL; - linphone_core_get_default_proxy(lc,&cfg); - if (cfg) - { - if(!linphone_proxy_config_is_registered(cfg)) { + { + /* it means that you want to register the default proxy */ + LinphoneProxyConfig *cfg=NULL; + linphone_core_get_default_proxy(lc,&cfg); + if (cfg) + { + if(!linphone_proxy_config_is_registered(cfg)) { linphone_proxy_config_enable_register(cfg,TRUE); linphone_proxy_config_done(cfg); }else{ linphonec_out("default proxy already registered\n"); } - }else{ - linphonec_out("we do not have a default proxy\n"); - return 0; - } - return 1; - } + }else{ + linphonec_out("we do not have a default proxy\n"); + return 0; + } + return 1; + } passwd[0]=proxy[0]=identity[0]='\0'; sscanf(args,"%511s %511s %511s",identity,proxy,passwd); if (proxy[0]=='\0' || identity[0]=='\0'){ @@ -1929,9 +1943,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(linphone_address_get_username(from),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 +1954,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); @@ -1980,7 +1992,7 @@ static int lpc_cmd_duration(LinphoneCore *lc, char *args){ static int lpc_cmd_status(LinphoneCore *lc, char *args) { LinphoneProxyConfig *cfg; - + if ( ! args ) return 0; linphone_core_get_default_proxy(lc,&cfg); if (strstr(args,"register")) @@ -2030,7 +2042,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" , @@ -2043,7 +2055,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args) default: break; } - + } else return 0; @@ -2102,15 +2114,25 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){ char voice[64]; char *sentence; char cl[128]; - char *wavfile; + char wavfile[128]="/tmp/linphonec-espeak-XXXXXX"; int status; FILE *file; - + if (!args) return 0; memset(voice,0,sizeof(voice)); sscanf(args,"%63s",voice); sentence=args+strlen(voice); - wavfile=tempnam("/tmp/","linphonec-espeak-"); + +#ifdef __APPLE__ + mktemp(wavfile); +#else + if (mkstemp(wavfile)==-1){ + ms_error("Could not create temporary filename: %s", strerror(errno)); + linphonec_out("An error occured, please consult logs for details."); + return 1; + } +#endif + snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile); file=popen(cl,"w"); if (file==NULL){ @@ -2195,7 +2217,7 @@ static void linphonec_codec_list(int type, LinphoneCore *lc){ for(;node!=NULL;node=ms_list_next(node)){ pt=(PayloadType*)(node->data); - linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, + linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled"); index++; } @@ -2269,7 +2291,7 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){ if (arg2 != 0) { n = sscanf(arg2, "%d %d %d", &delay, &tail_len, &frame_size); - if (n == 1) { + if (n == 1) { lp_config_set_int(config,"sound","ec_delay",delay); } else if (n == 2) { @@ -2287,11 +2309,11 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){ linphone_core_enable_echo_cancellation(lc,0); } else if (strcmp(arg1,"show")==0){ - linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", + linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", linphone_core_echo_cancellation_enabled(lc) ? "on" : "off", lp_config_get_int(config,"sound","ec_delay",0), lp_config_get_int(config,"sound","ec_tail_len",0), - lp_config_get_int(config,"sound","ec_framesize",0)); + lp_config_get_int(config,"sound","ec_framesize",0)); } else { return 0; @@ -2341,7 +2363,7 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) if(strstr(args,"1"))rtp_xmit_off=TRUE; if(linphone_core_get_current_call (lc)==NULL) linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off); - else + else linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n"); } rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc); @@ -2354,12 +2376,12 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) #ifdef VIDEO_ENABLED static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview){ char subcommand[64]; - int a,b; + long a,b; int err; VideoParams *params=is_preview ? &lpc_preview_params : &lpc_video_params; if (!args) return 0; - err=sscanf(args,"%63s %i %i",subcommand,&a,&b); + err=sscanf(args,"%63s %ld %ld",subcommand,&a,&b); if (err>=1){ if (strcmp(subcommand,"pos")==0){ if (err<3) return 0; @@ -2381,15 +2403,15 @@ static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview if (is_preview) linphone_core_enable_video_preview (lc,FALSE); }else if (strcmp(subcommand,"id")==0){ if (err == 1){ - linphonec_out("vwindow id: 0x%x\n",is_preview ? linphone_core_get_native_preview_window_id (lc) : + linphonec_out("vwindow id: 0x%p\n",is_preview ? linphone_core_get_native_preview_window_id (lc) : linphone_core_get_native_video_window_id (lc)); return 1; } else if (err != 2) return 0; - params->wid=a; + params->wid=(void *)a; if (is_preview) - linphone_core_set_native_preview_window_id (lc,a); + linphone_core_set_native_preview_window_id(lc, (void *)a); else - linphone_core_set_native_video_window_id(lc,a); + linphone_core_set_native_video_window_id(lc, (void *)a); }else if (is_preview==TRUE){ if (strcmp(subcommand,"integrated")==0){ linphone_core_use_preview_window (lc,FALSE); @@ -2428,8 +2450,9 @@ static void lpc_display_call_states(LinphoneCore *lc){ }else{ for(;elem!=NULL;elem=elem->next){ const char *flag; + bool_t in_conference; call=(LinphoneCall*)elem->data; - bool_t in_conference=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + in_conference=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); tmp=linphone_call_get_remote_address_as_string (call); flag=in_conference ? "conferencing" : ""; flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag; @@ -2482,7 +2505,7 @@ static int lpc_cmd_states(LinphoneCore *lc, char *args){ static int lpc_cmd_camera(LinphoneCore *lc, char *args){ LinphoneCall *call=linphone_core_get_current_call(lc); bool_t activated=FALSE; - + if (linphone_core_video_enabled (lc)==FALSE){ linphonec_out("Video is disabled, re-run linphonec with -V option."); return 1; @@ -2510,13 +2533,15 @@ static int lpc_cmd_camera(LinphoneCore *lc, char *args){ const LinphoneCallParams *cp=linphone_call_get_current_params (call); if (args){ linphone_call_enable_camera(call,activated); - if ((activated && !linphone_call_params_video_enabled (cp))){ - /*update the call to add the video stream*/ - LinphoneCallParams *ncp=linphone_call_params_copy(cp); - linphone_call_params_enable_video(ncp,TRUE); - linphone_core_update_call(lc,call,ncp); - linphone_call_params_destroy (ncp); - linphonec_out("Trying to bring up video stream...\n"); + if (linphone_call_get_state(call)==LinphoneCallStreamsRunning){ + if ((activated && !linphone_call_params_video_enabled (cp))){ + /*update the call to add the video stream*/ + LinphoneCallParams *ncp=linphone_call_params_copy(cp); + linphone_call_params_enable_video(ncp,TRUE); + linphone_core_update_call(lc,call,ncp); + linphone_call_params_destroy (ncp); + linphonec_out("Trying to bring up video stream...\n"); + } } } if (linphone_call_camera_enabled (call)) @@ -2537,6 +2562,17 @@ static int lpc_cmd_snapshot(LinphoneCore *lc, char *args){ return 1; } +static int lpc_cmd_preview_snapshot(LinphoneCore *lc, char *args){ + LinphoneCall *call; + if (!args) return 0; + call=linphone_core_get_current_call(lc); + if (call!=NULL){ + linphone_call_take_preview_snapshot(call,args); + linphonec_out("Taking video preview snapshot in file %s\n", args); + }else linphonec_out("There is no active call.\n"); + return 1; +} + static int lpc_cmd_vfureq(LinphoneCore *lc, char *arg){ LinphoneCall *call; call=linphone_core_get_current_call(lc); diff --git a/console/linphonec.c b/console/linphonec.c index fca5a9b86..cdf06f474 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -25,9 +25,7 @@ ****************************************************************************/ #include #ifndef _WIN32_WCE -#include #include -#include #include #include #include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */ @@ -48,32 +46,25 @@ #endif /*_WIN32_WCE*/ #else #include +#include #include #include #include +#include #endif -#if defined(_WIN32_WCE) - #if !defined(PATH_MAX) #define PATH_MAX 256 #endif /*PATH_MAX*/ +#if defined(_WIN32_WCE) + #if !defined(strdup) #define strdup _strdup #endif /*strdup*/ #endif /*_WIN32_WCE*/ -#ifdef HAVE_GETTEXT -#include -#ifndef _ -#define _(String) gettext(String) -#endif -#else -#define _(something) (something) -#endif - #ifndef PACKAGE_DIR #define PACKAGE_DIR "" #endif @@ -117,13 +108,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, @@ -149,6 +139,7 @@ static char last_in_history[256]; #endif //auto answer (-a) option static bool_t auto_answer=FALSE; +static bool_t real_early_media_sending=FALSE; static bool_t answer_call=FALSE; static bool_t vcap_enabled=FALSE; static bool_t display_enabled=FALSE; @@ -161,9 +152,10 @@ static int trace_level = 0; static char *logfile_name = NULL; static char configfile_name[PATH_MAX]; static char zrtpsecrets[PATH_MAX]; +static char usr_certificates_path[PATH_MAX]; static const char *factory_configfile_name=NULL; static char *sip_addr_to_call = NULL; /* for autocall */ -static int window_id = 0; /* 0=standalone window, or window id for embedding video */ +static void *window_id = NULL; /* NULL=standalone window, or window id for embedding video */ #if !defined(_WIN32_WCE) static ortp_pipe_t client_sock=ORTP_PIPE_INVALID; #endif /*_WIN32_WCE*/ @@ -256,7 +248,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 +264,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 +273,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); } @@ -362,10 +355,17 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L linphone_call_enable_camera (call,linphonec_camera_enabled); id=(long)linphone_call_get_user_pointer (call); linphonec_set_caller(from); + linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id); if ( auto_answer) { answer_call=TRUE; + } else if (real_early_media_sending) { + LinphoneCallParams* callparams = linphone_core_create_default_call_parameters(lc); + linphonec_out("Sending early media using real hardware\n"); + linphone_call_params_enable_early_media_sending(callparams, TRUE); + if (vcap_enabled) linphone_call_params_enable_video(callparams, TRUE); + linphone_core_accept_early_media_with_params(lc, call, callparams); + linphone_call_params_destroy(callparams); } - linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id); break; case LinphoneCallOutgoingInit: linphonec_call_identify(call); @@ -492,7 +492,6 @@ static void *pipe_thread(void*p){ } static void start_pipe_reader(void){ - ms_mutex_init(&prompt_mutex,NULL); pipe_reader_run=TRUE; ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL); } @@ -528,6 +527,7 @@ char *linphonec_readline(char *prompt){ fprintf(stdout,"%s",prompt); fflush(stdout); while(1){ + ms_mutex_lock(&prompt_mutex); if (have_prompt){ char *ret=strdup(received_prompt); @@ -538,15 +538,17 @@ char *linphonec_readline(char *prompt){ ms_mutex_unlock(&prompt_mutex); linphonec_idle_call(); #ifdef WIN32 - Sleep(20); - /* Following is to get the video window going as it - should. Maybe should we only have this on when the option -V - or -D is on? */ - MSG msg; - - if (PeekMessage(&msg, NULL, 0, 0,1)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + { + MSG msg; + Sleep(20); + /* Following is to get the video window going as it + should. Maybe should we only have this on when the option -V + or -D is on? */ + + if (PeekMessage(&msg, NULL, 0, 0,1)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } #else usleep(20000); @@ -628,8 +630,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,9 +640,9 @@ 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); linphonec_main_loop (linphonec); @@ -650,6 +652,12 @@ main (int argc, char *argv[]) { exit(EXIT_SUCCESS); /* should never reach here */ } +#ifdef _MSC_VER +int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + return main(__argc, __argv); +} +#endif + /* * Initialize linphonec */ @@ -663,13 +671,15 @@ linphonec_init(int argc, char **argv) * Set initial values for global variables */ mylogfile = NULL; - - + + #ifndef _WIN32 snprintf(configfile_name, PATH_MAX, "%s/.linphonerc", getenv("HOME")); snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache", getenv("HOME")); + snprintf(usr_certificates_path, PATH_MAX, "%s/.linphone-usr-crt", + getenv("HOME")); #elif defined(_WIN32_WCE) strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX); mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w"); @@ -679,6 +689,8 @@ linphonec_init(int argc, char **argv) getenv("APPDATA")); snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache", getenv("APPDATA")); + snprintf(usr_certificates_path, PATH_MAX, "%s/Linphone/linphone-usr-crt", + getenv("APPDATA")); #endif /* Handle configuration filename changes */ switch (handle_configfile_migration()) @@ -694,17 +706,6 @@ linphonec_init(int argc, char **argv) break; } -#ifdef ENABLE_NLS - if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR)) - perror ("bindtextdomain failed"); -#ifndef __ARM__ - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif - textdomain (GETTEXT_PACKAGE); -#else - printf ("NLS disabled.\n"); -#endif - linphonec_parse_cmdline(argc, argv); if (trace_level > 0) @@ -733,11 +734,15 @@ linphonec_init(int argc, char **argv) * Initialize linphone core */ linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL); + + linphone_core_set_user_agent(linphonec,"Linphonec", LINPHONE_VERSION); linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets); - linphone_core_enable_video(linphonec,vcap_enabled,display_enabled); - if (display_enabled && window_id != 0) + linphone_core_set_user_certificates_path(linphonec,usr_certificates_path); + linphone_core_enable_video_capture(linphonec, vcap_enabled); + linphone_core_enable_video_display(linphonec, display_enabled); + if (display_enabled && (window_id != NULL)) { - printf ("Setting window_id: 0x%x\n", window_id); + printf("Setting window_id: 0x%p\n", window_id); linphone_core_set_native_video_window_id(linphonec,window_id); } @@ -773,7 +778,7 @@ linphonec_finish(int exit_status) { // Do not allow concurrent destroying to prevent glibc errors static bool_t terminating=FALSE; - if (terminating) return; + if (terminating) return; terminating=TRUE; linphonec_out("Terminating...\n"); @@ -792,6 +797,7 @@ linphonec_finish(int exit_status) if (mylogfile != NULL && mylogfile != stdout) { fclose (mylogfile); + mylogfile=stdout; } printf("\n"); exit(exit_status); @@ -818,12 +824,13 @@ linphonec_prompt_for_auth_final(LinphoneCore *lc) #ifdef HAVE_READLINE rl_hook_func_t *old_event_hook; #endif + LinphoneAuthInfo *pending_auth; if (reentrancy!=0) return 0; - + reentrancy++; - - LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1]; + + pending_auth=auth_stack.elem[auth_stack.nitems-1]; snprintf(auth_prompt, 256, "Password for %s on %s: ", pending_auth->username, pending_auth->realm); @@ -905,12 +912,14 @@ print_usage (int exit_status) " -l logfile specify the log file for your SIP phone\n" " -s sipaddress specify the sip call to do at startup\n" " -a enable auto answering for incoming calls\n" +" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n" " -V enable video features globally (disabled by default)\n" " -C enable video capture only (disabled by default)\n" " -D enable video display only (disabled by default)\n" " -S show general state messages (disabled by default)\n" " --wid windowid force embedding of video window into provided windowid (disabled by default)\n" -" -v or --version display version and exits.\n"); +" -v or --version display version and exits.\n" +); exit(exit_status); } @@ -957,28 +966,29 @@ static void x11_apply_video_params(VideoParams *params, Window window){ static void lpc_apply_video_params(){ - static unsigned long old_wid=0,old_pwid=0; - unsigned long wid=linphone_core_get_native_video_window_id (linphonec); - unsigned long pwid=linphone_core_get_native_preview_window_id (linphonec); + static void *old_wid=NULL; + static void *old_pwid=NULL; + void *wid=linphone_core_get_native_video_window_id(linphonec); + void *pwid=linphone_core_get_native_preview_window_id(linphonec); - if (wid!=0 && (lpc_video_params.refresh || old_wid!=wid)){ + if (wid!=NULL && (lpc_video_params.refresh || old_wid!=wid)){ lpc_video_params.refresh=FALSE; #ifdef HAVE_X11_XLIB_H if (lpc_video_params.wid==0){ // do not manage window if embedded - x11_apply_video_params(&lpc_video_params,wid); + x11_apply_video_params(&lpc_video_params,(Window)wid); } else { linphone_core_show_video(linphonec, lpc_video_params.show); } #endif } old_wid=wid; - if (pwid!=0 && (lpc_preview_params.refresh || old_pwid!=pwid)){ + if (pwid!=NULL && (lpc_preview_params.refresh || old_pwid!=pwid)){ lpc_preview_params.refresh=FALSE; #ifdef HAVE_X11_XLIB_H - /*printf("wid=%lu pwid=%lu\n",wid,pwid);*/ - if (lpc_preview_params.wid==0){ // do not manage window if embedded + /*printf("wid=%p pwid=%p\n",wid,pwid);*/ + if (lpc_preview_params.wid==NULL){ // do not manage window if embedded printf("Refreshing\n"); - x11_apply_video_params(&lpc_preview_params,pwid); + x11_apply_video_params(&lpc_preview_params,(Window)pwid); } #endif } @@ -1074,7 +1084,7 @@ linphonec_initialize_readline() rl_attempted_completion_function = linephonec_readline_completion; /* printf("Readline initialized.\n"); */ - setlinebuf(stdout); + setlinebuf(stdout); return 0; } @@ -1149,7 +1159,6 @@ linphonec_main_loop (LinphoneCore * opm) add_history(iptr); } #endif - linphonec_parse_command_line(linphonec, iptr); linphonec_command_finished(); free(input); @@ -1193,15 +1202,21 @@ linphonec_parse_cmdline(int argc, char **argv) else if (strncmp ("-c", argv[arg_num], 2) == 0) { if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE); +#ifdef _MSC_VER + if (strcmp(argv[arg_num], "NUL") != 0) { +#endif #if !defined(_WIN32_WCE) - if (access(argv[arg_num],F_OK)!=0 ) - { - fprintf (stderr, - "Cannot open config file %s.\n", - argv[arg_num]); - exit(EXIT_FAILURE); - } + if (access(argv[arg_num], F_OK) != 0) + { + fprintf(stderr, + "Cannot open config file %s.\n", + argv[arg_num]); + exit(EXIT_FAILURE); + } #endif /*_WIN32_WCE*/ +#ifdef _MSC_VER + } +#endif snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]); } else if (strncmp ("-b", argv[arg_num], 2) == 0) @@ -1228,6 +1243,10 @@ linphonec_parse_cmdline(int argc, char **argv) { auto_answer = TRUE; } + else if (strncmp ("--real-early-media", argv[arg_num], strlen("--real-early-media")) == 0) + { + real_early_media_sending = TRUE; + } else if (strncmp ("-C", argv[arg_num], 2) == 0) { vcap_enabled = TRUE; @@ -1266,7 +1285,7 @@ linphonec_parse_cmdline(int argc, char **argv) arg_num++; if (arg_num < argc) { char *tmp; - window_id = strtol( argv[arg_num], &tmp, 0 ); + window_id = (void *)strtol( argv[arg_num], &tmp, 0 ); lpc_video_params.wid = window_id; } } @@ -1305,11 +1324,7 @@ handle_configfile_migration() char *old_cfg_gui; char *old_cfg_cli; char *new_cfg; -#if !defined(_WIN32_WCE) const char *home = getenv("HOME"); -#else - const char *home = "."; -#endif /*_WIN32_WCE*/ new_cfg = ms_strdup_printf("%s/.linphonerc", home); /* @@ -1400,6 +1415,7 @@ copy_file(const char *from, const char *to) snprintf(message, 255, "Can't open %s for writing: %s\n", to, strerror(errno)); fprintf(stderr, "%s", message); + fclose(in); return 0; } @@ -1408,6 +1424,8 @@ copy_file(const char *from, const char *to) { if ( ! fwrite(buf, 1, n, out) ) { + fclose(in); + fclose(out); return 0; } } diff --git a/console/linphonec.h b/console/linphonec.h index 3265d42ac..23c0ee5a0 100644 --- a/console/linphonec.h +++ b/console/linphonec.h @@ -99,7 +99,7 @@ typedef struct { typedef struct { int x,y,w,h; - unsigned long wid; + void *wid; bool_t show; bool_t refresh; } VideoParams; diff --git a/console/shell.c b/console/shell.c index e61a6e514..7fbccb4c3 100644 --- a/console/shell.c +++ b/console/shell.c @@ -22,12 +22,13 @@ #include #include - +#include +#include #ifdef WIN32 +#include #include #include -#include #include #include #else @@ -47,6 +48,7 @@ #define STATUS_AUTOANSWER (1<<3) #define STATUS_IN_CONNECTED (1<<4) /* incoming call accepted */ #define STATUS_OUT_CONNECTED (1<<5) /*outgoing call accepted */ +#define STATUS_IN_COMING (1<<6) /*incoming call pending */ static int make_status_value(const char *status_string){ @@ -69,6 +71,9 @@ static int make_status_value(const char *status_string){ if (strstr(status_string,"hook=answered")){ ret|=STATUS_IN_CONNECTED; } + if (strstr(status_string,"Incoming call from ")){ + ret|=STATUS_IN_COMING; + } return ret; } @@ -125,11 +130,36 @@ static void print_usage(void){ exit(-1); } +#ifdef WIN32 +static char *argv_to_line(int argc, char *argv[]) { + int i; + int line_length; + char *line; + + assert( argc>=0 ); + + if(argc == 0) return NULL; + + line_length = strlen(argv[0]); + for(i=1; i $(GITVERSION_FILE_TMP) ; \ - elif test "$(GITREVISION)" != "" ; then \ - $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ - else \ - $(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \ + if test -n "$(GITLOG)" ; then \ + if test "$(GITDESCRIBE)" != "" ; then \ + if [ "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ]; then \ + $(ECHO) "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ + exit 1; \ + fi ; \ + printf "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"\n" > $(builddir)/$(GITVERSION_FILE_TMP) ; \ + elif test "$(GITREVISION)" != "" ; then \ + printf "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"\n" > $(builddir)/$(GITVERSION_FILE_TMP) ; \ + else \ + printf "" > $(builddir)/$(GITVERSION_FILE_TMP) ; \ + fi ; \ + if ! test -f $(builddir)/$(GITVERSION_FILE) ; then \ + cp -f $(builddir)/$(GITVERSION_FILE_TMP) $(builddir)/$(GITVERSION_FILE) ; \ + fi ; \ + if test "`cat $(builddir)/$(GITVERSION_FILE_TMP)`" != "`cat $(builddir)/$(GITVERSION_FILE)`" ; then \ + cp -f $(builddir)/$(GITVERSION_FILE_TMP) $(builddir)/$(GITVERSION_FILE) ; \ + fi ; \ + rm -f $(builddir)/$(GITVERSION_FILE_TMP) ; \ fi - if test ! -f $(srcdir)/$(GITVERSION_FILE) ; then \ - cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \ - fi - if test "`cat $(GITVERSION_FILE_TMP)`" != "`cat $(srcdir)/$(GITVERSION_FILE)`" ; then \ - cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \ - fi - rm -f $(GITVERSION_FILE_TMP) ; $(GITVERSION_FILE): make_gitversion_h diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 4828bf114..128707a12 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -1,7 +1,7 @@ /* * C Implementation: tunnel * - * Description: + * Description: * * * Author: Simon Morlat , (C) 2009 @@ -16,92 +16,22 @@ #include "ortp/rtpsession.h" #include "linphonecore.h" #include "linphonecore_utils.h" -#include "eXosip2/eXosip_transport_hook.h" -#include "tunnel/udp_mirror.hh" +#include "private.h" #ifdef ANDROID #include #endif +belledonnecomm::TunnelManager *bcTunnel(const LinphoneTunnel *tunnel); using namespace belledonnecomm; using namespace ::std; -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){ - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - - sMutex.lock(); - if (lTunnelMgr->mSipSocket==NULL){ - sMutex.unlock(); - return len; - } - lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen); - sMutex.unlock(); - //ignore the error in all cases, retransmissions might be successful. - return len; -} - -int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){ - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - int err; - sMutex.lock(); - if (lTunnelMgr->mSipSocket==NULL){ - sMutex.unlock(); - return 0;//let ignore the error - } - err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen); - sMutex.unlock(); - return err; -} - -int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){ - struct timeval begin,cur; - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - if (s1 && tv!=0 && tv->tv_sec){ - /*this is the select from udp.c, the one that is interesting to us*/ - NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket(); - NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd(); - - FD_ZERO(s1); - gettimeofday(&begin,NULL); - do{ - struct timeval abit; - - abit.tv_sec=0; - abit.tv_usec=20000; - sMutex.lock(); - if (lTunnelMgr->mSipSocket!=NULL){ - if (lTunnelMgr->mSipSocket->hasData()) { - sMutex.unlock(); - /* we make exosip believe that it has udp data to read*/ - FD_SET(udp_fd,s1); - return 1; - } - } - sMutex.unlock(); - gettimeofday(&cur,NULL); - if (cur.tv_sec-begin.tv_sec>tv->tv_sec) { - FD_SET(controlfd,s1); - FD_SET(udp_fd,s1); - return 0; - } - FD_ZERO(s1); - FD_SET(controlfd,s1); - if (select(max_fds,s1,s2,s3,&abit)==1) { - return 1; - } - }while(1); - - }else{ - /*select called from other places, only the control fd is present */ - return select(max_fds,s1,s2,s3,tv); - } -} - - void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) { + if (ip == NULL) { + ip = ""; + ms_warning("Adding tunnel server with empty ip, it will not work!"); + } addServer(ip,port); mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay)); } @@ -119,7 +49,6 @@ void TunnelManager::cleanServers() { mServerAddrs.clear(); UdpMirrorClientList::iterator it; - mAutoDetectStarted=false; for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) { UdpMirrorClient& s=*it++; s.stop(); @@ -133,11 +62,6 @@ void TunnelManager::reconnect(){ mTunnelClient->reconnect(); } -void TunnelManager::setCallback(StateCallback cb, void *userdata) { - mCallback=cb; - mCallbackData=userdata; -} - static void sCloseRtpTransport(RtpTransport *t, void *userData){ TunnelSocket *s=(TunnelSocket*)userData; TunnelManager *manager=(TunnelManager*)s->getUserPointer(); @@ -145,13 +69,16 @@ static void sCloseRtpTransport(RtpTransport *t, void *userData){ } void TunnelManager::closeRtpTransport(RtpTransport *t, TunnelSocket *s){ mTunnelClient->closeSocket(s); - ms_free(t); } static RtpTransport *sCreateRtpTransport(void* userData, int port){ return ((TunnelManager *) userData)->createRtpTransport(port); } +void sDestroyRtpTransport(RtpTransport *t){ + ms_free(t); +} + RtpTransport *TunnelManager::createRtpTransport(int port){ TunnelSocket *socket=mTunnelClient->createSocket(port); socket->setUserPointer(this); @@ -160,32 +87,27 @@ RtpTransport *TunnelManager::createRtpTransport(int port){ t->t_recvfrom=customRecvfrom; t->t_sendto=customSendto; t->t_close=sCloseRtpTransport; + t->t_destroy=sDestroyRtpTransport; t->data=socket; return t; } -void TunnelManager::start() { - if (!mTunnelClient) { - mTunnelClient = new TunnelClient(); - mTunnelClient->setCallback((StateCallback)tunnelCallback,this); - list::iterator it; - for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){ - const ServerAddr &addr=*it; - mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort); - } - mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str()); +void TunnelManager::startClient() { + ms_message("TunnelManager: Starting tunnel client"); + mTunnelClient = new TunnelClient(TRUE); + mTunnelClient->setCallback((TunnelClientController::StateCallback)tunnelCallback,this); + list::iterator it; + for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){ + const ServerAddr &addr=*it; + mTunnelClient->addServer(addr.mAddr.c_str(), addr.mPort); } + mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str()); mTunnelClient->start(); - - if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060); + sal_set_tunnel(mCore->sal, mTunnelClient); } -bool TunnelManager::isStarted() { - return mTunnelClient != 0 && mTunnelClient->isStarted(); -} - -bool TunnelManager::isReady() const { - return mTunnelClient && mTunnelClient->isReady(); +bool TunnelManager::isConnected() const { + return mTunnelClient != NULL && mTunnelClient->isReady(); } int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){ @@ -197,25 +119,23 @@ int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags } int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){ + memset(&msg->recv_addr,0,sizeof(msg->recv_addr)); int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen); + //to make ice happy + inet_aton(((TunnelManager*)((TunnelSocket*)t->data)->getUserPointer())->mLocalAddr,&msg->recv_addr.addr.ipi_addr); if (err>0) return err; return 0; } - -TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() -,mCore(lc) -,mSipSocket(NULL) -,mCallback(NULL) -,mEnabled(false) -,mTunnelClient(NULL) -,mAutoDetectStarted(false) -,mHttpProxyPort(0){ - - mExosipTransport.data=this; - mExosipTransport.recvfrom=eXosipRecvfrom; - mExosipTransport.sendto=eXosipSendto; - mExosipTransport.select=eXosipSelect; +TunnelManager::TunnelManager(LinphoneCore* lc) : + mCore(lc), + mMode(LinphoneTunnelModeDisable), + mState(disabled), + mTunnelizeSipPackets(true), + mTunnelClient(NULL), + mHttpProxyPort(0), + mVTable(NULL) +{ linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); mTransportFactories.audio_rtcp_func=sCreateRtpTransport; mTransportFactories.audio_rtcp_func_data=this; @@ -225,108 +145,103 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() mTransportFactories.video_rtcp_func_data=this; mTransportFactories.video_rtp_func=sCreateRtpTransport; mTransportFactories.video_rtp_func_data=this; + mVTable = linphone_core_v_table_new(); + mVTable->network_reachable = networkReachableCb; + linphone_core_add_listener(mCore, mVTable); + linphone_core_get_local_ip_for(AF_INET, NULL, mLocalAddr); } TunnelManager::~TunnelManager(){ - stopClient(); + for(UdpMirrorClientList::iterator udpMirror = mUdpMirrorClients.begin(); udpMirror != mUdpMirrorClients.end(); udpMirror++) { + udpMirror->stop(); + } + if(mTunnelClient) delete mTunnelClient; + linphone_core_remove_listener(mCore, mVTable); + linphone_core_v_table_destroy(mVTable); } -void TunnelManager::stopClient(){ - eXosip_transport_hook_register(NULL); - if (mSipSocket != NULL){ - sMutex.lock(); - mTunnelClient->closeSocket(mSipSocket); - mSipSocket = NULL; - sMutex.unlock(); +void TunnelManager::doRegistration(){ + LinphoneProxyConfig* lProxy; + linphone_core_get_default_proxy(mCore, &lProxy); + if (lProxy) { + ms_message("TunnelManager: New registration"); + lProxy->commit = TRUE; } - if (mTunnelClient){ - delete mTunnelClient; - mTunnelClient=NULL; +} + +void TunnelManager::doUnregistration() { + LinphoneProxyConfig *lProxy; + linphone_core_get_default_proxy(mCore, &lProxy); + if(lProxy) { + _linphone_proxy_config_unregister(lProxy); } } void TunnelManager::processTunnelEvent(const Event &ev){ - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - - if (mEnabled && mTunnelClient->isReady()){ - 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); - //register - if (lProxy) { - linphone_proxy_config_done(lProxy); - } - }else if (mEnabled && !mTunnelClient->isReady()){ - /* we got disconnected from the tunnel */ - if (lProxy && linphone_proxy_config_is_registered(lProxy)) { - /*forces de-registration so that we register again when the tunnel is up*/ - linphone_proxy_config_edit(lProxy); - linphone_core_iterate(mCore); + if (ev.mData.mConnected){ + ms_message("TunnelManager: tunnel is connected"); + if(mState == connecting) { + linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories); + mState = ready; + if(mTunnelizeSipPackets) { + doUnregistration(); + _linphone_core_apply_transports(mCore); + doRegistration(); + } + } + } else { + ms_error("TunnelManager: tunnel has been disconnected"); } } -void TunnelManager::waitUnRegistration(){ - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) { - int i=0; - linphone_proxy_config_edit(lProxy); - //make sure unregister is sent and authenticated - do{ - linphone_core_iterate(mCore); - ms_usleep(20000); - if (i>100){ - ms_message("tunnel: timeout for unregistration expired, giving up"); - break; - } - i++; - }while(linphone_proxy_config_get_state(lProxy)!=LinphoneRegistrationCleared); - } -} - -void TunnelManager::enable(bool isEnable) { - ms_message("Turning tunnel [%s]",(isEnable?"on":"off")); - if (isEnable && !mEnabled){ - mEnabled=true; - //1 save transport and firewall policy - linphone_core_get_sip_transports(mCore, &mRegularTransport); - mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore); - //2 unregister - waitUnRegistration(); - //3 insert tunnel - start(); - }else if (!isEnable && mEnabled){ - //1 unregister - waitUnRegistration(); - - mEnabled=false; - stopClient(); - - linphone_core_set_rtp_transport_factories(mCore,NULL); - - eXosip_transport_hook_register(NULL); - //Restore transport and firewall policy - linphone_core_set_sip_transports(mCore, &mRegularTransport); - linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy); - //register - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy) { - linphone_proxy_config_done(lProxy); +void TunnelManager::setMode(LinphoneTunnelMode mode) { + if(mMode == mode) return; + if((mode==LinphoneTunnelModeDisable && mState==disabled) + || (mode==LinphoneTunnelModeEnable && mState==ready)) { + return; + } + ms_message("TunnelManager: switching mode from %s to %s", + linphone_tunnel_mode_to_string(mMode), + linphone_tunnel_mode_to_string(mode)); + switch(mode) { + case LinphoneTunnelModeEnable: + if(mState == disabled) { + startClient(); + mState = connecting; + mMode = mode; + } else { + ms_error("TunnelManager: could not change mode. Bad state"); } - + break; + case LinphoneTunnelModeDisable: + if(mState == ready) { + linphone_core_set_rtp_transport_factories(mCore,NULL); + mState = disabled; + mMode = mode; + if(mTunnelizeSipPackets) { + doUnregistration(); + _linphone_core_apply_transports(mCore); + } + sal_set_tunnel(mCore->sal,NULL); + delete mTunnelClient; + mTunnelClient=NULL; + } else { + ms_error("TunnelManager: could not change mode. Bad state"); + } + break; + case LinphoneTunnelModeAuto: + if(mState == disabled || mState == ready) { + if(startAutoDetection()) { + mState = autodetecting; + mMode = mode; + } + } else { + ms_error("TunnelManager: could not change mode. Bad state"); + } + break; + default: + ms_error("TunnelManager::setMode(): invalid mode (%d)", mode); } } @@ -359,8 +274,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; @@ -370,7 +289,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*/ @@ -383,7 +302,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) { @@ -392,30 +311,39 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) { SetLogLevel(TUNNEL_ERROR|TUNNEL_WARN); } } - -bool TunnelManager::isEnabled() { - return mEnabled; + +LinphoneTunnelMode TunnelManager::getMode() const { + return mMode; } void TunnelManager::processUdpMirrorEvent(const Event &ev){ + if(mState != autodetecting) return; if (ev.mData.mHaveUdp) { - LOGI("Tunnel is not required, disabling"); - enable(false); - mAutoDetectStarted = false; + ms_message("TunnelManager: UDP mirror test succeed"); + if(mTunnelClient) { + if(mTunnelizeSipPackets) doUnregistration(); + delete mTunnelClient; + mTunnelClient = NULL; + if(mTunnelizeSipPackets) doRegistration(); + } + mState = disabled; } else { + ms_message("TunnelManager: UDP mirror test failed"); mCurrentUdpMirrorClient++; if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) { - // enable tunnel but also try backup server - LOGI("Tunnel is required, enabling; Trying backup udp mirror"); - + ms_message("TunnelManager: trying another UDP mirror"); UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); } else { - LOGI("Tunnel is required, enabling; no backup udp mirror available"); - mAutoDetectStarted = false; + ms_message("TunnelManager: all UDP mirror tests failed"); + if(mTunnelClient==NULL) { + startClient(); + mState = connecting; + } else { + mState = ready; + } } - enable(true); } } @@ -433,21 +361,37 @@ void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) { thiz->postEvent(ev); } -void TunnelManager::autoDetect() { - // first check if udp mirrors was provisionned +void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) { + TunnelManager *tunnel = bcTunnel(linphone_core_get_tunnel(lc)); + if(reachable && tunnel->getMode() == LinphoneTunnelModeAuto && tunnel->mState != connecting && tunnel->mState != autodetecting) { + tunnel->startAutoDetection(); + tunnel->mState = autodetecting; + } + linphone_core_get_local_ip_for(AF_INET, NULL,tunnel->mLocalAddr); +} + +bool TunnelManager::startAutoDetection() { if (mUdpMirrorClients.empty()) { - LOGE("No UDP mirror server configured aborting auto detection"); - return; + ms_error("TunnelManager: No UDP mirror server configured aborting auto detection"); + return false; } - if (mAutoDetectStarted) { - LOGE("auto detection already in progress, restarting"); - (*mCurrentUdpMirrorClient).stop(); - } - mAutoDetectStarted=true; - mCurrentUdpMirrorClient =mUdpMirrorClients.begin(); + ms_message("TunnelManager: Starting auto-detection"); + mCurrentUdpMirrorClient = mUdpMirrorClients.begin(); UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); - + return true; +} + +bool TunnelManager::isActivated() const{ + switch(getMode()){ + case LinphoneTunnelModeAuto: + return !(mState==disabled); + case LinphoneTunnelModeDisable: + return false; + case LinphoneTunnelModeEnable: + return true; + } + return false; } void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) { @@ -456,6 +400,14 @@ void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd if (mTunnelClient) mTunnelClient->setHttpProxyAuthInfo(username,passwd); } +void TunnelManager::tunnelizeSipPackets(bool enable){ + mTunnelizeSipPackets = enable; +} + +bool TunnelManager::tunnelizeSipPacketsEnabled() const { + return mTunnelizeSipPackets; +} + void TunnelManager::setHttpProxy(const char *host,int port, const char *username, const char *passwd){ mHttpUserName=username?username:""; mHttpPasswd=passwd?passwd:""; @@ -464,6 +416,6 @@ void TunnelManager::setHttpProxy(const char *host,int port, const char *username if (mTunnelClient) mTunnelClient->setHttpProxy(host, port, username, passwd); } -LinphoneCore *TunnelManager::getLinphoneCore(){ +LinphoneCore *TunnelManager::getLinphoneCore() const{ return mCore; } diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index d4c1458fc..f8002ee5d 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -1,7 +1,7 @@ /* * C Implementation: tunnel * - * Description: + * Description: * * * @@ -12,32 +12,35 @@ #define __TUNNEL_CLIENT_MANAGER_H__ #include #include -#include "tunnel/client.hh" +#include +#include #include "linphonecore.h" +#include "linphone_tunnel.h" +#ifndef USE_BELLESIP extern "C" { - #include "eXosip2/eXosip_transport_hook.h" + #include } +#endif + namespace belledonnecomm { -class TunnelClient; -class UdpMirrorClient; /** - * @addtogroup tunnel_client + * @addtogroup tunnel_client * @{ **/ /** - * The TunnelManager class extends the LinphoneCore functionnality in order to provide an easy to use API to + * The TunnelManager class extends the LinphoneCore functionnality in order to provide an easy to use API to * - provision tunnel servers ip addresses and ports * - start/stop the tunneling service - * - be informed of of connection and disconnection events to the tunnel server + * - be informed of connection and disconnection events to the tunnel server * - perform auto-detection whether tunneling is required, based on a test of sending/receiving a flow of UDP packets. - * + * * It takes in charge automatically the SIP registration procedure when connecting or disconnecting to a tunnel server. * No other action on LinphoneCore is required to enable full operation in tunnel mode. **/ - class TunnelManager : public TunnelClientController{ - + class TunnelManager { + public: /** * Add a tunnel server. At least one should be provided to be able to connect. @@ -53,25 +56,13 @@ class UdpMirrorClient; * @param ip tunnel server ip address * @param port tunnel server tls port, recommended value is 443 * @param udpMirrorPort remote port on the tunnel server side used to test udp reachability - * @param delay udp packet round trip delay in ms considered as acceptable. recommanded value is 1000 ms. + * @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms. */ void addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay); /** * Removes all tunnel server address previously entered with addServer() - **/ - void cleanServers(); - /** - * Register a state callback to be notified whenever the tunnel client is connected or disconnected to the tunnel server. - * @param cb application callback function to use for notifying of connection/disconnection events. - * @param userdata An opaque pointer passed to the callback, used optionally by the application to retrieve a context. - **/ - void setCallback(StateCallback cb, void *userdata); - /** - * Start connecting to a tunnel server. - * At this step, nothing is tunneled yet. The enable() method must be used to state whether SIP and RTP traffic - * need to be tunneled or not. **/ - void start(); + void cleanServers(); /** * Forces reconnection to the tunnel server. * This method is useful when the device switches from wifi to Edge/3G or vice versa. In most cases the tunnel client socket @@ -80,22 +71,15 @@ class UdpMirrorClient; **/ void reconnect(); /** - * Sets whether tunneling of SIP and RTP is required. - * @param isEnabled If true enter in tunneled mode, if false exits from tunneled mode. - * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode. - * - **/ - void enable(bool isEnabled); - /** - * In auto detect mode, the tunnel manager try to establish a real time rtp cummunication with the tunnel server on specified port. - *
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 + * @brief setMode + * @param mode */ - void autoDetect(); + void setMode(LinphoneTunnelMode mode); /** - * Returns a boolean indicating whether tunneled operation is enabled. - **/ - bool isEnabled(); + * @brief Return the tunnel mode + * @return #LinphoneTunnelMode + */ + LinphoneTunnelMode getMode() const; /** * Enables debug logs of the Tunnel subsystem. **/ @@ -112,24 +96,61 @@ class UdpMirrorClient; * @param passwd The password. **/ void setHttpProxyAuthInfo(const char* username,const char* passwd); - ~TunnelManager(); + void setHttpProxy(const char *host,int port, const char *username, const char *passwd); + /** + * Indicate to the tunnel manager whether SIP packets must pass + * through the tunnel. That featurte is automatically enabled at + * the creation of the TunnelManager instance. + * @param enable If set to TRUE, SIP packets will pass through the tunnel. + * If set to FALSE, SIP packets will pass by the configured proxies. + */ + void tunnelizeSipPackets(bool enable); + /** + * @brief Check whether the tunnel manager is set to tunnelize SIP packets + * @return True, SIP packets pass through the tunnel + */ + bool tunnelizeSipPacketsEnabled() const; + /** + * @brief Constructor + * @param lc The LinphoneCore instance of which the TunnelManager will be associated to. + */ TunnelManager(LinphoneCore* lc); /** - * Destroy the given RtpTransport. + * @brief Destructor */ - void closeRtpTransport(RtpTransport *t, TunnelSocket *s); - + ~TunnelManager(); /** - * Create an RtpTransport. + * @brief Create an RtpTransport + * @param port + * @return */ RtpTransport *createRtpTransport(int port); - /** - * Get associated Linphone Core. + * @brief Destroy the given RtpTransport + * @param t + * @param s */ - LinphoneCore *getLinphoneCore(); - virtual void setHttpProxy(const char *host,int port, const char *username, const char *passwd); + void closeRtpTransport(RtpTransport *t, TunnelSocket *s); + /** + * @brief Get associated Linphone Core + * @return pointer on the associated LinphoneCore + */ + LinphoneCore *getLinphoneCore() const; + /** + * @brief Check wehter the tunnel is connected + * @return True whether the tunnel is connected + */ + bool isConnected() const; + + bool isActivated() const; private: + enum State { + disabled, + connecting, + ready, + autodetecting + }; + enum EventType{ UdpMirrorClientEvent, TunnelEvent, @@ -142,9 +163,6 @@ class UdpMirrorClient; }mData; }; typedef std::list UdpMirrorClientList; - virtual bool isStarted(); - virtual bool isReady() const; - void onIterate(); static int customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen); static int customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen); static int eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata); @@ -153,32 +171,36 @@ class UdpMirrorClient; static void tunnelCallback(bool connected, TunnelManager *zis); static void sOnIterate(TunnelManager *zis); static void sUdpMirrorClientCallback(bool result, void* data); - void waitUnRegistration(); + static void networkReachableCb(LinphoneCore *lc, bool_t reachable); + + private: + void onIterate(); + void doRegistration(); + void doUnregistration(); + void startClient(); + bool startAutoDetection(); void processTunnelEvent(const Event &ev); void processUdpMirrorEvent(const Event &ev); void postEvent(const Event &ev); + + private: LinphoneCore* mCore; - LCSipTransports mRegularTransport; - TunnelSocket *mSipSocket; - eXosip_transport_hooks_t mExosipTransport; - StateCallback mCallback; - void * mCallbackData; - bool mEnabled; - std::queue mEvq; - std::list mServerAddrs; - UdpMirrorClientList mUdpMirrorClients; - UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + LinphoneTunnelMode mMode; + State mState; + bool mTunnelizeSipPackets; TunnelClient* mTunnelClient; - void stopClient(); - Mutex mMutex; - static Mutex sMutex; - bool mAutoDetectStarted; - LinphoneRtpTransportFactories mTransportFactories; std::string mHttpUserName; std::string mHttpPasswd; std::string mHttpProxyHost; int mHttpProxyPort; - LinphoneFirewallPolicy mPreviousFirewallPolicy; + LinphoneCoreVTable *mVTable; + std::list mServerAddrs; + UdpMirrorClientList mUdpMirrorClients; + UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + LinphoneRtpTransportFactories mTransportFactories; + Mutex mMutex; + std::queue mEvq; + char mLocalAddr[64]; }; /** diff --git a/coreapi/account_creator.c b/coreapi/account_creator.c new file mode 100644 index 000000000..23cdffb28 --- /dev/null +++ b/coreapi/account_creator.c @@ -0,0 +1,325 @@ +/* +linphone +Copyright (C) 2010-2015 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "private.h" + + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreatorCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +static LinphoneAccountCreatorCbs * linphone_account_creator_cbs_new(void) { + return belle_sip_object_new(LinphoneAccountCreatorCbs); +} + +LinphoneAccountCreatorCbs * linphone_account_creator_cbs_ref(LinphoneAccountCreatorCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_account_creator_cbs_unref(LinphoneAccountCreatorCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void *linphone_account_creator_cbs_get_user_data(const LinphoneAccountCreatorCbs *cbs) { + return cbs->user_data; +} + +void linphone_account_creator_cbs_set_user_data(LinphoneAccountCreatorCbs *cbs, void *ud) { + cbs->user_data = ud; +} + +LinphoneAccountCreatorCbsExistenceTestedCb linphone_account_creator_cbs_get_existence_tested(const LinphoneAccountCreatorCbs *cbs) { + return cbs->existence_tested; +} + +void linphone_account_creator_cbs_set_existence_tested(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsExistenceTestedCb cb) { + cbs->existence_tested = cb; +} + +LinphoneAccountCreatorCbsValidationTestedCb linphone_account_creator_cbs_get_validation_tested(const LinphoneAccountCreatorCbs *cbs) { + return cbs->validation_tested; +} + +void linphone_account_creator_cbs_set_validation_tested(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsValidationTestedCb cb) { + cbs->validation_tested = cb; +} + +LinphoneAccountCreatorCbsValidatedCb linphone_account_creator_cbs_get_validated(const LinphoneAccountCreatorCbs *cbs) { + return cbs->validated; +} + +void linphone_account_creator_cbs_set_validated(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsValidatedCb cb) { + cbs->validated = cb; +} + + +static void _linphone_account_creator_destroy(LinphoneAccountCreator *creator) { + linphone_xml_rpc_session_unref(creator->xmlrpc_session); + linphone_account_creator_cbs_unref(creator->callbacks); + if (creator->username) ms_free(creator->username); + if (creator->password) ms_free(creator->password); + if (creator->domain) ms_free(creator->domain); + if (creator->route) ms_free(creator->route); + if (creator->email) ms_free(creator->email); + if (creator->display_name) ms_free(creator->display_name); + ms_free(creator); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreator); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreator, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_account_creator_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + + +LinphoneAccountCreator * linphone_account_creator_new(LinphoneCore *core, const char *xmlrpc_url) { + LinphoneAccountCreator *creator; + creator = belle_sip_object_new(LinphoneAccountCreator); + creator->callbacks = linphone_account_creator_cbs_new(); + creator->core = core; + creator->xmlrpc_session = linphone_xml_rpc_session_new(core, xmlrpc_url); + return creator; +} + +LinphoneAccountCreator * linphone_account_creator_ref(LinphoneAccountCreator *creator) { + belle_sip_object_ref(creator); + return creator; +} + +void linphone_account_creator_unref(LinphoneAccountCreator *creator) { + belle_sip_object_unref(creator); +} + +void *linphone_account_creator_get_user_data(const LinphoneAccountCreator *creator) { + return creator->user_data; +} + +void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, void *ud) { + creator->user_data = ud; +} + +void linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username) { + set_string(&creator->username, username); +} + +const char * linphone_account_creator_get_username(const LinphoneAccountCreator *creator) { + return creator->username; +} + +void linphone_account_creator_set_password(LinphoneAccountCreator *creator, const char *password){ + set_string(&creator->password, password); +} + +const char * linphone_account_creator_get_password(const LinphoneAccountCreator *creator) { + return creator->password; +} + +void linphone_account_creator_set_domain(LinphoneAccountCreator *creator, const char *domain){ + set_string(&creator->domain, domain); +} + +const char * linphone_account_creator_get_domain(const LinphoneAccountCreator *creator) { + return creator->domain; +} + +void linphone_account_creator_set_route(LinphoneAccountCreator *creator, const char *route) { + set_string(&creator->route, route); +} + +const char * linphone_account_creator_get_route(const LinphoneAccountCreator *creator) { + return creator->route; +} + +void linphone_account_creator_set_display_name(LinphoneAccountCreator *creator, const char *display_name) { + set_string(&creator->display_name, display_name); +} + +const char * linphone_account_creator_get_display_name(const LinphoneAccountCreator *creator) { + return creator->display_name; +} + +void linphone_account_creator_set_email(LinphoneAccountCreator *creator, const char *email) { + set_string(&creator->email, email); +} + +const char * linphone_account_creator_get_email(const LinphoneAccountCreator *creator) { + return creator->email; +} + +void linphone_account_creator_enable_newsletter_subscription(LinphoneAccountCreator *creator, bool_t subscribe) { + creator->subscribe_to_newsletter = subscribe; +} + +bool_t linphone_account_creator_newsletter_subscription_enabled(const LinphoneAccountCreator *creator) { + return creator->subscribe_to_newsletter; +} + +LinphoneAccountCreatorCbs * linphone_account_creator_get_callbacks(const LinphoneAccountCreator *creator) { + return creator->callbacks; +} + +static void _test_existence_cb(LinphoneXmlRpcRequest *request) { + LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request); + if (creator->callbacks->existence_tested != NULL) { + LinphoneAccountCreatorStatus status = LinphoneAccountCreatorFailed; + if ((linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) + && (linphone_xml_rpc_request_get_int_response(request) == 0)) { + status = LinphoneAccountCreatorOk; + } + creator->callbacks->existence_tested(creator, status); + } +} + +LinphoneAccountCreatorStatus linphone_account_creator_test_existence(LinphoneAccountCreator *creator) { + LinphoneXmlRpcRequest *request; + char *identity; + + if (!creator->username || !creator->domain) return LinphoneAccountCreatorFailed; + + identity = ms_strdup_printf("%s@%s", creator->username, creator->domain); + request = linphone_xml_rpc_request_new_with_args("check_account", LinphoneXmlRpcArgInt, + LinphoneXmlRpcArgString, identity, + LinphoneXmlRpcArgNone); + linphone_xml_rpc_request_set_user_data(request, creator); + linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _test_existence_cb); + linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request); + linphone_xml_rpc_request_unref(request); + ms_free(identity); + return LinphoneAccountCreatorOk; +} + +static void _test_validation_cb(LinphoneXmlRpcRequest *request) { + LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request); + if (creator->callbacks->validation_tested != NULL) { + LinphoneAccountCreatorStatus status = LinphoneAccountCreatorFailed; + if ((linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) + && (linphone_xml_rpc_request_get_int_response(request) == 1)) { + status = LinphoneAccountCreatorOk; + } + creator->callbacks->validation_tested(creator, status); + } +} + +LinphoneAccountCreatorStatus linphone_account_creator_test_validation(LinphoneAccountCreator *creator) { + LinphoneXmlRpcRequest *request; + char *identity; + + if (!creator->username || !creator->domain) return LinphoneAccountCreatorFailed; + + identity = ms_strdup_printf("%s@%s", creator->username, creator->domain); + request = linphone_xml_rpc_request_new_with_args("check_account_validated", LinphoneXmlRpcArgInt, + LinphoneXmlRpcArgString, identity, + LinphoneXmlRpcArgNone); + linphone_xml_rpc_request_set_user_data(request, creator); + linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _test_validation_cb); + linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request); + linphone_xml_rpc_request_unref(request); + ms_free(identity); + return LinphoneAccountCreatorOk; +} + +static void _validate_cb(LinphoneXmlRpcRequest *request) { + LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request); + if (creator->callbacks->validated != NULL) { + LinphoneAccountCreatorStatus status = LinphoneAccountCreatorFailed; + if ((linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) + && (linphone_xml_rpc_request_get_int_response(request) == 0)) { + status = LinphoneAccountCreatorOk; + } + creator->callbacks->validated(creator, status); + } +} + +LinphoneAccountCreatorStatus linphone_account_creator_validate(LinphoneAccountCreator *creator) { + LinphoneXmlRpcRequest *request; + char *identity; + + if (!creator->username || !creator->domain) return LinphoneAccountCreatorFailed; + + identity = ms_strdup_printf("%s@%s", creator->username, creator->domain); + request = linphone_xml_rpc_request_new_with_args("create_account", LinphoneXmlRpcArgInt, + LinphoneXmlRpcArgString, identity, + LinphoneXmlRpcArgString, creator->password, + LinphoneXmlRpcArgString, creator->email, + LinphoneXmlRpcArgInt, (creator->subscribe_to_newsletter == TRUE) ? 1 : 0, + LinphoneXmlRpcArgNone); + linphone_xml_rpc_request_set_user_data(request, creator); + linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _validate_cb); + linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request); + linphone_xml_rpc_request_unref(request); + ms_free(identity); + return LinphoneAccountCreatorOk; +} + +LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCreator *creator) { + LinphoneAuthInfo *info; + LinphoneProxyConfig *cfg = linphone_core_create_proxy_config(creator->core); + char *identity_str = ms_strdup_printf("sip:%s@%s", creator->username, creator->domain); + LinphoneAddress *identity = linphone_address_new(identity_str); + if (creator->display_name) { + linphone_address_set_display_name(identity, creator->display_name); + } + + linphone_proxy_config_set_identity(cfg, linphone_address_as_string(identity)); + linphone_proxy_config_set_server_addr(cfg, creator->domain); + linphone_proxy_config_set_route(cfg, creator->route); + linphone_proxy_config_enable_publish(cfg, FALSE); + linphone_proxy_config_enable_register(cfg, TRUE); + ms_free(identity_str); + + if (strcmp(creator->domain, "sip.linphone.org") == 0) { + linphone_proxy_config_enable_avpf(cfg, TRUE); + // If account created on sip.linphone.org, we configure linphone to use TLS by default + if (linphone_core_sip_transport_supported(creator->core, LinphoneTransportTls)) { + LinphoneAddress *addr = linphone_address_new(linphone_proxy_config_get_server_addr(cfg)); + char *tmp; + linphone_address_set_transport(addr, LinphoneTransportTls); + tmp = linphone_address_as_string(addr); + linphone_proxy_config_set_server_addr(cfg, tmp); + linphone_proxy_config_set_route(cfg, tmp); + ms_free(tmp); + linphone_address_destroy(addr); + } + linphone_core_set_stun_server(creator->core, "stun.linphone.org"); + linphone_core_set_firewall_policy(creator->core, LinphonePolicyUseIce); + } + + info = linphone_auth_info_new(linphone_address_get_username(identity), NULL, creator->password, NULL, NULL, linphone_address_get_domain(identity)); + linphone_core_add_auth_info(creator->core, info); + linphone_address_destroy(identity); + + if (linphone_core_add_proxy_config(creator->core, cfg) != -1) { + linphone_core_set_default_proxy(creator->core, cfg); + return cfg; + } + + linphone_core_remove_auth_info(creator->core, info); + linphone_proxy_config_unref(cfg); + return NULL; +} diff --git a/coreapi/account_creator.h b/coreapi/account_creator.h new file mode 100644 index 000000000..f2231984a --- /dev/null +++ b/coreapi/account_creator.h @@ -0,0 +1,320 @@ +/* +account_creator.h +Copyright (C) 2010-2015 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 LINPHONE_ACCOUNT_CREATOR_H_ +#define LINPHONE_ACCOUNT_CREATOR_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup misc + * @{ + */ + +/** +* Enum describing the status of a LinphoneAccountCreator operation. +**/ +typedef enum _LinphoneAccountCreatorStatus { + LinphoneAccountCreatorOk, + LinphoneAccountCreatorFailed +} LinphoneAccountCreatorStatus; + +/** + * The LinphoneAccountCreator object used to create an account on a server via XML-RPC. +**/ +typedef struct _LinphoneAccountCreator LinphoneAccountCreator; + +/** + * An object to handle the callbacks for handling the LinphoneAccountCreator operations. +**/ +typedef struct _LinphoneAccountCreatorCbs LinphoneAccountCreatorCbs; + +/** + * Callback used to notify the end of a LinphoneAccountCreator test existence operation. + * @param[in] creator LinphoneAccountCreator object + * @param[in] status The status of the LinphoneAccountCreator test existence operation that has just finished +**/ +typedef void (*LinphoneAccountCreatorCbsExistenceTestedCb)(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status); + +/** + * Callback used to notify the end of a LinphoneAccountCreator test validation operation. + * @param[in] creator LinphoneAccountCreator object + * @param[in] status The status of the LinphoneAccountCreator test validation operation that has just finished +**/ +typedef void (*LinphoneAccountCreatorCbsValidationTestedCb)(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status); + +/** + * Callback used to notify the end of a LinphoneAccountCreator validate operation. + * @param[in] creator LinphoneAccountCreator object + * @param[in] status The status of the LinphoneAccountCreator validate operation that has just finished +**/ +typedef void (*LinphoneAccountCreatorCbsValidatedCb)(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status); + +/** + * Create a LinphoneAccountCreator. + * @param[in] core The LinphoneCore used for the XML-RPC communication + * @param[in] xmlrpc_url The URL to the XML-RPC server + * @return The new LinphoneAccountCreator object +**/ +LINPHONE_PUBLIC LinphoneAccountCreator * linphone_account_creator_new(LinphoneCore *core, const char *xmlrpc_url); + +/** + * Acquire a reference to the LinphoneAccountCreator. + * @param[in] creator LinphoneAccountCreator object. + * @return The same LinphoneAccountCreator object. +**/ +LINPHONE_PUBLIC LinphoneAccountCreator * linphone_account_creator_ref(LinphoneAccountCreator *creator); + +/** + * Release reference to the LinphoneAccountCreator. + * @param[in] creator LinphoneAccountCreator object. +**/ +LINPHONE_PUBLIC void linphone_account_creator_unref(LinphoneAccountCreator *creator); + +/** + * Retrieve the user pointer associated with the LinphoneAccountCreator. + * @param[in] creator LinphoneAccountCreator object. + * @return The user pointer associated with the LinphoneAccountCreator. +**/ +LINPHONE_PUBLIC void *linphone_account_creator_get_user_data(const LinphoneAccountCreator *creator); + +/** + * Assign a user pointer to the LinphoneAccountCreator. + * @param[in] creator LinphoneAccountCreator object. + * @param[in] ud The user pointer to associate with the LinphoneAccountCreator. +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, void *ud); + +/** + * Set the username. + * @param[in] creator LinphoneAccountCreator object + * @param[in] username The username to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username); + +/** + * Get the username. + * @param[in] creator LinphoneAccountCreator object + * @return The username of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_username(const LinphoneAccountCreator *creator); + +/** + * Set the password. + * @param[in] creator LinphoneAccountCreator object + * @param[in] password The password to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_password(LinphoneAccountCreator *creator, const char *password); + +/** + * Get the password. + * @param[in] creator LinphoneAccountCreator object + * @return The password of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_password(const LinphoneAccountCreator *creator); + +/** + * Set the domain. + * @param[in] creator LinphoneAccountCreator object + * @param[in] domain The domain to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_domain(LinphoneAccountCreator *creator, const char *domain); + +/** + * Get the domain. + * @param[in] creator LinphoneAccountCreator object + * @return The domain of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_domain(const LinphoneAccountCreator *creator); + +/** + * Set the route. + * @param[in] creator LinphoneAccountCreator object + * @param[in] route The route to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_route(LinphoneAccountCreator *creator, const char *route); + +/** + * Get the route. + * @param[in] creator LinphoneAccountCreator object + * @return The route of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_route(const LinphoneAccountCreator *creator); + +/** + * Set the email. + * @param[in] creator LinphoneAccountCreator object + * @param[in] display_name The display name to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_display_name(LinphoneAccountCreator *creator, const char *display_name); + +/** + * Get the email. + * @param[in] creator LinphoneAccountCreator object + * @return The display name of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_display_name(const LinphoneAccountCreator *creator); + +/** + * Set the email. + * @param[in] creator LinphoneAccountCreator object + * @param[in] email The email to set +**/ +LINPHONE_PUBLIC void linphone_account_creator_set_email(LinphoneAccountCreator *creator, const char *email); + +/** + * Get the email. + * @param[in] creator LinphoneAccountCreator object + * @return The email of the LinphoneAccountCreator +**/ +LINPHONE_PUBLIC const char * linphone_account_creator_get_email(const LinphoneAccountCreator *creator); + +/** + * Enable the newsletter subscription. + * @param[in] creator LinphoneAccountCreator object + * @param[in] subscribe A boolean telling whether to subscribe to the newsletter or not. +**/ +LINPHONE_PUBLIC void linphone_account_creator_enable_newsletter_subscription(LinphoneAccountCreator *creator, bool_t subscribe); + +/** + * Tell whether to subscribe to the newsletter or not. + * @param[in] creator LinphoneAccountCreator object + * @return A boolean telling whether to subscribe to the newsletter or not. +**/ +LINPHONE_PUBLIC bool_t linphone_account_creator_newsletter_subscription_enabled(const LinphoneAccountCreator *creator); + +/** + * Get the LinphoneAccountCreatorCbs object associated with a LinphoneAccountCreator. + * @param[in] creator LinphoneAccountCreator object + * @return The LinphoneAccountCreatorCbs object associated with the LinphoneAccountCreator. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorCbs * linphone_account_creator_get_callbacks(const LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to test the existence of a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorOk if the request has been sent, LinphoneAccountCreatorFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_test_existence(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to test the validation of a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorOk if the request has been sent, LinphoneAccountCreatorFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_test_validation(LinphoneAccountCreator *creator); + +/** + * Send an XML-RPC request to create a Linphone account. + * @param[in] creator LinphoneAccountCreator object + * @return LinphoneAccountCreatorOk if the request has been sent, LinphoneAccountCreatorFailed otherwise +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_validate(LinphoneAccountCreator *creator); + +/** + * Configure an account (create a proxy config and authentication info for it). + * @param[in] creator LinphoneAccountCreator object + * @return A LinphoneProxyConfig object if successful, NULL otherwise +**/ +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCreator *creator); + + +/** + * Acquire a reference to a LinphoneAccountCreatorCbs object. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @return The same LinphoneAccountCreatorCbs object. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorCbs * linphone_account_creator_cbs_ref(LinphoneAccountCreatorCbs *cbs); + +/** + * Release a reference to a LinphoneAccountCreatorCbs object. + * @param[in] cbs LinphoneAccountCreatorCbs object. +**/ +LINPHONE_PUBLIC void linphone_account_creator_cbs_unref(LinphoneAccountCreatorCbs *cbs); + +/** + * Retrieve the user pointer associated with a LinphoneAccountCreatorCbs object. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @return The user pointer associated with the LinphoneAccountCreatorCbs object. +**/ +LINPHONE_PUBLIC void *linphone_account_creator_cbs_get_user_data(const LinphoneAccountCreatorCbs *cbs); + +/** + * Assign a user pointer to a LinphoneAccountCreatorCbs object. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @param[in] ud The user pointer to associate with the LinphoneAccountCreatorCbs object. +**/ +LINPHONE_PUBLIC void linphone_account_creator_cbs_set_user_data(LinphoneAccountCreatorCbs *cbs, void *ud); + +/** + * Get the existence tested callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @return The current existence tested callback. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorCbsExistenceTestedCb linphone_account_creator_cbs_get_existence_tested(const LinphoneAccountCreatorCbs *cbs); + +/** + * Set the existence tested callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @param[in] cb The existence tested callback to be used. +**/ +LINPHONE_PUBLIC void linphone_account_creator_cbs_set_existence_tested(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsExistenceTestedCb cb); + +/** + * Get the validation tested callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @return The current validation tested callback. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorCbsValidationTestedCb linphone_account_creator_cbs_get_validation_tested(const LinphoneAccountCreatorCbs *cbs); + +/** + * Set the validation tested callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @param[in] cb The validation tested callback to be used. +**/ +LINPHONE_PUBLIC void linphone_account_creator_cbs_set_validation_tested(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsValidationTestedCb cb); + +/** + * Get the validated callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @return The current validated callback. +**/ +LINPHONE_PUBLIC LinphoneAccountCreatorCbsValidatedCb linphone_account_creator_cbs_get_validated(const LinphoneAccountCreatorCbs *cbs); + +/** + * Set the validated callback. + * @param[in] cbs LinphoneAccountCreatorCbs object. + * @param[in] cb The validated callback to be used. +**/ +LINPHONE_PUBLIC void linphone_account_creator_cbs_set_validated(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsValidatedCb cb); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONE_ACCOUNT_CREATOR_H_ */ diff --git a/coreapi/address.c b/coreapi/address.c index ad07819bc..1299a5351 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,36 @@ 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) + * @deprecated use linphone_address_get_secure() +**/ +bool_t linphone_address_is_secure(const LinphoneAddress *uri){ + return sal_address_is_secure(uri); +} + +/** + * Returns true if address refers to a secure location (sips) +**/ +bool_t linphone_address_get_secure(const LinphoneAddress *uri){ + return sal_address_is_secure(uri); +} + +/** + * Make the address refer to a secure location (sips scheme) + * @param enabled TRUE if address is requested to be secure. +**/ +void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled){ + sal_address_set_secure(addr, enabled); +} + +/** + * returns true if address is a routable sip address + */ +bool_t linphone_address_is_sip(const LinphoneAddress *uri){ + return sal_address_is_sip(uri); +} + static bool_t strings_equals(const char *s1, const char *s2){ if (s1==NULL && s2==NULL) return TRUE; if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE; @@ -137,7 +190,10 @@ static bool_t strings_equals(const char *s1, const char *s2){ /** * Compare two LinphoneAddress ignoring tags and headers, basically just domain, username, and port. - * Returns TRUE if they are equal. + * @param[in] a1 LinphoneAddress object + * @param[in] a2 LinphoneAddress object + * @return Boolean value telling if the LinphoneAddress objects are equal. + * @see linphone_address_equal() **/ bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2){ const char *u1,*u2; @@ -145,26 +201,86 @@ 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. + * Compare two LinphoneAddress taking the tags and headers into account. + * @param[in] a1 LinphoneAddress object + * @param[in] a2 LinphoneAddress object + * @return Boolean value telling if the LinphoneAddress objects are equal. + * @see linphone_address_weak_equal() + */ +bool_t linphone_address_equal(const LinphoneAddress *a1, const LinphoneAddress *a2) { + char *s1; + char *s2; + bool_t res; + if ((a1 == NULL) && (a2 == NULL)) return TRUE; + if ((a1 == NULL) || (a2 == NULL)) return FALSE; + s1 = linphone_address_as_string(a1); + s2 = linphone_address_as_string(a2); + res = (strcmp(s1, s2) == 0) ? TRUE : FALSE; + ms_free(s1); + ms_free(s2); + return res; +} + +/** + * Destroys a LinphoneAddress object (actually calls linphone_address_unref()). + * @deprecated Use linphone_address_unref() instead **/ 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); } +/** + * Set the password encoded in the address. + * It is used for basic authentication (not recommended). + * @param addr the LinphoneAddress + * @param passwd the password to set. +**/ +void linphone_address_set_password(LinphoneAddress *addr, const char *passwd){ + sal_address_set_password(addr,passwd); +} + +/** + * Get the password encoded in the address. + * It is used for basic authentication (not recommended). + * @param addr the address + * @return the password, if any, NULL otherwise. +**/ +const char *linphone_address_get_password(const LinphoneAddress *addr){ + return sal_address_get_password(addr); +} + +/** + * Set a header into the address. + * Headers appear in the URI with '?', such as . + * @param addr the address + * @param header_name the header name + * @param header_value the header value +**/ +void linphone_address_set_header(LinphoneAddress *addr, const char *header_name, const char *header_value){ + sal_address_set_header(addr,header_name,header_value); +} + +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 4b5d10fa8..f0f5eec2e 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #include "linphonecore.h" #include "private.h" #include "lpconfig.h" @@ -31,47 +31,32 @@ * @{ **/ -/** - * 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. -**/ -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); - obj->works=FALSE; + if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); return obj; } -static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ +LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1); if (ai->username) obj->username=ms_strdup(ai->username); if (ai->userid) obj->userid=ms_strdup(ai->userid); 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); - obj->works=FALSE; - obj->usecount=0; + if (ai->domain) obj->domain=ms_strdup(ai->domain); return obj; } -/** - * Returns username. -**/ const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i){ return i->username; } -/** - * Returns password. -**/ const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i){ return i->passwd; } @@ -80,9 +65,18 @@ const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){ return i->userid; } -/** - * Sets the password. -**/ +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; +} + void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd){ if (info->passwd!=NULL) { ms_free(info->passwd); @@ -91,9 +85,6 @@ void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd){ if (passwd!=NULL && (strlen(passwd)>0)) info->passwd=ms_strdup(passwd); } -/** - * Sets the username. -**/ void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username){ if (info->username){ ms_free(info->username); @@ -102,9 +93,6 @@ void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *usernam if (username && strlen(username)>0) info->username=ms_strdup(username); } -/** - * Sets userid. -**/ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){ if (info->userid){ ms_free(info->userid); @@ -113,6 +101,30 @@ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){ if (userid && strlen(userid)>0) info->userid=ms_strdup(userid); } +void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm){ + if (info->realm){ + ms_free(info->realm); + info->realm=NULL; + } + if (realm && strlen(realm)>0) info->realm=ms_strdup(realm); +} + +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); +} + +void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1){ + if (info->ha1){ + ms_free(info->ha1); + info->ha1=NULL; + } + if (ha1 && strlen(ha1)>0) info->ha1=ms_strdup(ha1); +} + /** * Destroys a LinphoneAuthInfo object. **/ @@ -122,6 +134,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); } @@ -130,50 +143,53 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in char key[50]; sprintf(key,"auth_info_%i",pos); lp_config_clean_section(config,key); - + 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)){ return NULL; } - + username=lp_config_get_string(config,key,"username",NULL); userid=lp_config_get_string(config,key,"userid",NULL); 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){ @@ -184,7 +200,7 @@ static char * remove_quotes(char * input){ return input; } -static int realm_match(const char *realm1, const char *realm2){ +static bool_t realm_match(const char *realm1, const char *realm2){ if (realm1==NULL && realm2==NULL) return TRUE; if (realm1!=NULL && realm2!=NULL){ if (strcmp(realm1,realm2)==0) return TRUE; @@ -202,41 +218,63 @@ 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 && realm_match(realm,pinfo->realm) + && 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 && pinfo->ha1==NULL) { + return pinfo; + } else if (!domain && pinfo->ha1==NULL) { + return pinfo; } } } - if (ret==NULL && candidate!=NULL) - ret=candidate; return ret; } +/** + * Find authentication info matching realm, username, domain criteria. + * 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); + } + /*if (ai) ms_message("linphone_core_find_auth_info(): returning auth info username=%s, realm=%s", ai->username, ai->realm);*/ + return ai; +} + static void write_auth_infos(LinphoneCore *lc){ MSList *elem; int i; @@ -249,43 +287,73 @@ 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. - * - * This information will be used during all SIP transacations that require authentication. + * + * This information will be used during all SIP transactions that require authentication. **/ -void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) -{ +void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){ LinphoneAuthInfo *ai; MSList *elem; MSList *l; - + int restarted_op_count=0; + bool_t updating=FALSE; + + if (info->ha1==NULL && info->passwd==NULL){ + ms_error("linphone_core_add_auth_info(): info supplied with empty password or ha1."); + return; + } /* find if we are attempting to modify an existing auth info */ - ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); - 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); + updating=TRUE; } lc->auth_info=ms_list_append(lc->auth_info,linphone_auth_info_clone(info)); + /* retry pending authentication operations */ for(l=elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){ - 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++; + restarted_op_count++; } } + if (l){ + ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n" + "\tusername: [%s]\n" + "\trealm [%s]\n" + "\tdomain [%s]\n", + restarted_op_count, + updating ? "updating" : "adding", + info->username ? info->username : "", + info->realm ? info->realm : "", + info->domain ? info->domain : ""); + } ms_list_free(l); - write_auth_infos(lc); + if(lc->sip_conf.save_auth_info) write_auth_infos(lc); } @@ -301,17 +369,18 @@ 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);*/ linphone_auth_info_destroy(r); - write_auth_infos(lc); + if(lc->sip_conf.save_auth_info) write_auth_infos(lc); } } /** * Returns an unmodifiable list of currently entered LinphoneAuthInfo. + * @param[in] lc The LinphoneCore object + * @return \mslist{LinphoneAuthInfo} **/ const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc){ return lc->auth_info; diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c new file mode 100644 index 000000000..2546e7850 --- /dev/null +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -0,0 +1,238 @@ +/* +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); + belle_generic_uri_t* generic_uri = belle_sip_header_address_get_absolute_uri(header_addr); + if (uri) { + if (belle_sip_uri_is_secure(uri)) return "sips"; + else return "sip"; + } else if (generic_uri) + return belle_generic_uri_get_scheme(generic_uri); + else + return NULL; +} + +void sal_address_set_secure(SalAddress *addr, bool_t enabled){ + 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_uri_set_secure(uri,enabled); +} + +bool_t sal_address_is_secure(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) return belle_sip_uri_is_secure(uri); + 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_password(SalAddress *addr, const char *passwd){ + SAL_ADDRESS_SET(addr,user_password,passwd); +} + +const char* sal_address_get_password(const SalAddress *addr){ + SAL_ADDRESS_GET(addr,user_password); +} + +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_uri_headers_clean(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); +} + +bool_t sal_address_is_sip(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + return belle_sip_header_address_get_uri(header_addr) != NULL; +} + +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* sip_uri = belle_sip_header_address_get_uri(header_addr); + belle_generic_uri_t* absolute_uri = belle_sip_header_address_get_absolute_uri(header_addr); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_t* uri; + + if (sip_uri) { + uri=(belle_sip_object_t*)sip_uri; + } else if (absolute_uri) { + uri=(belle_sip_object_t*)absolute_uri; + } else { + ms_error("Cannot generate string for addr [%p] with null uri",addr); + return NULL; + } + belle_sip_object_marshal(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_params(SalAddress *addr, const char *params){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); + belle_sip_parameters_set(parameters,params); +} + +void sal_address_set_uri_params(SalAddress *addr, const char *params){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))); + belle_sip_parameters_set(parameters,params); +} + +void sal_address_set_header(SalAddress *addr, const char *header_name, const char *header_value){ + belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)),header_name, header_value); +} + +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)); +} + +bool_t sal_address_is_ipv6(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){ + const char *host=belle_sip_uri_get_host(uri); + if (host && strchr(host,':')!=NULL) + return TRUE; + } + return FALSE; +} + +void sal_address_destroy(SalAddress *addr){ + sal_address_unref(addr); +} + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c new file mode 100644 index 000000000..6e3a6cba9 --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.c @@ -0,0 +1,1184 @@ +/* +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_log(){ + sal_set_log_level(ORTP_MESSAGE); +} + +void sal_disable_log() { + sal_set_log_level(ORTP_ERROR); +} + +void sal_set_log_level(OrtpLogLevel level) { + belle_sip_log_level belle_sip_level; + if ((level&ORTP_FATAL) != 0) { + belle_sip_level = BELLE_SIP_LOG_FATAL; + } else if ((level&ORTP_ERROR) != 0) { + belle_sip_level = BELLE_SIP_LOG_ERROR; + } else if ((level&ORTP_WARNING) != 0) { + belle_sip_level = BELLE_SIP_LOG_WARNING; + } else if ((level&ORTP_MESSAGE) != 0) { + belle_sip_level = BELLE_SIP_LOG_MESSAGE; + } else if (((level&ORTP_DEBUG) != 0) || ((level&ORTP_TRACE) != 0)) { + belle_sip_level = BELLE_SIP_LOG_DEBUG; + } else { + //well, this should never occurs but... + belle_sip_level = BELLE_SIP_LOG_MESSAGE; + } + belle_sip_set_log_level(belle_sip_level); +} + +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,op); + op->has_auth_pending=TRUE; + } +} + +void sal_remove_pending_auth(Sal *sal, SalOp *op){ + if (op->has_auth_pending){ + op->has_auth_pending=FALSE; + if (ms_list_find(sal->pending_auths,op)){ + sal->pending_auths=ms_list_remove(sal->pending_auths,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); + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t); + belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); + + if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){ + /*prefer using the from from the SalOp*/ + from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op)); + } + + if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { + new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); + if (!new_request) + 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,from_uri,&auth_list,op->base.realm)) { + 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 { + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t); + char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + ms_message("No auth info found for [%s]",tmp); + belle_sip_free(tmp); + sal_add_pending_auth(op->base.root,op); + + if (is_within_dialog) { + belle_sip_object_unref(new_request); + } + } + /*always store auth info, for case of wrong credential*/ + if (op->auth_info) { + sal_auth_info_delete(op->auth_info); + op->auth_info=NULL; + } + if (auth_list){ + auth_event=(belle_sip_auth_event_t*)(auth_list->data); + op->auth_info=sal_auth_info_create(auth_event); + belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); + } +} + +static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ + belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event); + SalOp* op = belle_sip_dialog_get_application_data(dialog); + if (op && op->callbacks && 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)); + /*also reset auth count on IO error*/ + op->auth_requests=0; + if (op->callbacks && op->callbacks->process_io_error) { + op->callbacks->process_io_error(op,event); + } + } else { + /*ms_error("sal process_io_error not implemented yet for non transaction");*/ + /*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=NULL; + 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); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + + 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,405); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp) + ,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO"))); + belle_sip_provider_send_response(sal->prov,resp); + return; + } + + if (!op->base.from_address) { + if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))) + 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))); + else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header)))) + address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + else + ms_error("Cannot not find from uri from request [%p]",req); + sal_op_set_from_address(op,(SalAddress*)address); + belle_sip_object_unref(address); + } + + if( remote_contact ){ + __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } + + if (!op->base.to_address) { + to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); + if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))) + 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))); + else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to)))) + address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) + ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to))); + else + ms_error("Cannot not find to uri from request [%p]",req); + + 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 && 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)); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t); + + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } + /*do it all the time, since we can receive provisional responses from a different instance than the final one*/ + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); + + if(remote_contact) { + __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } + + if (!op->base.call_id) { + op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); + } + + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); + + if (op->callbacks && op->callbacks->process_response_event) { + /*handle authorization*/ + switch (response_code) { + case 200: + break; + case 401: + case 407: + 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; + } + if (++op->auth_requests > 2) { + ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op) + ,sal_op_get_to(op)); + op->base.root->callbacks.auth_failure(op,op->auth_info); + sal_remove_pending_auth(op->base.root,op); + } else { + op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); + sal_process_authentication(op); + return; + } + } + break; + case 403: + if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info); + break; + } + if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) { + /*not an auth request*/ + op->auth_requests=0; + } + op->callbacks->process_response_event(op,event); + } else { + ms_error("Unhandled event response [%p]",event); + } + } +} + +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 && 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 && op->callbacks->process_transaction_terminated) { + op->callbacks->process_transaction_terminated(op,event); + } else { + ms_message("Unhandled transaction terminated [%p]",trans); + } + if (op) sal_op_unref(op); /*because every 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); + + /*belle_sip_object_enable_marshal_check(TRUE);*/ + sal->auto_contacts=TRUE; + + /*first create the stack, which initializes the belle-sip object's pool for this thread*/ + belle_sip_set_log_handler(_belle_sip_log); + sal->stack = belle_sip_stack_new(NULL); + + sal->user_agent=belle_sip_header_user_agent_new(); +#if defined(PACKAGE_NAME) && defined(LIBLINPHONE_VERSION) + belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LIBLINPHONE_VERSION); +#endif + sal_append_stack_string_to_user_agent(sal); + belle_sip_object_ref(sal->user_agent); + + 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*/ + sal->enable_sip_update=TRUE; + sal->pending_trans_checking=TRUE; + 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.is_composing_received==NULL) + ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub; + if (ctx->callbacks.ping_reply==NULL) + ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; + if (ctx->callbacks.auth_requested==NULL) + 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->supported) belle_sip_object_unref(sal->supported); + ms_list_free_with_data(sal->supported_tags,ms_free); + 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; +} + +static int sal_add_listen_port(Sal *ctx, SalAddress* addr, bool_t is_tunneled){ + int result; + belle_sip_listening_point_t* lp; + if (is_tunneled){ +#ifdef TUNNEL_ENABLED + if (sal_address_get_transport(addr)!=SalTransportUDP){ + ms_error("Tunneled mode is only available for UDP kind of transports."); + return -1; + } + lp = belle_sip_tunnel_listening_point_new(ctx->stack, ctx->tunnel_client); + if (!lp){ + ms_error("Could not create tunnel listening point."); + return -1; + } +#else + ms_error("No tunnel support in library."); + return -1; +#endif + }else{ + 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); + if (sal_address_get_transport(addr)==SalTransportTLS) set_tls_properties(ctx); + } else { + return -1; + } + return result; +} + +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_tunneled) { + 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, is_tunneled); + sal_address_destroy(sal_addr); + return result; +} + +static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { + belle_sip_provider_remove_listening_point(prov,lp); +} + +int sal_get_listening_port(Sal *ctx, SalTransport tr){ + const char *tpn=sal_transport_to_string(tr); + belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn); + if (lp){ + return belle_sip_listening_point_get_port(lp); + } + return 0; +} + +int sal_unlisten_ports(Sal *ctx){ + const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); + belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); + belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); + belle_sip_list_free(tmp_list); + ms_message("sal_unlisten_ports done"); + return 0; +} + +ortp_socket_t sal_get_socket(Sal *ctx){ + ms_warning("sal_get_socket is deprecated"); + return -1; +} + +void sal_set_user_agent(Sal *ctx, const char *user_agent){ + belle_sip_header_user_agent_set_products(ctx->user_agent,NULL); + belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent); + return ; +} + +const char* sal_get_user_agent(Sal *ctx){ + static char user_agent[255]; + belle_sip_header_user_agent_get_products_as_string(ctx->user_agent, user_agent, 254); + return user_agent; +} + +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); + } + } +} +int sal_set_tunnel(Sal *ctx, void *tunnelclient) { +#ifdef TUNNEL_ENABLED + ctx->tunnel_client=tunnelclient; + return 0; +#else + return -1; +#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_set_transport_timeout(Sal* sal,int timeout) { + belle_sip_stack_set_transport_timeout(sal->stack, timeout); +} +int sal_get_transport_timeout(const Sal* sal) { + return belle_sip_stack_get_transport_timeout(sal->stack); +} +void sal_enable_dns_srv(Sal *sal, bool_t enable) { + belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable); +} +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; + + if (msg==NULL){ + msg=(belle_sip_message_t*)belle_sip_request_new(); + belle_sip_object_ref(msg); + } + h=belle_sip_header_create(name,value); + if (h==NULL){ + belle_sip_error("Fail to parse custom 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){ + 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){ + ms_free(sal->uuid); + sal->uuid=NULL; + } + if (uuid) + sal->uuid=ms_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; +} + +static void make_supported_header(Sal *sal){ + MSList *it; + char *alltags=NULL; + size_t buflen=64; + size_t written=0; + + if (sal->supported){ + belle_sip_object_unref(sal->supported); + sal->supported=NULL; + } + for(it=sal->supported_tags;it!=NULL;it=it->next){ + const char *tag=(const char*)it->data; + size_t taglen=strlen(tag); + if (alltags==NULL || (written+taglen+1>=buflen)) alltags=ms_realloc(alltags,(buflen=buflen*2)); + snprintf(alltags+written,buflen-written,it->next ? "%s, " : "%s",tag); + } + if (alltags){ + sal->supported=belle_sip_header_create("Supported",alltags); + if (sal->supported){ + belle_sip_object_ref(sal->supported); + } + ms_free(alltags); + } +} + +void sal_set_supported_tags(Sal *ctx, const char* tags){ + ctx->supported_tags=ms_list_free_with_data(ctx->supported_tags,ms_free); + if (tags){ + char *iter; + char *buffer=ms_strdup(tags); + char *tag; + char *context=NULL; + iter=buffer; + while((tag=strtok_r(iter,", ",&context))!=NULL){ + iter=NULL; + ctx->supported_tags=ms_list_append(ctx->supported_tags,ms_strdup(tag)); + } + ms_free(buffer); + } + make_supported_header(ctx); +} + +const char *sal_get_supported_tags(Sal *ctx){ + if (ctx->supported){ + return belle_sip_header_get_unparsed_value(ctx->supported); + } + return NULL; +} + +void sal_add_supported_tag(Sal *ctx, const char* tag){ + MSList *elem=ms_list_find_custom(ctx->supported_tags,(MSCompareFunc)strcasecmp,tag); + if (!elem){ + ctx->supported_tags=ms_list_append(ctx->supported_tags,ms_strdup(tag)); + make_supported_header(ctx); + } + +} + +void sal_remove_supported_tag(Sal *ctx, const char* tag){ + MSList *elem=ms_list_find_custom(ctx->supported_tags,(MSCompareFunc)strcasecmp,tag); + if (elem){ + ms_free(elem->data); + ctx->supported_tags=ms_list_remove_link(ctx->supported_tags,elem); + make_supported_header(ctx); + } +} + + + +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->supported); + 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; +} + +void sal_use_no_initial_route(Sal *ctx, bool_t enabled){ + ctx->no_initial_route=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); +} + +/** + * Parse a directory to get a certificate with the given subject common name + * + */ +void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) { + belle_sip_certificates_chain_t *certificate = NULL; + belle_sip_signing_key_t *key = NULL; + *certificate_pem = NULL; + *key_pem = NULL; + if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) { + *certificate_pem = belle_sip_certificates_chain_get_pem(certificate); + *key_pem = belle_sip_signing_key_get_pem(key); + ms_message("Retrieve certificate with CN=%s successful\n", subject); + } else { + if (generate_certificate == TRUE) { + if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) { + *certificate_pem = belle_sip_certificates_chain_get_pem(certificate); + *key_pem = belle_sip_signing_key_get_pem(key); + ms_message("Generate self-signed certificate with CN=%s successful\n", subject); + } + } + } + /* generate the fingerprint as described in RFC4572 if needed */ + if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) { + if (*fingerprint != NULL) { + ms_free(*fingerprint); + } + *fingerprint = belle_sip_certificates_chain_get_fingerprint(certificate); + } + + /* free key and certificate */ + if ( certificate != NULL ) { + belle_sip_object_unref(certificate); + } + if ( key != NULL ) { + belle_sip_object_unref(key); + } +} + +unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ + return belle_sip_random_bytes(ret,size); +} + +char *sal_get_random_token(int size){ + return belle_sip_random_token(ms_malloc(size),size); +} + +unsigned int sal_get_random(void){ + unsigned int ret=0; + belle_sip_random_bytes((unsigned char*)&ret,4); + return ret; +} + +belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); + return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); +} + +void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); + belle_sip_main_loop_remove_source(ml, timer); +} + +unsigned long sal_begin_background_task(const char *name, void (*max_time_reached)(void *), void *data){ + return belle_sip_begin_background_task(name, max_time_reached, data); +} + +void sal_end_background_task(unsigned long id){ + belle_sip_end_background_task(id); +} + + +void sal_enable_sip_update_method(Sal *ctx,bool_t value) { + ctx->enable_sip_update=value; +} + +void sal_default_set_sdp_handling(Sal *sal, SalOpSDPHandling sdp_handling_method) { + if (sdp_handling_method != SalOpSDPNormal ) ms_message("Enabling special SDP handling for all new SalOp in Sal[%p]!", sal); + sal->default_sdp_handling = sdp_handling_method; +} + +bool_t sal_pending_trans_checking_enabled(const Sal *sal) { + return sal->pending_trans_checking; +} + +int sal_enable_pending_trans_checking(Sal *sal, bool_t value) { + sal->pending_trans_checking = value; + return 0; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h new file mode 100644 index 000000000..b75be9156 --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.h @@ -0,0 +1,175 @@ +/* +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 *tunnel_client; + 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*/ + MSList *supported_tags;/*list of char * */ + belle_sip_header_t *supported; + bool_t one_matching_codec; + bool_t use_tcp_tls_keep_alive; + bool_t nat_helper_enabled; + bool_t tls_verify; + bool_t tls_verify_cn; + bool_t use_dates; + bool_t auto_contacts; + bool_t enable_test_features; + bool_t no_initial_route; + bool_t enable_sip_update; /*true by default*/ + SalOpSDPHandling default_sdp_handling; + bool_t pending_trans_checking; /*testing purpose*/ +}; + +typedef enum SalOpState { + SalOpStateEarly=0 + ,SalOpStateActive + ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ + ,SalOpStateTerminated +}SalOpState; + +const char* sal_op_state_to_string(SalOpState value); + +typedef enum SalOpDir { + SalOpDirIncoming=0 + ,SalOpDirOutgoing +}SalOpDir; +typedef enum SalOpType { + SalOpUnknown, + SalOpRegister, + SalOpCall, + SalOpMessage, + SalOpPresence, + SalOpPublish, + SalOpSubscribe +}SalOpType; + +const char* sal_op_type_to_string(SalOpType type); + +struct SalOp{ + SalOpBase base; + const belle_sip_listener_callbacks_t *callbacks; + SalErrorInfo error_info; + belle_sip_client_transaction_t *pending_auth_transaction; + belle_sip_server_transaction_t* pending_server_trans; + belle_sip_server_transaction_t* pending_update_server_trans; + belle_sip_client_transaction_t* pending_client_trans; + SalAuthInfo* auth_info; + belle_sip_dialog_t* dialog; + belle_sip_header_replaces_t *replaces; + belle_sip_header_referred_by_t *referred_by; + SalMediaDescription *result; + belle_sdp_session_description_t *sdp_answer; + SalOpState state; + SalOpDir dir; + belle_sip_refresher_t* refresher; + int ref; + SalOpType type; + SalPrivacyMask privacy; + belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/ + SalOpSDPHandling sdp_handling; + int auth_requests; /*number of auth requested for this op*/ + bool_t cnx_ip_to_0000_if_sendonly_enabled; + bool_t auto_answer_asked; + bool_t sdp_offering; + bool_t call_released; + bool_t manual_refresher; + bool_t has_auth_pending; + bool_t supports_session_timers; +}; + + +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, SalReason* sal_reason, char* reason, size_t reason_size); +SalReason _sal_reason_from_sip_code(int code); + +void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response); +/*presence*/ +void sal_op_presence_fill_cbs(SalOp*op); +/*messaging*/ +void sal_op_message_fill_cbs(SalOp*op); +void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event); +void sal_op_subscribe_fill_cbs(SalOp*op); + +/*call transfer*/ +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); + +void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg); + +#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..5474540ea --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -0,0 +1,1042 @@ +/* +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" + +static int extract_sdp(SalOp* op,belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); + +/*used for calls terminated before creation of a dialog*/ +static void call_set_released(SalOp* op){ + if (!op->call_released){ + op->state=SalOpStateTerminated; + op->base.root->callbacks.call_released(op); + op->call_released=TRUE; + /*be aware that the following line may destroy the op*/ + set_or_update_dialog(op,NULL); + } +} + +static void call_set_error(SalOp* op,belle_sip_response_t* response){ + sal_op_set_error_info_from_response(op,response); + op->base.root->callbacks.call_failure(op); +} +static void set_addr_to_0000(char value[]) { + if (ms_is_ipv6(value)) { + strcpy(value,"::0"); + } else { + strcpy(value,"0.0.0.0"); + } + return; +} +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 = NULL; + } + + /* if SDP was invalid */ + if (h->base.remote_media == NULL) return; + + 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); + /*for backward compatibility purpose*/ + if(h->cnx_ip_to_0000_if_sendonly_enabled && sal_media_description_has_dir(h->result,SalStreamSendOnly)) { + set_addr_to_0000(h->result->addr); + for(i=0;iresult->nb_streams;++i){ + if (h->result->streams[i].dir == SalStreamSendOnly) + set_addr_to_0000(h->result->streams[i].rtp_addr); + set_addr_to_0000(h->result->streams[i].rtcp_addr); + } + } + 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->nb_streams;++i){ + /*copy back parameters from remote description that we need in our result description*/ + if (h->result->streams[i].rtp_port!=0){ /*if stream was accepted*/ + 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 == SalProtoRtpSavpf) || (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_BUFFER_OVERFLOW; + size_t length = 0; + + if (session_desc) { + size_t bufLen = 2048; + size_t hardlimit = 16*1024; /* 16k SDP limit seems reasonable */ + char* buff = belle_sip_malloc(bufLen); + content_type = belle_sip_header_content_type_create("application","sdp"); + + /* try to marshal the description. This could go higher than 2k so we iterate */ + while( error != BELLE_SIP_OK && bufLen <= hardlimit && buff != NULL){ + error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length); + if( error != BELLE_SIP_OK ){ + bufLen *= 2; + length = 0; + buff = belle_sip_realloc(buff,bufLen); + } + } + /* give up if hard limit reached */ + if (error != BELLE_SIP_OK || buff == NULL) { + ms_error("Buffer too small (%d) or not enough memory, giving up SDP", (int)bufLen); + 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_assign_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*/ + sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL); + op->base.root->callbacks.call_failure(op); + call_set_released(op); + } else { + /*dialog will terminated shortly, nothing to do*/ + } +} +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 + , 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; + SalReason reason; + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=NULL; + } + if (extract_sdp(op,BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { + if (sdp){ + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + }/*if no sdp in response, what can we do ?*/ + } + /* process sdp in any case to reset result media description*/ + 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 int vfu_retry (void *user_data, unsigned int events) { + SalOp *op=(SalOp *)user_data; + sal_call_send_vfu_request(op); + sal_op_unref(op); + return BELLE_SIP_STOP; +} + +static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + belle_sip_request_t* ack; + 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); + belle_sip_header_content_type_t *header_content_type=NULL; + belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event); + const char *method; + + 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,dialog); + dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; + method=belle_sip_request_get_method(req); + ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state)); + /*to make sure no cb will destroy op*/ + sal_op_ref(op); + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: { + if (strcmp("INVITE",method)==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<200) { + belle_sip_response_t *prev_response=belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response"); + if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_ringing(op); + } + belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); + } else if (code>=300){ + call_set_error(op,response); + if (op->dialog==NULL) call_set_released(op); + } + } else if (code >=200 + && code<300 + && strcmp("UPDATE",belle_sip_request_get_method(req))==0) { + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_accepted(op); + } + } + break; + case BELLE_SIP_DIALOG_CONFIRMED: { + switch (op->state) { + case SalOpStateEarly:/*invite case*/ + case SalOpStateActive: /*re-invite, INFO, UPDATE case*/ + if (strcmp("INVITE",method)==0){ + if (code >=200 && code<300) { + 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){ + call_set_error(op,response); + } + }else if (strcmp("INFO",method)==0){ + if (code == 491 + && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) + && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 + && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { + unsigned int retry_in =1000*((float)rand()/RAND_MAX); + belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry"); + ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); + belle_sip_object_unref(s); + }else { + /*ignoring*/ + } + }else if (strcmp("UPDATE",method)==0){ + op->base.root->callbacks.call_accepted(op); /*INVITE*/ + } + 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 (strcmp("INVITE",method)==0 && code >= 300){ + call_set_error(op,response); + } + } + break; + default: { + ms_error("call op [%p] receive answer [%i] not implemented",op,code); + } + break; + } + sal_op_unref(op); +} + +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*/ + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + op->base.root->callbacks.call_failure(op); + call_set_released(op); + } else { + /*dialog will terminated shortly, nothing to do*/ + } +} + +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; + bool_t release_call=FALSE; + + 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)) + && op->dialog==NULL) { + release_call=TRUE; + } + if (server_transaction){ + if (op->pending_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=NULL; + } + if (op->pending_update_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_update_server_trans); + op->pending_update_server_trans=NULL; + } + } + if (release_call) 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,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; +} + +/* + * Extract the sdp from a sip message. + * If there is no body in the message, the session_desc is set to null, 0 is returned. + * If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately. + * +**/ +static int extract_sdp(SalOp *op, belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { + const char *body; + belle_sip_header_content_type_t* content_type; + + if (op&&op->sdp_handling == SalOpSDPSimulateError){ + ms_error("Simulating SDP parsing error for op %p", op); + *session_desc=NULL; + *error=SalReasonNotAcceptable; + return -1; + } else if( op && op->sdp_handling == SalOpSDPSimulateRemove){ + ms_error("Simulating no SDP for op %p", op); + *session_desc = NULL; + return 0; + } + + body = belle_sip_message_get_body(message); + if(body == NULL) { + *session_desc = NULL; + return 0; + } + + content_type = belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t); + if (content_type){ + if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) { + *session_desc=belle_sdp_session_description_parse(body); + if (*session_desc==NULL) { + ms_error("Failed to parse SDP message."); + *error=SalReasonNotAcceptable; + return -1; + } + }else{ + *error=SalReasonUnsupportedContent; + return -1; + } + }else *session_desc=NULL; + return 0; +} + +static int is_media_description_acceptable(SalMediaDescription *md){ + if (md->nb_streams==0){ + ms_warning("Media description does not define any stream."); + return FALSE; + } + return TRUE; +} + +static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { + belle_sdp_session_description_t* sdp; + int err=0; + SalReason reason; + if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { + if (sdp){ + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + /*make some sanity check about the SDP received*/ + if (!is_media_description_acceptable(op->base.remote_media)){ + err=-1; + reason=SalReasonNotAcceptable; + } + belle_sip_object_unref(sdp); + }else op->sdp_offering=TRUE; /*INVITE without SDP*/ + }else err=-1; + + if (err==-1){ + sal_call_decline(op,reason,NULL); + } + return err; +} + +static void sal_op_reset_descriptions(SalOp *op) { + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=NULL; + } + if (op->result){ + sal_media_description_unref(op->result); + op->result=NULL; + } +} +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_server_transaction_t* server_transaction=NULL; + 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; + const char *method=belle_sip_request_get_method(req); + bool_t is_update=FALSE; + + if (strcmp("ACK",method)!=0){ /*ACK does'nt create srv transaction*/ + server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_object_ref(server_transaction); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),sal_op_ref(op)); + } + + if (strcmp("INVITE",method)==0) { + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + /*updating pending invite transaction*/ + op->pending_server_trans=server_transaction; + belle_sip_object_ref(op->pending_server_trans); + } + + if (strcmp("UPDATE",method)==0) { + if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); + /*updating pending update transaction*/ + op->pending_update_server_trans=server_transaction; + belle_sip_object_ref(op->pending_update_server_trans); + } + + if (!op->dialog) { + set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans))); + ms_message("new incoming call from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: { + if (strcmp("INVITE",method)==0) { + if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { + belle_sip_object_ref(op->replaces); + } else if(op->replaces) { + ms_warning("replace header already set"); + } + + if (process_sdp_for_invite(op,req) == 0) { + if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { + if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) { + op->auto_answer_asked=TRUE; + ms_message("The caller asked to automatically answer the call(Emergency?)\n"); + } + } + op->base.root->callbacks.call_received(op); + } + break; + } /* else same behavior as for EARLY state*/ + } + case BELLE_SIP_DIALOG_EARLY: { + //hmm probably a cancel + if (strcmp("CANCEL",method)==0) { + if(belle_sip_request_event_get_server_transaction(event)) { + /*first answer 200 ok to cancel*/ + belle_sip_server_transaction_send_response(server_transaction + ,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",method)==0) { + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("UPDATE",method)==0) { + sal_op_reset_descriptions(op); + if (process_sdp_for_invite(op,req)==0) + op->base.root->callbacks.call_updating(op,TRUE); + } 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",method)==0) { + if (!op->pending_client_trans || + !belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){ + if (op->sdp_offering){ + SalReason reason; + if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){ + if (sdp){ + if (op->base.remote_media) + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_process(op); + belle_sip_object_unref(sdp); + }else{ + ms_warning("SDP expected in ACK but not found."); + } + } + } + op->base.root->callbacks.call_ack(op); + }else{ + ms_message("Ignored received ack since a new client transaction has been started since."); + } + } else if(strcmp("BYE",method)==0) { + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + op->state=SalOpStateTerminating; + /*call end not notified by dialog deletion because transaction can end before dialog*/ + } else if(strcmp("INVITE",method)==0 || (is_update=(strcmp("UPDATE",method)==0)) ) { + if (is_update && !belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) { + /*session timer case*/ + /*session expire should be handled. to be done when real session timer (rfc4028) will be implemented*/ + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + belle_sip_object_unref(op->pending_update_server_trans); + op->pending_update_server_trans=NULL; + } else { + /*re-invite*/ + sal_op_reset_descriptions(op); + if (process_sdp_for_invite(op,req)==0) + op->base.root->callbacks.call_updating(op,is_update); + } + } else if (strcmp("INFO",method)==0){ + if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) + && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { + /*vfu request*/ + 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",method)==0) { + sal_op_process_refer(op,event,server_transaction); + } else if (strcmp("NOTIFY",method)==0) { + sal_op_call_process_notify(op,event,server_transaction); + } else if (strcmp("OPTIONS",method)==0) { + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("CANCEL",method)==0) { + /*call leg does not exist because 200ok already sent*/ + belle_sip_server_transaction_send_response(server_transaction,sal_op_create_response_from_request(op,req,481)); + } else if (strcmp("MESSAGE",method)==0){ + sal_process_incoming_message(op,event); + }else{ + ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); + unsupported_method(server_transaction,req); + } + 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(bool_t enable_update){ + belle_sip_header_allow_t* header_allow; + char allow [256]; + snprintf(allow,sizeof(allow),"INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO%s",(enable_update?", UPDATE":"")); + header_allow = belle_sip_header_allow_create(allow); + 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(op->base.root->enable_sip_update))); + + if (op->base.root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "600;refresher=uas")); + 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"); + + if( invite == NULL ){ + /* can happen if the op has an invalid address */ + return -1; + } + + 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); +} + +static belle_sip_listener_callbacks_t call_op_callbacks={0}; + +void sal_op_call_fill_cbs(SalOp*op) { + if (call_op_callbacks.process_response_event==NULL){ + call_op_callbacks.process_io_error=call_process_io_error; + call_op_callbacks.process_response_event=call_process_response; + call_op_callbacks.process_timeout=call_process_timeout; + call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated; + call_op_callbacks.process_request_event=process_request_event; + call_op_callbacks.process_dialog_terminated=process_dialog_terminated; + } + op->callbacks=&call_op_callbacks; + op->type=SalOpCall; +} + +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 ) + { + if( op->sdp_handling == SalOpSDPSimulateRemove ){ + ms_warning("Simulating SDP removal in answer for op %p", op); + } else { + 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_create("Require","100rel")); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); + } + +#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING + 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; + belle_sip_server_transaction_t* transaction; + + /*first check if an UPDATE transaction need to be accepted*/ + if (h->pending_update_server_trans) { + transaction=h->pending_update_server_trans; + } else if (h->pending_server_trans) { + /*so it must be an invite/re-invite*/ + transaction=h->pending_server_trans; + } else { + ms_error("No transaction to accept for op [%p]",h); + return -1; + } + ms_message("Accepting server transaction [%p] on op [%p]", transaction, h); + /* sends a 200 OK */ + response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),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(h->base.root->enable_sip_update))); + 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")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Session-expires", "600;refresher=uac")); + /*}*/ + } + + if ((contact_header=sal_op_create_contact(h))) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); + } + + _sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response)); + + handle_offer_answer_response(h,response); + + belle_sip_server_transaction_send_response(transaction,response); + if (h->pending_update_server_trans) { + belle_sip_object_unref(h->pending_update_server_trans); + h->pending_update_server_trans=NULL; + } + return 0; +} + +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); + belle_sip_transaction_t *trans; + + if (reason==SalReasonRedirect){ + if (redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + else status=380; + contact= belle_sip_header_contact_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + } else { + ms_error("Cannot redirect to null"); + } + } + trans=(belle_sip_transaction_t*)op->pending_server_trans; + if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; + if (!trans){ + ms_error("sal_call_decline(): no pending transaction to decline."); + return -1; + } + response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); + if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); + return 0; +} + +int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ + belle_sip_request_t *update; + belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog); + belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); + + /*check for dialog state*/ + if ( state == BELLE_SIP_DIALOG_CONFIRMED) { + if (no_user_consent) + update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); + else + update=belle_sip_dialog_create_request(op->dialog,"INVITE"); + } else if (state == BELLE_SIP_DIALOG_EARLY) { + update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); + } else { + ms_error("Cannot update op [%p] with dialog [%p] in state [%s]",op, op->dialog,belle_sip_dialog_state_to_string(state)); + return -1; + } + if (update){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject)); + sal_op_fill_invite(op, update); + return sal_op_send_request(op,update); + } + /*it failed why ?*/ + if (belle_sip_dialog_request_pending(op->dialog)) + sal_error_info_set(&op->error_info,SalReasonRequestPending,491,NULL,NULL); + else + sal_error_info_set(&op->error_info,SalReasonUnknown,500,NULL,NULL); + 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..84e529091 --- /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,400); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"); + belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t); + belle_sip_response_t* resp; + + ms_message("Receiving NOTIFY request on op [%p]",op); + if (header_event + && strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0 + && content_type + && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 + && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 + && body){ + belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); + + if (sipfrag){ + int code=belle_sip_response_get_status_code(sipfrag); + SalReferStatus status=SalReferFailed; + if (code<200){ + status=SalReferTrying; + }else if (code<300){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.notify_refer(op,status); + } + }else{ + ms_error("Notify without sipfrag, 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..d4a24bd9b --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -0,0 +1,276 @@ +/* +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; + 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_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.subscribe_response(op,sss); + }else if (status_code==0){ + op->base.root->callbacks.on_expire(op); + } + +} + +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)); + } + } +} + +static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 }; + +void sal_op_subscribe_fill_cbs(SalOp*op) { + if (op_subscribe_callbacks.process_io_error==NULL){ + op_subscribe_callbacks.process_io_error=subscribe_process_io_error; + op_subscribe_callbacks.process_response_event=subscribe_response_event; + op_subscribe_callbacks.process_timeout=subscribe_process_timeout; + op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; + op_subscribe_callbacks.process_request_event=subscribe_process_request_event; + op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + } + op->callbacks=&op_subscribe_callbacks; + op->type=SalOpSubscribe; +} + + +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( req == NULL ) { + return -1; + } + 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..d19091c96 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -0,0 +1,819 @@ +/* +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*/ + op->sdp_handling=sal->default_sdp_handling; + 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); + sal_remove_pending_auth(op->base.root,op); + if (op->auth_info) { + sal_auth_info_delete(op->auth_info); + } + if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); + if (op->refresher) { + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + if (op->result) + sal_media_description_unref(op->result); + if(op->replaces) belle_sip_object_unref(op->replaces); + if(op->referred_by) belle_sip_object_unref(op->referred_by); + + if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); + if (op->event) belle_sip_object_unref(op->event); + sal_error_info_reset(&op->error_info); + __sal_op_free(op); + return ; +} + +void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ + if (op->type == SalOpRegister) { + /*Registration authenticate is just about registering again*/ + sal_register_refresh(op,-1); + }else { + /*for sure auth info will be 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_user_password(contact_uri,NULL); + belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); + if (op->privacy!=SalPrivacyNone){ + belle_sip_uri_set_user(contact_uri,NULL); + } + 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; +} + + + +static void add_initial_route_set(belle_sip_request_t *request, const MSList *list){ + const MSList *elem; + for (elem=list;elem!=NULL;elem=elem->next){ + SalAddress *addr=(SalAddress*)elem->data; + belle_sip_header_route_t *route; + belle_sip_uri_t *uri; + /*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/ + if (elem==list && list->next==NULL){ + belle_sip_uri_t *requri=belle_sip_request_get_uri(request); + /*skip the first route it is the same as the request uri*/ + if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){ + ms_message("Skipping top route of initial route-set because same as request-uri."); + continue; + } + } + + route=belle_sip_header_route_create((belle_sip_header_address_t*)addr); + uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route); + belle_sip_uri_set_lr_param(uri,1); + belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route); + } +} + +belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + belle_sip_uri_t* to_uri; + + const SalAddress* to_address; + const MSList *elem=sal_op_get_route_addresses(op); + char token[10]; + + /* check that the op has a correct to address */ + to_address = sal_op_get_to_address(op); + if( to_address == NULL ){ + ms_error("No To: address, cannot build request"); + return NULL; + } + + to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address)); + if( to_uri == NULL ){ + ms_error("To: address is invalid, cannot build request"); + return NULL; + } + + if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) { + from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) + ,belle_sip_random_token(token,sizeof(token))); + } else { + from_header=belle_sip_header_from_create2("Anonymous ",belle_sip_random_token(token,sizeof(token))); + } + /*make sure to preserve components like headers or port*/ + + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri); + belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op)); + + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL); + + 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 (elem && strcmp(method,"REGISTER")!=0 && !op->base.root->no_initial_route){ + add_initial_route_set(req,elem); + } + + if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){ + belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new(); + if (op->privacy&SalPrivacyCritical) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical)); + if (op->privacy&SalPrivacyHeader) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader)); + if (op->privacy&SalPrivacyId) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId)); + if (op->privacy&SalPrivacyNone) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone)); + if (op->privacy&SalPrivacySession) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession)); + if (op->privacy&SalPrivacyUser) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header)); + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->base.root->supported); + return req; +} + +belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code){ + return sal_create_response_from_request(op->base.root,req,code); +} + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to){ + sal_op_set_from(op,from); + sal_op_set_to(op,to); + return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS")); +} + +void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { + belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t); + char user_agent_string[256]; + if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + if (op->base.remote_ua!=NULL){ + ms_free(op->base.remote_ua); + } + op->base.remote_ua=ms_strdup(user_agent_string); + } +} + +int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { + belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); + + if (!expires_header && expires>=0) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); + return sal_op_send_request(op,request); +} + +void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + sal_op_send_request(op,request); +} + +static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){ + + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ + belle_sip_header_contact_t* newct; + /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ + sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); + newct = sal_op_create_contact(op); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); + return; + } + /*if a header already exists in the message, replace it*/ + belle_sip_message_set_header(msg,h); + +} + +void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ + if (op->base.sent_custom_headers){ + belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers; + belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); + belle_sip_list_t *elem; + for(elem=l;elem!=NULL;elem=elem->next){ + add_headers(op,(belle_sip_header_t*)elem->data,msg); + } + belle_sip_list_free(l); + } +} + +static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_uri_t* outbound_proxy=NULL; + belle_sip_header_contact_t* contact; + int result =-1; + belle_sip_uri_t *next_hop_uri=NULL; + + if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) { + contact = sal_op_create_contact(op); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); + } /*keep existing*/ + + _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); + + if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { + /*don't put route header if dialog is in confirmed state*/ + const MSList *elem=sal_op_get_route_addresses(op); + const char *transport; + const char *method=belle_sip_request_get_method(request); + belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP"); + + if (elem) { + outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); + next_hop_uri=outbound_proxy; + }else{ + next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); + } + transport=belle_sip_uri_get_transport_param(next_hop_uri); + if (transport==NULL){ + /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use + * the first available transport*/ + if (!belle_sip_uri_is_secure(next_hop_uri)){ + if (udplp==NULL){ + if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ + transport="tcp"; + }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ + transport="tls"; + } + } + if (transport){ + belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); + belle_sip_uri_set_transport_param(next_hop_uri,transport); + } + } + }else{ +#ifdef TUNNEL_ENABLED + if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){ + /* our tunnel mode only supports UDP. Force transport to be set to UDP */ + belle_sip_uri_set_transport_param(next_hop_uri,"udp"); + } +#endif + } + if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && + (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ + /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ + belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); + } + } + + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); + if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); + op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ + belle_sip_object_ref(op->pending_client_trans); + + if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); + + if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) + && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { + /*hmm just in case we already have authentication param in cache*/ + belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm); + } + result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); + + /*update call id if not set yet for this OP*/ + if (result == 0 && !op->base.call_id) { + op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t)))); + } + + return result; + +} + +int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { + bool_t need_contact=FALSE; + if (request==NULL) { + return -1; /*sanity check*/ + } + /* + Header field where proxy ACK BYE CAN INV OPT REG + ___________________________________________________________ + Contact R o - - m o o + */ + if (strcmp(belle_sip_request_get_method(request),"INVITE")==0 + ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0 + ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0 + ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0 + ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/ + need_contact=TRUE; + + return _sal_op_send_request_with_contact(op, request,need_contact); +} + +SalReason sal_reason_to_sip_code(SalReason r){ + int ret=500; + switch(r){ + case SalReasonNone: + ret=200; + break; + case SalReasonIOError: + ret=503; + break; + case SalReasonUnknown: + ret=400; + break; + case SalReasonBusy: + ret=486; + break; + case SalReasonDeclined: + ret=603; + break; + case SalReasonDoNotDisturb: + ret=600; + break; + case SalReasonForbidden: + ret=403; + break; + case SalReasonUnsupportedContent: + ret=415; + break; + case SalReasonNotFound: + ret=404; + break; + case SalReasonRedirect: + ret=302; + break; + case SalReasonTemporarilyUnavailable: + ret=480; + break; + case SalReasonServiceUnavailable: + ret=503; + break; + case SalReasonRequestPending: + ret=491; + break; + case SalReasonUnauthorized: + ret=401; + break; + case SalReasonNotAcceptable: + ret=488; /*or maybe 606 Not Acceptable ?*/ + break; + case SalReasonNoMatch: + ret=481; + break; + case SalReasonRequestTimeout: + ret=408; + break; + case SalReasonMovedPermanently: + ret=301; + break; + case SalReasonGone: + ret=410; + break; + case SalReasonAddressIncomplete: + ret=484; + break; + case SalReasonNotImplemented: + ret=501; + break; + case SalReasonServerTimeout: + ret=504; + break; + case SalReasonBadGateway: + ret=502; + break; + case SalReasonInternalError: + ret=500; + break; + } + return ret; +} + +SalReason _sal_reason_from_sip_code(int code) { + if (code>=100 && code<300) return SalReasonNone; + + switch(code) { + case 0: + return SalReasonIOError; + case 301: + return SalReasonMovedPermanently; + case 302: + return SalReasonRedirect; + case 401: + case 407: + return SalReasonUnauthorized; + case 403: + return SalReasonForbidden; + case 404: + return SalReasonNotFound; + case 408: + return SalReasonRequestTimeout; + case 410: + return SalReasonGone; + case 415: + return SalReasonUnsupportedContent; + case 422: + ms_error ("422 not implemented yet");; + break; + case 480: + return SalReasonTemporarilyUnavailable; + case 481: + return SalReasonNoMatch; + case 484: + return SalReasonAddressIncomplete; + case 486: + return SalReasonBusy; + case 487: + return SalReasonNone; + case 488: + return SalReasonNotAcceptable; + case 491: + return SalReasonRequestPending; + case 500: + return SalReasonInternalError; + case 501: + return SalReasonNotImplemented; + case 502: + return SalReasonBadGateway; + case 504: + return SalReasonServerTimeout; + case 600: + return SalReasonDoNotDisturb; + case 603: + return SalReasonDeclined; + case 503: + return SalReasonServiceUnavailable; + default: + return SalReasonUnknown; + } + return SalReasonUnknown; +} + +const SalErrorInfo *sal_error_info_none(void){ + static SalErrorInfo none={ + SalReasonNone, + "Ok", + 200, + NULL, + NULL + }; + return &none; +} + +void sal_error_info_reset(SalErrorInfo *ei){ + if (ei->status_string){ + ms_free(ei->status_string); + ei->status_string=NULL; + } + if (ei->warnings){ + ms_free(ei->warnings); + ei->warnings=NULL; + + } + if (ei->full_string){ + ms_free(ei->full_string); + ei->full_string=NULL; + } + ei->protocol_code=0; + ei->reason=SalReasonNone; +} + +void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning){ + sal_error_info_reset(ei); + if (reason==SalReasonUnknown) ei->reason=_sal_reason_from_sip_code(code); + else ei->reason=reason; + ei->protocol_code=code; + ei->status_string=status_string ? ms_strdup(status_string) : NULL; + ei->warnings=warning ? ms_strdup(warning) : NULL; + if (ei->status_string){ + if (ei->warnings) + ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); + else ei->full_string=ms_strdup(ei->status_string); + } +} + +void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){ + int code = belle_sip_response_get_status_code(response); + const char *reason_phrase=belle_sip_response_get_reason_phrase(response); + /*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/ + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning"); + SalErrorInfo *ei=&op->error_info; + const char *warnings; + + warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL; + if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL; + sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings); +} + +const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ + return &op->error_info; +} + +static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ + belle_sip_dialog_set_application_data(dialog,NULL); + sal_op_unref(op); + belle_sip_object_unref(dialog); +} + +static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ + belle_sip_dialog_set_application_data(dialog,sal_op_ref(op)); + belle_sip_object_ref(dialog); + return dialog; +} + +void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { + ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog); + sal_op_ref(op); + if (op->dialog!=dialog){ + if (op->dialog){ + /*FIXME: shouldn't we delete unconfirmed dialogs ?*/ + unlink_op_with_dialog(op,op->dialog); + op->dialog=NULL; + } + if (dialog) { + op->dialog=link_op_with_dialog(op,dialog); + belle_sip_dialog_enable_pending_trans_checking(dialog,op->base.root->pending_trans_checking); + } + } + sal_op_unref(op); +} +/*return reffed op*/ +SalOp* sal_op_ref(SalOp* op) { + op->ref++; + return op; +} +/*return null, destroy op if ref count =0*/ +void* sal_op_unref(SalOp* op) { + op->ref--; + if (op->ref==0) { + sal_op_release_impl(op); + }else if (op->ref<0){ + ms_fatal("SalOp [%p]: too many unrefs.",op); + } + return NULL; +} + +int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) { + if (sal_op_send_request_with_expires(op,req,expires)==0) { + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + } + if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { + /*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified + * that it is terminated anymore.*/ + sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/ + /* Note that the refresher will replace our data with belle_sip_transaction_set_application_data(). + Something in the design is not very good here, it makes things complicated to the belle-sip user. + Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction + notify the user as a normal transaction*/ + belle_sip_refresher_set_listener(op->refresher,listener,op); + belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); + belle_sip_refresher_set_realm(op->refresher,op->base.realm); + belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); + return 0; + } else { + return -1; + } + } + return -1; +} + +const char* sal_op_state_to_string(const SalOpState value) { + switch(value) { + case SalOpStateEarly: return"SalOpStateEarly"; + case SalOpStateActive: return "SalOpStateActive"; + case SalOpStateTerminating: return "SalOpStateTerminating"; + case SalOpStateTerminated: return "SalOpStateTerminated"; + default: + return "Unknown"; + } +} + +/* + * Warning: this function takes owneship of the custom headers + */ +void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){ + SalOpBase *b=(SalOpBase *)op; + if (b->sent_custom_headers){ + sal_custom_header_free(b->sent_custom_headers); + b->sent_custom_headers=NULL; + } + if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); + b->sent_custom_headers=ch; +} + +void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ + if (incoming) belle_sip_object_ref(incoming); + if (op->base.recv_custom_headers){ + belle_sip_object_unref(op->base.recv_custom_headers); + op->base.recv_custom_headers=NULL; + } + if (incoming){ + op->base.recv_custom_headers=(SalCustomHeader*)incoming; + } +} + +const char *sal_op_get_remote_contact(const SalOp *op){ + /* + * remote contact is filled in process_response + * return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); + */ + return op->base.remote_contact; +} + +void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){ + 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; +} + +bool_t sal_op_is_ipv6(SalOp *op){ + belle_sip_transaction_t *tr=NULL; + belle_sip_header_address_t *contact; + belle_sip_request_t *req; + + if (op->refresher) + tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher); + + if (tr==NULL) + tr=(belle_sip_transaction_t *)op->pending_client_trans; + if (tr==NULL) + tr=(belle_sip_transaction_t *)op->pending_server_trans; + + if (tr==NULL){ + ms_error("Unable to determine IP version from signaling operation."); + return FALSE; + } + req=belle_sip_transaction_get_request(tr); + contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); + if (!contact){ + ms_error("Unable to determine IP version from signaling operation, no contact header found."); + } + return sal_address_is_ipv6((SalAddress*)contact); +} + +bool_t sal_op_is_idle(SalOp *op){ + if (op->dialog){ + return !belle_sip_dialog_request_pending(op->dialog); + } + return TRUE; +} + +void sal_op_stop_refreshing(SalOp *op){ + if (op->refresher){ + belle_sip_refresher_stop(op->refresher); + } +} + +void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling) { + if (handling != SalOpSDPNormal) ms_message("Enabling special SDP handling for SalOp[%p]!", h); + h->sdp_handling = handling; +} +void sal_op_cnx_ip_to_0000_if_sendonly_enable(SalOp *op,bool_t yesno) { + op->cnx_ip_to_0000_if_sendonly_enabled = yesno; +} +bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *op) { + return op->cnx_ip_to_0000_if_sendonly_enabled; +} diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c new file mode 100644 index 000000000..3cffb8e55 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -0,0 +1,32 @@ +/* +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_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); + 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..921f8c0a6 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -0,0 +1,357 @@ +/* +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 "linphonecore.h" +#include "private.h" +#include "lime.h" +#include + +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; + sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO Error",NULL); + process_error(op); +} +static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalOp* op=(SalOp*)user_ctx; + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + process_error(op); + +} +static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); + SalTextDeliveryStatus status; + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); + + if (code>=100 && code <200) + status=SalTextDeliveryInProgress; + else if (code>=200 && code <300) + status=SalTextDeliveryDone; + else + status=SalTextDeliveryFailed; + + op->base.root->callbacks.text_delivery_update(op,status); +} + +static bool_t is_rcs_filetransfer(belle_sip_header_content_type_t* content_type) { + return (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0) + && ((strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0) || (strcmp("cipher.vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0)); +} + +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_cipher_xml(belle_sip_header_content_type_t* content_type) { + return (strcmp("xml",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher",belle_sip_header_content_type_get_subtype(content_type))==0) + + || (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher.vnd.gsma.rcs-ft-http+xml",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 bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { + return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("im-iscomposing+xml",belle_sip_header_content_type_get_subtype(content_type))==0; +} + +static void add_message_accept(belle_sip_message_t *msg){ + belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cipher, application/vnd.gsma.rcs-ft-http+xml, application/cipher.vnd.gsma.rcs-ft-http+xml")); +} + +void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; + int errcode=500; + belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); + belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); + belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); + char* from; + bool_t plain_text=FALSE; + bool_t external_body=FALSE; + bool_t cipher_xml=FALSE; + bool_t rcs_filetransfer=FALSE; + uint8_t *decryptedMessage = NULL; + + 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); + /* check if we have a xml/cipher message to be decrypted */ + if (content_type && (cipher_xml=is_cipher_xml(content_type))) { + /* access the zrtp cache to get keys needed to decipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+"); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to decrypt message"); + goto error; + } else { + size_t cacheSize; + char *cacheString; + int retval; + xmlDocPtr cacheXml; + + cacheString=ms_load_file_content(CACHEFD, &cacheSize); + if (!cacheString){ + ms_warning("Unable to load content of ZRTP ZID cache to decrypt message"); + goto error; + } + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + cacheXml = xmlParseDoc((xmlChar*)cacheString); + ms_free(cacheString); + retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); + if (retval != 0) { + ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op); + free(decryptedMessage); + xmlFreeDoc(cacheXml); + errcode = 488; + goto error; + } else { + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+"); + if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){ + ms_warning("Fail to write cache"); + } + xmlFree(xmlStringOutput); + fclose(CACHEFD); + } + + xmlFreeDoc(cacheXml); + } + + } + + rcs_filetransfer=is_rcs_filetransfer(content_type); + if (content_type && ((plain_text=is_plain_text(content_type)) + || (external_body=is_external_body(content_type)) + || (decryptedMessage!=NULL) + || rcs_filetransfer)) { + SalMessage salmsg; + char message_id[256]={0}; + + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + belle_sip_object_ref(op->pending_server_trans); + + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + snprintf(message_id,sizeof(message_id)-1,"%s%i" + ,belle_sip_header_call_id_get_call_id(call_id) + ,belle_sip_header_cseq_get_seq_number(cseq)); + salmsg.from=from; + /* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/ + if (cipher_xml) { + salmsg.text = (char *)decryptedMessage; + } else { /* message body wasn't ciphered */ + salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + } + salmsg.url=NULL; + salmsg.content_type = NULL; + if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */ + salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml"; + } + 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); + + free(decryptedMessage); + belle_sip_object_unref(address); + belle_sip_free(from); + if (salmsg.url) ms_free((char*)salmsg.url); + } else if (content_type && is_im_iscomposing(content_type)) { + SalIsComposing saliscomposing; + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + saliscomposing.from=from; + saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + op->base.root->callbacks.is_composing_received(op,&saliscomposing); + resp = belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + belle_sip_object_unref(address); + belle_sip_free(from); + } else { + ms_error("Unsupported MESSAGE (content-type not recognized)"); + resp = belle_sip_response_create_from_request(req,415); + add_message_accept((belle_sip_message_t*)resp); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); + return; + } + return; +error: + resp = belle_sip_response_create_from_request(req, errcode); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); +} + +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + sal_process_incoming_message(op,event); +} + +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ + belle_sip_request_t* req; + char content_type_raw[256]; + size_t content_length = msg?strlen(msg):0; + time_t curtime=time(NULL); + uint8_t *multipartEncryptedMessage = NULL; + int retval; + + if (op->dialog){ + /*for SIP MESSAGE that are sent in call's dialog*/ + req=belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); + }else{ + sal_op_message_fill_cbs(op); + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + op->dir=SalOpDirOutgoing; + + req=sal_op_build_request(op,"MESSAGE"); + if (req == NULL ){ + return -1; + } + if (sal_op_get_contact_address(op)){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); + } + } + + /* shall we try to encrypt the message?*/ + if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 0))) { + /* access the zrtp cache to get keys needed to cipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+"); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to encrypt message"); + /*probably not a good idea to do this:*/ + sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + return -1; + } else { + size_t cacheSize; + char *cacheString; + xmlDocPtr cacheXml; + int retval; + + cacheString=ms_load_file_content(CACHEFD, &cacheSize); + if (!cacheString){ + ms_warning("Unable to load content of ZRTP ZID cache to encrypt message"); + return -1; + } + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + cacheXml = xmlParseDoc((xmlChar*)cacheString); + ms_free(cacheString); + retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); + if (retval != 0) { + ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op); + xmlFreeDoc(cacheXml); + free(multipartEncryptedMessage); + /*probably not a good idea to do this:*/ + sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + return -1; + } else { + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+"); + if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){ + ms_warning("Unable to write zid cache"); + } + xmlFree(xmlStringOutput); + fclose(CACHEFD); + content_length = strlen((const char *)multipartEncryptedMessage); + } + xmlFreeDoc(cacheXml); + } + } + + 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),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); + retval = sal_op_send_request(op,req); + free(multipartEncryptedMessage); + + return retval; +} + +int sal_message_reply(SalOp *op, SalReason reason){ + if (op->pending_server_trans){ + int code=sal_reason_to_sip_code(reason); + belle_sip_response_t *resp = belle_sip_response_create_from_request( + belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code); + belle_sip_server_transaction_send_response(op->pending_server_trans,resp); + return 0; + }else ms_error("sal_message_reply(): no server transaction"); + return -1; +} + +int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { + return sal_message_send(op,from,to,"text/plain",msg, NULL); +} + +static belle_sip_listener_callbacks_t op_message_callbacks={0}; + +void sal_op_message_fill_cbs(SalOp*op) { + if (op_message_callbacks.process_io_error==NULL){ + op_message_callbacks.process_io_error=process_io_error; + op_message_callbacks.process_response_event=process_response_event; + op_message_callbacks.process_timeout=process_timeout; + op_message_callbacks.process_request_event=process_request_event; + } + op->callbacks=&op_message_callbacks; + op->type=SalOpMessage; +} diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c new file mode 100644 index 000000000..6de0a0fbf --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -0,0 +1,364 @@ +/* +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); + belle_sip_free(contact_info); + if (content == NULL) return; + } + + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),NULL,0); + + if (content){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content)))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length); + ms_free(content); + } +} + +static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + 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); + belle_sip_header_expires_t* expires; + + sal_op_set_error_info_from_response(op,response); + + if (code>=300) { + ms_message("subscription to [%s] rejected",sal_op_get_to(op)); + op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ + return; + } + 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); + belle_sip_refresher_set_realm(op->refresher,op->base.realm); + } + } + 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; + + if (body==NULL) 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=NULL; + belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + SalSubscribeStatus sub_state; + + if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + SalPresenceModel *presence_model = NULL; + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + if (!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; + } + presence_model = process_presence_notification(op, req); + if (presence_model != NULL || body==NULL) { + /* Presence notification body parsed successfully. */ + + resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */ + op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); + } else if (body){ + /* Formatting error in presence notification body. */ + ms_warning("Wrongly formatted presence document."); + resp = sal_op_create_response_from_request(op, req, 488); + } + if (resp) belle_sip_server_transaction_send_response(server_transaction,resp); + } +} + +static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_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; + } +} + +static belle_sip_listener_callbacks_t op_presence_callbacks={0}; + +void sal_op_presence_fill_cbs(SalOp*op) { + if (op_presence_callbacks.process_request_event==NULL){ + op_presence_callbacks.process_io_error=presence_process_io_error; + op_presence_callbacks.process_response_event=presence_response_event; + op_presence_callbacks.process_timeout=presence_process_timeout; + op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated; + op_presence_callbacks.process_request_event=presence_process_request_event; + op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated; + } + op->callbacks=&op_presence_callbacks; + op->type=SalOpPresence; +} + + +/*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"); + if( req ){ + 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..17ef8e8db --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -0,0 +1,129 @@ +/* +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; + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ + ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op)); + if (status_code==412){ + /*resubmit the request after removing the SIP-If-Match*/ + 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){ + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); + op->base.root->callbacks.on_publish_response(op); + } +} + +static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){ + SalOp *op=(SalOp*)userctx; + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); + if (op->error_info.protocol_code>=200){ + op->base.root->callbacks.on_publish_response(op); + } +} + +static belle_sip_listener_callbacks_t op_publish_callbacks={0}; + +void sal_op_publish_fill_cbs(SalOp *op) { + if (op_publish_callbacks.process_response_event==NULL){ + op_publish_callbacks.process_response_event=publish_response_event; + } + op->callbacks=&op_publish_callbacks; + op->type=SalOpPublish; +} + +/* + * 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( req == NULL ){ + return -1; + } + + if (sal_op_get_contact_address(op)){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); + } + 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( req == NULL ){ + return -1; + } + + if (sal_op_get_contact_address(op)){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); + } + 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); + if (expires!=-1) + return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); + else return sal_op_send_request(op,req); + } else { + /*update status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*update body*/ + 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..961ba4a34 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -0,0 +1,130 @@ +/* +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; + 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)); + } + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + if (status_code>=200){ + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); + } + 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; + belle_sip_header_contact_t *contact = belle_sip_refresher_get_contact(refresher); + 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*/ + if (contact) { + sal_op_set_contact_address(op,(SalAddress*)(BELLE_SIP_HEADER_ADDRESS(contact))); /*update contact with real value*/ + } + 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_op_ref(op); /*take a ref while invoking the callback to make sure the operations done after are valid*/ + op->base.root->callbacks.register_failure(op); + if (op->state!=SalOpStateTerminated && op->auth_info) { + /*add pending auth*/ + sal_add_pending_auth(op->base.root,op); + if (status_code==403 || status_code==401 || status_code==407 ) + op->base.root->callbacks.auth_failure(op,op->auth_info); + } + sal_op_unref(op); + } +} + +int sal_register(SalOp *op, const char *proxy, const char *from, int expires,SalAddress* old_contact){ + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + belle_sip_header_t* accept_header; + + 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))); + } + accept_header = belle_sip_header_create("Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), accept_header); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op)); + if (old_contact) { + belle_sip_header_contact_t *contact=belle_sip_header_contact_create((const belle_sip_header_address_t *)old_contact); + if (contact) { + char * tmp; + belle_sip_header_contact_set_expires(contact,0); /*remove old aor*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(contact)); + tmp = belle_sip_object_to_string(contact); + ms_message("Clearing contact [%s] for op [%p]",tmp,op); + ms_free(tmp); + } else { + ms_error("Cannot add old contact header to op [%p]",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..9313a3d43 --- /dev/null +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -0,0 +1,899 @@ +/* +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 bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescription *stream, uint16_t *trr_int) { + MSList *pt_it; + bool_t first = TRUE; + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + PayloadType *pt = (PayloadType *)pt_it->data; + if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { + if (first == TRUE) { + *trr_int = payload_type_get_avpf_params(pt).trr_interval; + first = FALSE; + } else if (payload_type_get_avpf_params(pt).trr_interval != *trr_int) { + return FALSE; + } + } + } + return TRUE; +} + +static void add_rtcp_fb_trr_int_attribute(belle_sdp_media_description_t *media_desc, int8_t id, uint16_t trr_int) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); + belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, trr_int); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + +static void add_rtcp_fb_ack_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_ACK); + belle_sdp_rtcp_fb_attribute_set_param(attribute, param); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + +static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_NACK); + belle_sdp_rtcp_fb_attribute_set_param(attribute, param); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + +static void add_rtcp_fb_ccm_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_CCM); + belle_sdp_rtcp_fb_attribute_set_param(attribute, param); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + +static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream) { + MSList *pt_it; + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + bool_t general_trr_int; + uint16_t trr_int = 0; + + general_trr_int = is_rtcp_fb_trr_int_the_same_for_all_payloads(stream, &trr_int); + if (general_trr_int == TRUE) { + add_rtcp_fb_trr_int_attribute(media_desc, -1, trr_int); + } + if (stream->rtcp_fb.generic_nack_enabled == TRUE) { + add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_NONE); + } + if (stream->rtcp_fb.tmmbr_enabled == TRUE) { + add_rtcp_fb_ccm_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_TMMBR); + } + + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + + /* AVPF/SAVPF profile is used so enable AVPF for all paylad types. */ + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + + /* Add trr-int if not set generally. */ + if (general_trr_int != TRUE) { + add_rtcp_fb_trr_int_attribute(media_desc, payload_type_get_number(pt), avpf_params.trr_interval); + } + + /* Add rtcp-fb attributes according to the AVPF features of the payload types. */ + if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) { + if (avpf_params.rpsi_compatibility == TRUE) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); + } else { + add_rtcp_fb_ack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); + } + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_FIR) { + add_rtcp_fb_ccm_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR); + } + } +} + +static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfiguration *config) { + belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new(); + if (config->rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { + if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttAll) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "all"); + else if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttSender) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "sender"); + belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(attribute, config->rcvr_rtt_max_size); + } + belle_sdp_rtcp_xr_attribute_set_stat_summary(attribute, (config->stat_summary_enabled == TRUE)); + if (config->stat_summary_enabled == TRUE) { + if (config->stat_summary_flags & OrtpRtcpXrStatSummaryLoss) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "loss"); + if (config->stat_summary_flags & OrtpRtcpXrStatSummaryDup) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "dup"); + if (config->stat_summary_flags & OrtpRtcpXrStatSummaryJitt) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "jitt"); + if (config->stat_summary_flags & OrtpRtcpXrStatSummaryTTL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "TTL"); + if (config->stat_summary_flags & OrtpRtcpXrStatSummaryHL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "HL"); + } + belle_sdp_rtcp_xr_attribute_set_voip_metrics(attribute, (config->voip_metrics_enabled == TRUE)); + return BELLE_SDP_ATTRIBUTE(attribute); +} + +static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) { + belle_sdp_mime_parameter_t* mime_param; + belle_sdp_media_description_t* media_desc; + int j; + 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_description_get_type_as_string(stream) + ,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 + , pt->channels>0 ? pt->channels : -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; + belle_sdp_connection_t *connection; + if (strchr(rtp_addr,':')!=NULL){ + inet6=TRUE; + }else inet6=FALSE; + connection = belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr); + if (ms_is_multicast(rtp_addr)) { + /*remove session cline in case of multicast*/ + belle_sdp_session_description_set_connection(session_desc,NULL); + if (inet6 == FALSE) + belle_sdp_connection_set_ttl(connection,stream->ttl); + } + belle_sdp_media_description_set_connection(media_desc,connection); + } + + if ( stream->bandwidth>0 ) + belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); + + if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { + /* add crypto lines */ + for ( j=0; jcrypto[j].algo,&desc)==0){ + if (desc.params) + snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params); + else + snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key ); + + belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer)); + }else break; + } + } + + /* insert DTLS session attribute if needed */ + if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) { + char* ssrc_attribute = ms_strdup_printf("%u cname:%s",stream->rtp_ssrc,stream->rtcp_cname); + if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) { + switch(stream->dtls_role) { + case SalDtlsRoleIsClient: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","active")); + break; + case SalDtlsRoleIsServer: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","passive")); + break; + case SalDtlsRoleUnset: + default: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","actpass")); + break; + } + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint)); + } + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); + ms_free(ssrc_attribute); + } + + 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); + } + } + + if ((rtp_port != 0) && ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf))) { + add_rtcp_fb_attributes(media_desc, md, stream); + } + + if ((rtp_port != 0) && (stream->rtcp_xr.enabled == TRUE)) { + char sastr[1024] = {0}; + char mastr[1024] = {0}; + size_t saoff = 0; + size_t maoff = 0; + const belle_sdp_attribute_t *session_attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr"); + belle_sdp_attribute_t *media_attribute; + if (session_attribute != NULL) { + belle_sip_object_marshal((belle_sip_object_t*)session_attribute, sastr, sizeof(sastr), &saoff); + } + media_attribute = create_rtcp_xr_attribute(&stream->rtcp_xr); + if (media_attribute != NULL) { + belle_sip_object_marshal((belle_sip_object_t*)media_attribute, mastr, sizeof(mastr), &maoff); + } + if (strcmp(sastr, mastr) != 0) { + belle_sdp_media_description_add_attribute(media_desc, media_attribute); + } else { + belle_sip_object_unref((belle_sip_object_t*)media_attribute); + } + } + /* + * rfc5576 + * 4.1. The "ssrc" Media Attribute + * is the synchronization source (SSRC) ID of the + * source being described, interpreted as a 32-bit unsigned integer in + * network byte order and represented in decimal.*/ + + + belle_sdp_session_description_add_media_description(session_desc, 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 ( desc->name[0]!='\0' ? desc->name : "Talk" ) ); + + if ( !sal_media_description_has_dir ( desc,SalStreamInactive ) || desc->ice_ufrag[0] != '\0' ) { + /*in case of sendonly, setting of the IP on cnx we give a chance to receive stun packets*/ + 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)); + + if (desc->rtcp_xr.enabled == TRUE) { + belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr)); + } + + for ( i=0; inb_streams; i++ ) { + stream_description_to_sdp(session_desc, desc, &desc->streams[i]); + } + return session_desc; +} + + +static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + belle_sip_list_t* mime_param_it=NULL; + belle_sdp_mime_parameter_t* mime_param; + belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); + memset(&avpf_params, 0, sizeof(avpf_params)); + 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 ) ); + payload_type_set_avpf_params(pt, avpf_params); + stream->payloads=ms_list_append ( stream->payloads,pt ); + stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); + ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : "" ); + } + if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref ); +} + +static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + belle_sdp_attribute_t *attribute; + char tmp[256], tmp2[256], parameters[256]={0}; + int valid_count = 0; + int nb; + + memset ( &stream->crypto, 0, sizeof ( stream->crypto ) ); + for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc ) + ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; + attribute_it=attribute_it->next ) { + attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); + + if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { + nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s %256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2, parameters ); + + if ( nb >= 3 ) { + MSCryptoSuite cs; + MSCryptoSuiteNameParams np; + + np.name=tmp; + np.params=parameters[0]!='\0' ? parameters : NULL; + cs=ms_crypto_suite_build_from_name_params(&np); + if (cs==MS_CRYPTO_SUITE_INVALID){ + ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); + stream->crypto[valid_count].algo = 0; + }else{ + char *sep; + strncpy ( stream->crypto[valid_count].master_key, tmp2, sizeof(stream->crypto[valid_count].master_key)-1 ); + sep=strchr(stream->crypto[valid_count].master_key,'|'); + if (sep) *sep='\0'; + stream->crypto[valid_count].algo = cs; + ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + stream->crypto[valid_count].master_key ); + valid_count++; + } + }else{ + ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb ); + } + } + } + ms_message("Found: %d valid crypto lines", valid_count ); +} + +static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + belle_sdp_attribute_t *attribute; + const char *att_name; + const char *value; + int nb_ice_candidates = 0; + + for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { + attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); + att_name = belle_sdp_attribute_get_name(attribute); + value = belle_sdp_attribute_get_value(attribute); + + if ( (nb_ice_candidates < sizeof (stream->ice_candidates)/sizeof(SalIceCandidate)) + && (keywordcmp("candidate", att_name) == 0) + && (value != NULL)) { + SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; + char proto[4]; + int nb = sscanf(value, "%s %u %3s %u %s %d typ %s raddr %s rport %d", + candidate->foundation, &candidate->componentID, proto, &candidate->priority, candidate->addr, &candidate->port, + candidate->type, candidate->raddr, &candidate->rport); + if (strcasecmp("udp",proto)==0 && ((nb == 7) || (nb == 9))) nb_ice_candidates++; + else memset(candidate, 0, sizeof(*candidate)); + } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { + SalIceRemoteCandidate candidate; + unsigned int componentID; + int offset; + const char *ptr = value; + const char *endptr = value + strlen(ptr); + while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { + if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { + SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; + strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)-1); + remote_candidate->port = candidate.port; + } + ptr += offset; + if (ptr < endptr) { + if (ptr[offset] == ' ') ptr += 1; + } else break; + } + } else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)-1); + } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd) -1); + } else if (keywordcmp("ice-mismatch", att_name) == 0) { + stream->ice_mismatch = TRUE; + } + } +} + +static void enable_avpf_for_stream(SalStreamDescription *stream) { + MSList *pt_it; + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + PayloadType *pt = (PayloadType *)pt_it->data; + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + } +} + +static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, SalStreamDescription *stream, PayloadType *pt) { + PayloadTypeAvpfParams avpf_params = payload_type_get_avpf_params(pt); + switch (belle_sdp_rtcp_fb_attribute_get_type(fb_attribute)) { + case BELLE_SDP_RTCP_FB_ACK: + if (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute) == BELLE_SDP_RTCP_FB_RPSI) { + avpf_params.features |= PAYLOAD_TYPE_AVPF_RPSI; + } + break; + case BELLE_SDP_RTCP_FB_NACK: + switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_PLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI; + break; + case BELLE_SDP_RTCP_FB_SLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_SLI; + break; + case BELLE_SDP_RTCP_FB_RPSI: + /* Linphone uses positive feeback for RPSI. However first versions handling + * AVPF wrongly declared RPSI as negative feedback, so this is kept for compatibility + * with these versions but will probably be removed at some point in time. */ + avpf_params.features |= PAYLOAD_TYPE_AVPF_RPSI; + avpf_params.rpsi_compatibility = TRUE; + break; + case BELLE_SDP_RTCP_FB_NONE: + stream->rtcp_fb.generic_nack_enabled = TRUE; + break; + default: + break; + } + break; + case BELLE_SDP_RTCP_FB_TRR_INT: + avpf_params.trr_interval = belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); + break; + case BELLE_SDP_RTCP_FB_CCM: + switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_FIR: + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + break; + case BELLE_SDP_RTCP_FB_TMMBR: + stream->rtcp_fb.tmmbr_enabled = TRUE; + break; + default: + break; + } + break; + default: + break; + } + payload_type_set_avpf_params(pt, avpf_params); +} + +static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *it; + belle_sdp_attribute_t *attribute; + belle_sdp_rtcp_fb_attribute_t *fb_attribute; + MSList *pt_it; + PayloadType *pt; + int8_t pt_num; + + /* Handle rtcp-fb attributes that concern all payload types. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + if (belle_sdp_rtcp_fb_attribute_get_id(fb_attribute) == -1) { + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt); + } + } + } + } + + /* Handle rtcp-fb attributes that are specefic to a payload type. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + pt_num = belle_sdp_rtcp_fb_attribute_get_id(fb_attribute); + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + if (payload_type_get_number(pt) == (int)pt_num) { + apply_rtcp_fb_attribute_to_payload(fb_attribute, stream, pt); + } + } + } + } +} + +static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) { + config->enabled = FALSE; + config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; + config->rcvr_rtt_max_size = -1; + config->stat_summary_flags = 0; + config->voip_metrics_enabled = FALSE; +} + +static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, OrtpRtcpXrConfiguration *config) { + if (attribute != NULL) { + const belle_sdp_rtcp_xr_attribute_t *xr_attr; + const char *rcvr_rtt_mode; + sal_init_rtcp_xr_description(config); + xr_attr = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute); + rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(xr_attr); + if (rcvr_rtt_mode != NULL) { + if (strcasecmp(rcvr_rtt_mode, "all") == 0) { + config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll; + } else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) { + config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender; + } + config->rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(xr_attr); + } + config->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0); + if (config->stat_summary_enabled) { + const belle_sip_list_t *stat_summary_flag_it; + for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) { + const char *flag = (const char *)stat_summary_flag_it->data; + if (flag != NULL) { + if (strcasecmp(flag, "loss") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryLoss; + else if (strcasecmp(flag, "dup") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryDup; + else if (strcasecmp(flag, "jitt") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryJitt; + else if (strcasecmp(flag, "TTL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryTTL; + else if (strcasecmp(flag, "HL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryHL; + } + } + } + config->voip_metrics_enabled = (belle_sdp_rtcp_xr_attribute_has_voip_metrics(xr_attr) != 0); + config->enabled = TRUE; + } +} + +static void sdp_parse_session_rtcp_xr_parameters(belle_sdp_session_description_t *session_desc, OrtpRtcpXrConfiguration *config) { + const belle_sdp_attribute_t *attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr"); + sdp_parse_rtcp_xr_parameters(attribute, config); +} + +static void sdp_parse_media_rtcp_xr_parameters(belle_sdp_media_description_t *media_desc, OrtpRtcpXrConfiguration *config) { + const belle_sdp_attribute_t *attribute = belle_sdp_media_description_get_attribute(media_desc, "rtcp-xr"); + sdp_parse_rtcp_xr_parameters(attribute, config); +} + +static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) { + SalStreamDescription *stream; + belle_sdp_connection_t* cnx; + belle_sdp_media_t* media; + belle_sdp_attribute_t* attribute; + const char* value; + const char *mtype,*proto; + + stream=&md->streams[md->nb_streams]; + media=belle_sdp_media_description_get_media ( media_desc ); + + proto = belle_sdp_media_get_protocol ( media ); + stream->proto=SalProtoOther; + if ( proto ) { + if (strcasecmp(proto, "RTP/AVP") == 0) { + stream->proto = SalProtoRtpAvp; + } else if (strcasecmp(proto, "RTP/SAVP") == 0) { + stream->proto = SalProtoRtpSavp; + } else if (strcasecmp(proto, "RTP/AVPF") == 0) { + stream->proto = SalProtoRtpAvpf; + } else if (strcasecmp(proto, "RTP/SAVPF") == 0) { + stream->proto = SalProtoRtpSavpf; + } else if (strcasecmp(proto, "UDP/TLS/RTP/SAVP") == 0) { + stream->proto = SalProtoUdpTlsRtpSavp; + } else if (strcasecmp(proto, "UDP/TLS/RTP/SAVPF") == 0) { + stream->proto = SalProtoUdpTlsRtpSavpf; + } else { + strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1); + } + } + if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { + strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 ); + stream->ttl=belle_sdp_connection_get_ttl(cnx); + } + + stream->rtp_port=belle_sdp_media_get_media_port ( media ); + + mtype = belle_sdp_media_get_media_type ( media ); + if ( strcasecmp ( "audio", mtype ) == 0 ) { + stream->type=SalAudio; + } else if ( strcasecmp ( "video", mtype ) == 0 ) { + stream->type=SalVideo; + } else { + stream->type=SalOther; + strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 ); + } + + if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) { + stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ); + } + + if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) { + stream->dir=SalStreamSendRecv; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) { + stream->dir=SalStreamSendOnly; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) { + stream->dir=SalStreamRecvOnly; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) { + stream->dir=SalStreamInactive; + } else { + stream->dir=md->dir; /*takes default value if not present*/ + } + + /* Get media payload types */ + sdp_parse_payload_types(media_desc, stream); + + /* Get media specific RTCP attribute */ + stream->rtcp_port = stream->rtp_port + 1; + snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); + attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + char tmp[256]; + int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); + if (nb == 1) { + /* SDP rtcp attribute only contains the port */ + } else if (nb == 2) { + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)-1); + } else { + ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); + } + } + + /* Read DTLS specific attributes : check is some are found in the stream description otherwise copy the session description one(which are at least set to Invalid) */ + if (((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp))) { + attribute=belle_sdp_media_description_get_attribute(media_desc,"setup"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + if (strncmp(value, "actpass", 7) == 0) { + stream->dtls_role = SalDtlsRoleUnset; + } else if (strncmp(value, "active", 6) == 0) { + stream->dtls_role = SalDtlsRoleIsClient; + } else if (strncmp(value, "passive", 7) == 0) { + stream->dtls_role = SalDtlsRoleIsServer; + } + } + if (stream->dtls_role != SalDtlsRoleInvalid && (attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint"))) { + strncpy(stream->dtls_fingerprint, belle_sdp_attribute_get_value(attribute),sizeof(stream->dtls_fingerprint)); + } + } + + /* Read crypto lines if any */ + if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { + sdp_parse_media_crypto_parameters(media_desc, stream); + } + + /* Get ICE candidate attributes if any */ + sdp_parse_media_ice_parameters(media_desc, stream); + + /* Get RTCP-FB attributes if any */ + if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { + enable_avpf_for_stream(stream); + sdp_parse_rtcp_fb_parameters(media_desc, stream); + } + + /* Get RTCP-XR attributes if any */ + stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined + sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr); + + md->nb_streams++; + return stream; +} + + +int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { + belle_sdp_connection_t* cnx; + belle_sip_list_t* media_desc_it; + belle_sdp_media_description_t* media_desc; + belle_sdp_session_name_t *sname; + const char* value; + SalDtlsRole session_role=SalDtlsRoleInvalid; + int i; + + desc->nb_streams = 0; + desc->dir = SalStreamSendRecv; + + if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { + strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 ); + } + if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ + strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); + } + + if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { + desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ); + } + + /*in some very rare case, session attribute may set stream dir*/ + if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { + desc->dir=SalStreamSendRecv; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { + desc->dir=SalStreamSendOnly; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { + desc->dir=SalStreamRecvOnly; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { + desc->dir=SalStreamInactive; + } + + /*DTLS attributes can be defined at session level.*/ + value=belle_sdp_session_description_get_attribute_value(session_desc,"setup"); + if (value){ + if (strncmp(value, "actpass", 7) == 0) { + session_role = SalDtlsRoleUnset; + } else if (strncmp(value, "active", 6) == 0) { + session_role = SalDtlsRoleIsClient; + } else if (strncmp(value, "passive", 7) == 0) { + session_role = SalDtlsRoleIsServer; + } + } + value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint"); + /*copy dtls attributes to every streams, might be overwritten stream by stream*/ + for (i=0;istreams[i].dtls_fingerprint, value, sizeof(desc->streams[i].dtls_fingerprint)); + desc->streams[i].dtls_role=session_role; /*set or reset value*/ + } + + /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); + if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); + if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); + if (value) desc->ice_lite = TRUE; + + /* Get session RTCP-XR attributes if any */ + sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr); + + for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) + ; media_desc_it!=NULL + ; media_desc_it=media_desc_it->next ) { + if (desc->nb_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ + ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->nb_streams); + break; + } + media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); + sdp_to_stream_description(desc, media_desc); + } + return 0; +} diff --git a/coreapi/buffer.c b/coreapi/buffer.c new file mode 100644 index 000000000..9db65798e --- /dev/null +++ b/coreapi/buffer.c @@ -0,0 +1,106 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "private.h" + + + +static void linphone_buffer_destroy(LinphoneBuffer *buffer) { + if (buffer->content) belle_sip_free(buffer->content); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneBuffer); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneBuffer, belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_buffer_destroy, + NULL, // clone + NULL, // marshal + TRUE +); + + +LinphoneBuffer * linphone_buffer_new(void) { + LinphoneBuffer *buffer = belle_sip_object_new(LinphoneBuffer); + belle_sip_object_ref(buffer); + return buffer; +} + +LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size) { + LinphoneBuffer *buffer = linphone_buffer_new(); + linphone_buffer_set_content(buffer, data, size); + return buffer; +} + +LinphoneBuffer * linphone_buffer_new_from_string(const char *data) { + LinphoneBuffer *buffer = linphone_buffer_new(); + linphone_buffer_set_string_content(buffer, data); + return buffer; +} + +LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer) { + belle_sip_object_ref(buffer); + return buffer; +} + +void linphone_buffer_unref(LinphoneBuffer *buffer) { + belle_sip_object_unref(buffer); +} + +void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer) { + return buffer->user_data; +} + +void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud) { + buffer->user_data = ud; +} + +const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer) { + return buffer->content; +} + +void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size) { + buffer->size = size; + if (buffer->content) belle_sip_free(buffer->content); + buffer->content = belle_sip_malloc(size + 1); + memcpy(buffer->content, content, size); + ((char *)buffer->content)[size] = '\0'; +} + +const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer) { + return (const char *)buffer->content; +} + +void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content) { + buffer->size = strlen(content); + if (buffer->content) belle_sip_free(buffer->content); + buffer->content = (uint8_t *)belle_sip_strdup(content); +} + +size_t linphone_buffer_get_size(const LinphoneBuffer *buffer) { + return buffer->size; +} + +void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size) { + buffer->size = size; +} + +bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer) { + return (buffer->size == 0) ? TRUE : FALSE; +} diff --git a/coreapi/buffer.h b/coreapi/buffer.h new file mode 100644 index 000000000..0d22e9ad2 --- /dev/null +++ b/coreapi/buffer.h @@ -0,0 +1,147 @@ +/* +buffer.h +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef LINPHONE_BUFFER_H_ +#define LINPHONE_BUFFER_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup misc + * @{ + */ + +/** + * The LinphoneContent object representing a data buffer. +**/ +typedef struct _LinphoneBuffer LinphoneBuffer; + + +/** + * Create a new empty LinphoneBuffer object. + * @return A new LinphoneBuffer object. + */ +LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new(void); + +/** + * Create a new LinphoneBuffer object from existing data. + * @param[in] data The initial data to store in the LinphoneBuffer. + * @param[in] size The size of the initial data to stroe in the LinphoneBuffer. + * @return A new LinphoneBuffer object. + */ +LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size); + +/** + * Create a new LinphoneBuffer object from a string. + * @param[in] data The initial string content of the LinphoneBuffer. + * @return A new LinphoneBuffer object. + */ +LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_string(const char *data); + +/** + * Acquire a reference to the buffer. + * @param[in] buffer LinphoneBuffer object. + * @return The same LinphoneBuffer object. +**/ +LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer); + +/** + * Release reference to the buffer. + * @param[in] buffer LinphoneBuffer object. +**/ +LINPHONE_PUBLIC void linphone_buffer_unref(LinphoneBuffer *buffer); + +/** + * Retrieve the user pointer associated with the buffer. + * @param[in] buffer LinphoneBuffer object. + * @return The user pointer associated with the buffer. +**/ +LINPHONE_PUBLIC void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer); + +/** + * Assign a user pointer to the buffer. + * @param[in] buffer LinphoneBuffer object. + * @param[in] ud The user pointer to associate with the buffer. +**/ +LINPHONE_PUBLIC void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud); + +/** + * Get the content of the data buffer. + * @param[in] buffer LinphoneBuffer object. + * @return The content of the data buffer. + */ +LINPHONE_PUBLIC const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer); + +/** + * Set the content of the data buffer. + * @param[in] buffer LinphoneBuffer object. + * @param[in] content The content of the data buffer. + * @param[in] size The size of the content of the data buffer. + */ +LINPHONE_PUBLIC void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size); + +/** + * Get the string content of the data buffer. + * @param[in] buffer LinphoneBuffer object + * @return The string content of the data buffer. + */ +LINPHONE_PUBLIC const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer); + +/** + * Set the string content of the data buffer. + * @param[in] buffer LinphoneBuffer object. + * @param[in] content The string content of the data buffer. + */ +LINPHONE_PUBLIC void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content); + +/** + * Get the size of the content of the data buffer. + * @param[in] buffer LinphoneBuffer object. + * @return The size of the content of the data buffer. + */ +LINPHONE_PUBLIC size_t linphone_buffer_get_size(const LinphoneBuffer *buffer); + +/** + * Set the size of the content of the data buffer. + * @param[in] buffer LinphoneBuffer object + * @param[in] size The size of the content of the data buffer. + */ +LINPHONE_PUBLIC void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size); + +/** + * Tell whether the LinphoneBuffer is empty. + * @param[in] buffer LinphoneBuffer object + * @return A boolean value telling whether the LinphoneBuffer is empty or not. + */ +LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONE_CONTENT_H_ */ diff --git a/coreapi/call_log.c b/coreapi/call_log.c new file mode 100644 index 000000000..9d16e8511 --- /dev/null +++ b/coreapi/call_log.c @@ -0,0 +1,300 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define _XOPEN_SOURCE 700 /*required for strptime of GNU libc*/ + +#include +#include "private.h" + + +/******************************************************************************* + * Internal functions * + ******************************************************************************/ + +/*prevent a gcc bug with %c*/ +static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){ + return strftime(s, max, fmt, tm); +} + +static time_t string_to_time(const char *date){ +#ifndef _WIN32 + struct tm tmtime={0}; + strptime(date,"%c",&tmtime); + return mktime(&tmtime); +#else + return 0; +#endif +} + +static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){ + struct tm loctime; +#ifdef _WIN32 +#if !defined(_WIN32_WCE) + loctime=*localtime(&start_time); + /*FIXME*/ +#endif /*_WIN32_WCE*/ +#else + localtime_r(&start_time,&loctime); +#endif + my_strftime(cl->start_date,sizeof(cl->start_date),"%c",&loctime); +} + +/******************************************************************************* + * Private functions * + ******************************************************************************/ + +void call_logs_write_to_config_file(LinphoneCore *lc){ + MSList *elem; + char logsection[32]; + int i; + char *tmp; + LpConfig *cfg=lc->config; + + if (linphone_core_get_global_state (lc)==LinphoneGlobalStartup) return; + + for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){ + LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; + snprintf(logsection,sizeof(logsection),"call_log_%i",i); + lp_config_clean_section(cfg,logsection); + lp_config_set_int(cfg,logsection,"dir",cl->dir); + lp_config_set_int(cfg,logsection,"status",cl->status); + tmp=linphone_address_as_string(cl->from); + lp_config_set_string(cfg,logsection,"from",tmp); + ms_free(tmp); + tmp=linphone_address_as_string(cl->to); + lp_config_set_string(cfg,logsection,"to",tmp); + ms_free(tmp); + if (cl->start_date_time) + lp_config_set_int64(cfg,logsection,"start_date_time",(int64_t)cl->start_date_time); + else lp_config_set_string(cfg,logsection,"start_date",cl->start_date); + lp_config_set_int(cfg,logsection,"duration",cl->duration); + if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey); + lp_config_set_float(cfg,logsection,"quality",cl->quality); + lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled); + lp_config_set_string(cfg,logsection,"call_id",cl->call_id); + } + for(;imax_call_logs;++i){ + snprintf(logsection,sizeof(logsection),"call_log_%i",i); + lp_config_clean_section(cfg,logsection); + } +} + +void call_logs_read_from_config_file(LinphoneCore *lc){ + char logsection[32]; + int i; + const char *tmp; + uint64_t sec; + LpConfig *cfg=lc->config; + for(i=0;;++i){ + snprintf(logsection,sizeof(logsection),"call_log_%i",i); + if (lp_config_has_section(cfg,logsection)){ + LinphoneCallLog *cl; + LinphoneAddress *from=NULL,*to=NULL; + tmp=lp_config_get_string(cfg,logsection,"from",NULL); + if (tmp) from=linphone_address_new(tmp); + tmp=lp_config_get_string(cfg,logsection,"to",NULL); + if (tmp) to=linphone_address_new(tmp); + if (!from || !to) + continue; + cl=linphone_call_log_new(lp_config_get_int(cfg,logsection,"dir",0),from,to); + cl->status=lp_config_get_int(cfg,logsection,"status",0); + sec=lp_config_get_int64(cfg,logsection,"start_date_time",0); + if (sec) { + /*new call log format with date expressed in seconds */ + cl->start_date_time=(time_t)sec; + set_call_log_date(cl,cl->start_date_time); + }else{ + tmp=lp_config_get_string(cfg,logsection,"start_date",NULL); + if (tmp) { + strncpy(cl->start_date,tmp,sizeof(cl->start_date)); + cl->start_date_time=string_to_time(cl->start_date); + } + } + cl->duration=lp_config_get_int(cfg,logsection,"duration",0); + tmp=lp_config_get_string(cfg,logsection,"refkey",NULL); + if (tmp) cl->refkey=ms_strdup(tmp); + cl->quality=lp_config_get_float(cfg,logsection,"quality",-1); + cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0); + tmp=lp_config_get_string(cfg,logsection,"call_id",NULL); + if (tmp) cl->call_id=ms_strdup(tmp); + lc->call_logs=ms_list_append(lc->call_logs,cl); + }else break; + } +} + + +/******************************************************************************* + * Public functions * + ******************************************************************************/ + +const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl){ + return cl->call_id; +} + +LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){ + return cl->dir; +} + +int linphone_call_log_get_duration(LinphoneCallLog *cl){ + return cl->duration; +} + +LinphoneAddress *linphone_call_log_get_from_address(LinphoneCallLog *cl){ + return cl->from; +} + +const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl){ + return &cl->local_stats; +} + +float linphone_call_log_get_quality(LinphoneCallLog *cl){ + return cl->quality; +} + +const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){ + return cl->refkey; +} + +LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl){ + return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to; +} + +const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl){ + return &cl->remote_stats; +} + +time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){ + return cl->start_date_time; +} + +LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){ + return cl->status; +} + +LinphoneAddress *linphone_call_log_get_to_address(LinphoneCallLog *cl){ + return cl->to; +} + +void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){ + if (cl->refkey!=NULL){ + ms_free(cl->refkey); + cl->refkey=NULL; + } + if (refkey) cl->refkey=ms_strdup(refkey); +} + +char * linphone_call_log_to_str(LinphoneCallLog *cl){ + char *status; + char *tmp; + char *from=linphone_address_as_string (cl->from); + char *to=linphone_address_as_string (cl->to); + switch(cl->status){ + case LinphoneCallAborted: + status=_("aborted"); + break; + case LinphoneCallSuccess: + status=_("completed"); + break; + case LinphoneCallMissed: + status=_("missed"); + break; + default: + status=_("unknown"); + } + tmp=ms_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"), + (cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"), + cl->start_date, + from, + to, + status, + cl->duration/60, + cl->duration%60); + ms_free(from); + ms_free(to); + return tmp; +} + +bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) { + return cl->video_enabled; +} + + +/******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +void *linphone_call_log_get_user_data(const LinphoneCallLog *cl) { + return cl->user_data; +} + +void linphone_call_log_set_user_data(LinphoneCallLog *cl, void *ud) { + cl->user_data = ud; +} + +LinphoneCallLog * linphone_call_log_ref(LinphoneCallLog *cl) { + belle_sip_object_ref(cl); + return cl; +} + +void linphone_call_log_unref(LinphoneCallLog *cl) { + belle_sip_object_unref(cl); +} + +/******************************************************************************* + * Constructor and destructor functions * + ******************************************************************************/ + +static void _linphone_call_log_destroy(LinphoneCallLog *cl){ + if (cl->from!=NULL) linphone_address_destroy(cl->from); + if (cl->to!=NULL) linphone_address_destroy(cl->to); + if (cl->refkey!=NULL) ms_free(cl->refkey); + if (cl->call_id) ms_free(cl->call_id); + if (cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]); + if (cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]); +} + +LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress *to){ + LinphoneCallLog *cl=belle_sip_object_new(LinphoneCallLog); + cl->dir=dir; + cl->start_date_time=time(NULL); + set_call_log_date(cl,cl->start_date_time); + cl->from=from; + cl->to=to; + cl->status=LinphoneCallAborted; /*default status*/ + cl->quality=-1; + + cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); + cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); + cl->connected_date_time=0; + return cl; +} + +/* DEPRECATED */ +void linphone_call_log_destroy(LinphoneCallLog *cl) { + belle_sip_object_unref(cl); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallLog); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallLog, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_call_log_destroy, + NULL, // clone + NULL, // marshal + FALSE +); diff --git a/coreapi/call_log.h b/coreapi/call_log.h new file mode 100644 index 000000000..6a3ec8dab --- /dev/null +++ b/coreapi/call_log.h @@ -0,0 +1,244 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef __LINPHONE_CALL_LOG_H__ +#define __LINPHONE_CALL_LOG_H__ + +/** + * @addtogroup call_logs + * @{ +**/ + + +/******************************************************************************* + * Structures and enums * + ******************************************************************************/ + +/** + * Enum representing the direction of a call. +**/ +enum _LinphoneCallDir { + LinphoneCallOutgoing, /**< outgoing calls*/ + LinphoneCallIncoming /**< incoming calls*/ +}; + +/** + * Typedef for enum +**/ +typedef enum _LinphoneCallDir LinphoneCallDir; + +/** + * Enum representing the status of a call +**/ +typedef enum _LinphoneCallStatus { + LinphoneCallSuccess, /**< The call was sucessful */ + LinphoneCallAborted, /**< The call was aborted */ + LinphoneCallMissed, /**< The call was missed (unanswered) */ + LinphoneCallDeclined /**< The call was declined, either locally or by remote end */ +} LinphoneCallStatus; + +/** + * Structure representing a call log. +**/ +typedef struct _LinphoneCallLog LinphoneCallLog; + + +/******************************************************************************* + * Public functions * + ******************************************************************************/ + +/** + * Get the call ID used by the call. + * @param[in] cl LinphoneCallLog object + * @return The call ID used by the call as a string. +**/ +LINPHONE_PUBLIC const char * linphone_call_log_get_call_id(const LinphoneCallLog *cl); + +/** + * Get the direction of the call. + * @param[in] cl LinphoneCallLog object + * @return The direction of the call. +**/ +LINPHONE_PUBLIC LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl); + +/** + * Get the duration of the call since connected. + * @param[in] cl LinphoneCallLog object + * @return The duration of the call in seconds. +**/ +LINPHONE_PUBLIC int linphone_call_log_get_duration(LinphoneCallLog *cl); + +/** + * Get the origin address (ie from) of the call. + * @param[in] cl LinphoneCallLog object + * @return The origin address (ie from) of the call. +**/ +LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_from_address(LinphoneCallLog *cl); + +/** + * Get the RTP statistics computed locally regarding the call. + * @param[in] cl LinphoneCallLog object + * @return The RTP statistics that have been computed locally for the call. +**/ +LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_local_stats(const LinphoneCallLog *cl); + +/** + * Get the overall quality indication of the call. + * @param[in] cl LinphoneCallLog object + * @return The overall quality indication of the call. +**/ +LINPHONE_PUBLIC float linphone_call_log_get_quality(LinphoneCallLog *cl); + +/** + * Get the persistent reference key associated to the call log. + * + * The reference key can be for example an id to an external database. + * It is stored in the config file, thus can survive to process exits/restarts. + * + * @param[in] cl LinphoneCallLog object + * @return The reference key string that has been associated to the call log, or NULL if none has been associated. +**/ +LINPHONE_PUBLIC const char * linphone_call_log_get_ref_key(const LinphoneCallLog *cl); + +/** + * Get the remote address (that is from or to depending on call direction). + * @param[in] cl LinphoneCallLog object + * @return The remote address of the call. +**/ +LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_remote_address(LinphoneCallLog *cl); + +/** + * Get the RTP statistics computed by the remote end and sent back via RTCP. + * @note Not implemented yet. + * @param[in] cl LinphoneCallLog object + * @return The RTP statistics that have been computed by the remote end for the call. +**/ +LINPHONE_PUBLIC const rtp_stats_t * linphone_call_log_get_remote_stats(const LinphoneCallLog *cl); + +/** + * Get the start date of the call. + * @param[in] cl LinphoneCallLog object + * @return The date of the beginning of the call. +**/ +LINPHONE_PUBLIC time_t linphone_call_log_get_start_date(LinphoneCallLog *cl); + +/** + * Get the status of the call. + * @param[in] cl LinphoneCallLog object + * @return The status of the call. +**/ +LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl); + +/** + * Get the destination address (ie to) of the call. + * @param[in] cl LinphoneCallLog object + * @return The destination address (ie to) of the call. +**/ +LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_to_address(LinphoneCallLog *cl); + +/** + * Associate a persistent reference key to the call log. + * + * The reference key can be for example an id to an external database. + * It is stored in the config file, thus can survive to process exits/restarts. + * + * @param[in] cl LinphoneCallLog object + * @param[in] refkey The reference key string to associate to the call log. +**/ +LINPHONE_PUBLIC void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey); + +/** + * Tell whether video was enabled at the end of the call or not. + * @param[in] cl LinphoneCallLog object + * @return A boolean value telling whether video was enabled at the end of the call. +**/ +LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl); + +/** + * Get a human readable string describing the call. + * @note: the returned string must be freed by the application (use ms_free()). + * @param[in] cl LinphoneCallLog object + * @return A human readable string describing the call. +**/ +LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl); + + +/******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +/** + * Get the user data associated with the call log. + * @param[in] cl LinphoneCallLog object + * @return The user data associated with the call log. +**/ +LINPHONE_PUBLIC void *linphone_call_log_get_user_data(const LinphoneCallLog *cl); + +/** + * Assign a user data to the call log. + * @param[in] cl LinphoneCallLog object + * @param[in] ud The user data to associate with the call log. +**/ +LINPHONE_PUBLIC void linphone_call_log_set_user_data(LinphoneCallLog *cl, void *ud); + +/** + * Acquire a reference to the call log. + * @param[in] cl LinphoneCallLog object + * @return The same LinphoneCallLog object +**/ +LINPHONE_PUBLIC LinphoneCallLog * linphone_call_log_ref(LinphoneCallLog *cl); + +/** + * Release a reference to the call log. + * @param[in] cl LinphoneCallLog object +**/ +LINPHONE_PUBLIC void linphone_call_log_unref(LinphoneCallLog *cl); + + +/******************************************************************************* + * DEPRECATED * + ******************************************************************************/ + +/** @deprecated Use linphone_call_log_get_from_address() instead. */ +#define linphone_call_log_get_from(cl) linphone_call_log_get_from_address(cl) + +/** @deprecated Use linphone_call_log_get_to_address() instead. */ +#define linphone_call_log_get_to(cl) linphone_call_log_get_to_address(cl) + +/** @deprecated Use linphone_call_log_set_user_data() instead. */ +#define linphone_call_log_set_user_pointer(cl, ud) linphone_call_log_set_user_data(cl, ud) + +/** @deprecated Use linphone_call_log_get_user_data() instead. */ +#define linphone_call_log_get_user_pointer(cl) linphone_call_log_get_user_data(cl) + +/** + * Destroy a LinphoneCallLog. + * @param cl LinphoneCallLog object + * @deprecated Use linphone_call_log_unref() instead. + */ +LINPHONE_PUBLIC void linphone_call_log_destroy(LinphoneCallLog *cl); + + +/** + * @} +**/ + + +#endif /* __LINPHONE_CALL_LOG_H__ */ diff --git a/coreapi/call_params.c b/coreapi/call_params.c new file mode 100644 index 000000000..f9a1a1a4d --- /dev/null +++ b/coreapi/call_params.c @@ -0,0 +1,284 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" + + +/******************************************************************************* + * Internal functions * + ******************************************************************************/ + +SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { + if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf; + if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; + if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf; + if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp; + if (params->avpf_enabled) return SalProtoRtpAvpf; + return SalProtoRtpAvp; +} + +SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { + switch (cpdir) { + case LinphoneMediaDirectionInactive: + return SalStreamInactive; + case LinphoneMediaDirectionSendOnly: + return SalStreamSendOnly; + case LinphoneMediaDirectionRecvOnly: + return SalStreamRecvOnly; + case LinphoneMediaDirectionSendRecv: + return SalStreamSendRecv; + case LinphoneMediaDirectionInvalid: + ms_error("LinphoneMediaDirectionInvalid shall not be used."); + return SalStreamInactive; + } + return SalStreamSendRecv; +} + +LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir){ + switch (dir) { + case SalStreamInactive: + return LinphoneMediaDirectionInactive; + case SalStreamSendOnly: + return LinphoneMediaDirectionSendOnly; + case SalStreamRecvOnly: + return LinphoneMediaDirectionRecvOnly; + case SalStreamSendRecv: + return LinphoneMediaDirectionSendRecv; + } + return LinphoneMediaDirectionSendRecv; +} + +SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params) { + return sal_dir_from_call_params_dir(linphone_call_params_get_audio_direction(params)); +} + +SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) { + return sal_dir_from_call_params_dir(linphone_call_params_get_video_direction(params)); +} + + +/******************************************************************************* + * Public functions * + ******************************************************************************/ + +void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){ + params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value); +} + +LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){ + LinphoneCallParams *ncp=linphone_call_params_new(); + memcpy(ncp,cp,sizeof(LinphoneCallParams)); + if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file); + if (cp->session_name) ncp->session_name=ms_strdup(cp->session_name); + /* + * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. + */ + if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); + + return ncp; +} + +bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){ + return cp->real_early_media; +} + +void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){ + cp->real_early_media=enabled; +} + +void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){ + cp->low_bandwidth=enabled; +} + +void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){ + cp->has_video=enabled; + if (enabled && cp->video_dir==LinphoneMediaDirectionInactive) + cp->video_dir=LinphoneMediaDirectionSendRecv; +} + +const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){ + return sal_custom_header_find(params->custom_headers,header_name); +} + +bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp){ + return cp->in_conference; +} + +LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { + return cp->media_encryption; +} + +LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { + return params->privacy; +} + +float linphone_call_params_get_received_framerate(const LinphoneCallParams *cp){ + return cp->received_fps; +} + +MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp) { + return cp->recv_vsize; +} + +const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){ + return cp->record_file; +} + +const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp) { + return sal_media_proto_to_string(get_proto_from_call_params(cp)); +} + +float linphone_call_params_get_sent_framerate(const LinphoneCallParams *cp){ + return cp->sent_fps; +} + +MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp) { + return cp->sent_vsize; +} + +const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){ + return cp->session_name; +} + +const LinphonePayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) { + return cp->audio_codec; +} + +const LinphonePayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) { + return cp->video_codec; +} + +bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) { + return cp->low_bandwidth; +} + +void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){ + cp->audio_bw=bandwidth; +} + +void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e) { + cp->media_encryption = e; +} + +void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { + params->privacy=privacy; +} + +void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){ + if (cp->record_file){ + ms_free(cp->record_file); + cp->record_file=NULL; + } + if (path) cp->record_file=ms_strdup(path); +} + +void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){ + if (cp->session_name){ + ms_free(cp->session_name); + cp->session_name=NULL; + } + if (name) cp->session_name=ms_strdup(name); +} + +bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ + return cp->has_video; +} + +LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp) { + return cp->audio_dir; +} + +LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp) { + return cp->video_dir; +} + +void linphone_call_params_set_audio_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) { + cp->audio_dir=dir; +} + +void linphone_call_params_set_video_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) { + cp->video_dir=dir; +} + + +/******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +void *linphone_call_params_get_user_data(const LinphoneCallParams *cp) { + return cp->user_data; +} + +void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud) { + cp->user_data = ud; +} + +LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp) { + belle_sip_object_ref(cp); + return cp; +} + +void linphone_call_params_unref(LinphoneCallParams *cp) { + belle_sip_object_unref(cp); +} + +void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) { + params->audio_multicast_enabled=yesno; +} + +bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) { + return params->audio_multicast_enabled; +} + +void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) { + params->video_multicast_enabled=yesno; +} +bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) { + return params->video_multicast_enabled; +} + +/******************************************************************************* + * Constructor and destructor functions * + ******************************************************************************/ + +static void _linphone_call_params_destroy(LinphoneCallParams *cp){ + if (cp->record_file) ms_free(cp->record_file); + if (cp->custom_headers) sal_custom_header_free(cp->custom_headers); +} + +LinphoneCallParams * linphone_call_params_new(void) { + LinphoneCallParams *cp=belle_sip_object_new(LinphoneCallParams); + cp->audio_dir=LinphoneMediaDirectionSendRecv; + cp->video_dir=LinphoneMediaDirectionSendRecv; + return cp; +} + +/* DEPRECATED */ +void linphone_call_params_destroy(LinphoneCallParams *cp) { + linphone_call_params_unref(cp); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallParams); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallParams, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_call_params_destroy, + NULL, // clone + NULL, // marshal + FALSE +); diff --git a/coreapi/call_params.h b/coreapi/call_params.h new file mode 100644 index 000000000..a45eb8999 --- /dev/null +++ b/coreapi/call_params.h @@ -0,0 +1,381 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef __LINPHONE_CALL_PARAMS_H__ +#define __LINPHONE_CALL_PARAMS_H__ + +/** + * @addtogroup call_control + * @{ +**/ + + +/******************************************************************************* + * Structures and enums * + ******************************************************************************/ +/** + * Indicates for a given media the stream direction + * */ +enum _LinphoneMediaDirection { + LinphoneMediaDirectionInvalid = -1, + LinphoneMediaDirectionInactive, /** No active media not supported yet*/ + LinphoneMediaDirectionSendOnly, /** Send only mode*/ + LinphoneMediaDirectionRecvOnly, /** recv only mode*/ + LinphoneMediaDirectionSendRecv, /** send receive*/ +}; +/** + * Typedef for enum +**/ +typedef enum _LinphoneMediaDirection LinphoneMediaDirection; + +/** + * Private structure definition for LinphoneCallParams. +**/ +struct _LinphoneCallParams; + +/** + * The LinphoneCallParams is an object containing various call related parameters. + * It can be used to retrieve parameters from a currently running call or modify + * the call's characteristics dynamically. +**/ +typedef struct _LinphoneCallParams LinphoneCallParams; + + +/******************************************************************************* + * Public functions * + ******************************************************************************/ + +/** + * Add a custom SIP header in the INVITE for a call. + * @param[in] cp The #LinphoneCallParams to add a custom SIP header to. + * @param[in] header_name The name of the header to add. + * @param[in] header_value The content of the header to add. +**/ +LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *cp, const char *header_name, const char *header_value); + +/** + * Copy an existing LinphoneCallParams object to a new LinphoneCallParams object. + * @param[in] cp The LinphoneCallParams object to copy. + * @return A copy of the LinphoneCallParams object. +**/ +LINPHONE_PUBLIC LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp); + +/** + * Indicate whether sending of early media was enabled. + * @param[in] cp LinphoneCallParams object + * @return A boolean value telling whether sending of early media was enabled. +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp); + +/** + * Enable sending of real early media (during outgoing calls). + * @param[in] cp LinphoneCallParams object + * @param[in] enabled A boolean value telling whether to enable early media sending or not. +**/ +LINPHONE_PUBLIC void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled); + +/** + * Indicate low bandwith mode. + * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage + * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided + * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled. + * @param[in] cp LinphoneCallParams object + * @param[in] enabled A boolean value telling whether to activate the low bandwidth mode or not. +**/ +LINPHONE_PUBLIC void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); + +/** + * Enable video stream. + * @param[in] cp LinphoneCallParams object + * @param[in] enabled A boolean value telling whether to enable video or not. +**/ +LINPHONE_PUBLIC void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); + +/** + * Get a custom SIP header. + * @param[in] cp The #LinphoneCallParams to get the custom SIP header from. + * @param[in] header_name The name of the header to get. + * @return The content of the header or NULL if not found. +**/ +LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *cp, const char *header_name); + +/** + * Tell whether the call is part of the locally managed conference. + * @param[in] cp LinphoneCallParams object + * @return A boolean value telling whether the call is part of the locally managed conference. +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp); + +/** + * Get the kind of media encryption selected for the call. + * @param[in] cp LinphoneCallParams object + * @return The kind of media encryption selected for the call. +**/ +LINPHONE_PUBLIC LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp); + +/** + * Get requested level of privacy for the call. + * @param[in] cp LinphoneCallParams object + * @return The privacy mode used for the call. +**/ +LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *cp); + +/** + * Get the framerate of the video that is received. + * @param[in] cp LinphoneCallParams object + * @return The actual received framerate in frames per seconds, 0 if not available. + */ +LINPHONE_PUBLIC float linphone_call_params_get_received_framerate(const LinphoneCallParams *cp); + +/** + * Get the size of the video that is received. + * @param[in] cp LinphoneCallParams object + * @return The received video size or MS_VIDEO_SIZE_UNKNOWN if not available. + */ +LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp); + +/** + * Get the path for the audio recording of the call. + * @param[in] cp LinphoneCallParams object + * @return The path to the audio recording of the call. +**/ +LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); + +/** + * Get the RTP profile being used. + * @param[in] cp #LinphoneCallParams object + * @return The RTP profile. + */ +LINPHONE_PUBLIC const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp); + +/** + * Get the framerate of the video that is sent. + * @param[in] cp LinphoneCallParams object + * @return The actual sent framerate in frames per seconds, 0 if not available. + */ +LINPHONE_PUBLIC float linphone_call_params_get_sent_framerate(const LinphoneCallParams *cp); + +/** + * Gets the size of the video that is sent. + * @param[in] cp LinphoneCalParams object + * @return The sent video size or MS_VIDEO_SIZE_UNKNOWN if not available. + */ +LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp); + +/** + * Get the session name of the media session (ie in SDP). + * Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header() and is different. + * @param[in] cp LinphoneCallParams object + * @return The session name of the media session. +**/ +LINPHONE_PUBLIC const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp); + +/** + * Get the audio codec used in the call, described as a LinphonePayloadType object. + * @param[in] cp LinphoneCallParams object + * @return The LinphonePayloadType object corresponding to the audio codec being used in the call. +**/ +LINPHONE_PUBLIC const LinphonePayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp); + +/** + * Get the video codec used in the call, described as a LinphonePayloadType structure. + * @param[in] cp LinphoneCallParams object + * @return The LinphonePayloadType object corresponding to the video codec being used in the call. +**/ +LINPHONE_PUBLIC const LinphonePayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp); + +/** + * Tell whether the call has been configured in low bandwidth mode or not. + * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file. + * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure + * low bandwidth mode with linphone_call_params_enable_low_bandwidth(). + * When enabled, this param may transform a call request with video in audio only mode. + * @param[in] cp LinphoneCallParams object + * @return A boolean value telling whether the low bandwidth mode has been configured/detected. + */ +LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp); + +/** + * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams. + * As a consequence, codecs whose bitrates are not compatible with this limit won't be used. + * @param[in] cp LinphoneCallParams object + * @param[in] bw The audio bandwidth limit to set in kbit/s. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw); + +/** + * Set requested media encryption for a call. + * @param[in] cp LinphoneCallParams object + * @param[in] enc The media encryption to use for the call. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption enc); + +/** + * Set requested level of privacy for the call. + * \xmlonly javascript \endxmlonly + * @param[in] cp LinphoneCallParams object + * @param[in] privacy The privacy mode to used for the call. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); + +/** + * Enable recording of the call. + * This function must be used before the call parameters are assigned to the call. + * The call recording can be started and paused after the call is established with + * linphone_call_start_recording() and linphone_call_pause_recording(). + * @param[in] cp LinphoneCallParams object + * @param[in] path A string containing the path and filename of the file where audio/video streams are to be written. + * The filename must have either .mkv or .wav extention. The video stream will be written only if a MKV file is given. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path); + +/** + * Set the session name of the media session (ie in SDP). + * Subject from the SIP message (which is different) can be set using linphone_call_params_set_custom_header(). + * @param[in] cp LinphoneCallParams object + * @param[in] name The session name to be used. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name); + +/** + * Tell whether video is enabled or not. + * @param[in] cp LinphoneCallParams object + * @return A boolean value telling whether video is enabled or not. +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp); + +/** + * Get the audio stream direction. + * @param[in] cl LinphoneCallParams object + * @return The audio stream direction associated with the call params. +**/ +LINPHONE_PUBLIC LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp); + +/** + * Get the video stream direction. + * @param[in] cl LinphoneCallParams object + * @return The video stream direction associated with the call params. +**/ +LINPHONE_PUBLIC LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp); + +/** + * Set the audio stream direction. Only relevant for multicast + * @param[in] cl LinphoneCallParams object + * @param[in] The audio stream direction associated with this call params. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_audio_direction(LinphoneCallParams *cp, LinphoneMediaDirection dir); + +/** + * Set the video stream direction. Only relevant for multicast + * @param[in] cl LinphoneCallParams object + * @param[in] The video stream direction associated with this call params. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_video_direction(LinphoneCallParams *cp, LinphoneMediaDirection dir); + + +/******************************************************************************* + * Reference and user data handling functions * + ******************************************************************************/ + +/** + * Get the user data associated with the call params. + * @param[in] cl LinphoneCallParams object + * @return The user data associated with the call params. +**/ +LINPHONE_PUBLIC void *linphone_call_params_get_user_data(const LinphoneCallParams *cp); + +/** + * Assign a user data to the call params. + * @param[in] cl LinphoneCallParams object + * @param[in] ud The user data to associate with the call params. +**/ +LINPHONE_PUBLIC void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud); + +/** + * Acquire a reference to the call params. + * @param[in] cl LinphoneCallParams object + * @return The same LinphoneCallParams object +**/ +LINPHONE_PUBLIC LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp); + +/** + * Release a reference to the call params. + * @param[in] cl LinphoneCallParams object +**/ +LINPHONE_PUBLIC void linphone_call_params_unref(LinphoneCallParams *cp); + + +/** + * Use to enable multicast rtp for audio stream. + * * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into audio cline. In case of outgoing call audio stream is sent to this multicast address. + *
For incoming calls behavior is unchanged. + * @param core #LinphoneCallParams + * @param yesno if yes, subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_call_params_enable_audio_multicast(LinphoneCallParams *param, bool_t yesno); + +/** + * Use to get multicast state of audio stream. + * @param core #LinphoneCallParams + * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *param); + +/** + * Use to enable multicast rtp for video stream. + * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address. + *
For incoming calls behavior is unchanged. + * @param core #LinphoneCallParams + * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by #linphone_core_set_video_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_call_params_enable_video_multicast(LinphoneCallParams *param, bool_t yesno); +/** + * Use to get multicast state of video stream. + * @param core #LinphoneCallParams + * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_video_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *param); + + +/******************************************************************************* + * DEPRECATED * + ******************************************************************************/ + +/** @deprecated Use linphone_call_params_get_local_conference_mode() instead. */ +#define linphone_call_params_local_conference_mode linphone_call_params_get_local_conference_mode + +/** + * Destroy a LinphoneCallParams object. + * @param[in] cp LinphoneCallParams object + * @deprecated Use linphone_call_params_unref() instead. +**/ +LINPHONE_PUBLIC void linphone_call_params_destroy(LinphoneCallParams *cp); + + +/** + * @} +**/ + + +#endif /* __LINPHONE_CALL_PARAMS_H__ */ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cf2b5cb4a..5ce07dd3c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -25,30 +25,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "lpconfig.h" -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); +// stat +#ifndef _WIN32 +#include +#include +#include +#endif + +static void register_failure(SalOp *op); static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { - if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; - if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; - return sal_media_description_equals(oldmd, newmd); + int result=0; + if (call->params->in_conference != call->current_params->in_conference) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; + if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION; + if (call->localdesc_changed) ms_message("Local description has changed: %i", call->localdesc_changed); + result = call->localdesc_changed | sal_media_description_equals(oldmd, newmd); + return result; } 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++) { + for (i = 0; i < new_md->nb_streams; i++) { + if (!sal_stream_description_active(&new_md->streams[i])) continue; if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; } else if (new_md->streams[i].type == SalVideo) { @@ -59,110 +61,156 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->audiostream->ms.session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); } #ifdef VIDEO_ENABLED if (call->videostream && new_videodesc) { rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); } +#else + (void)new_videodesc; #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; +static void _clear_early_media_destinations(LinphoneCall *call, MediaStream *ms){ + RtpSession *session=ms->sessions.rtp_session; + rtp_session_clear_aux_remote_addr(session); + if (!call->ice_session) rtp_session_set_symmetric_rtp(session,linphone_core_symmetric_rtp_enabled(call->core));/*restore symmetric rtp if ICE is not used*/ +} + +static void clear_early_media_destinations(LinphoneCall *call){ + if (call->audiostream){ + _clear_early_media_destinations(call,(MediaStream*)call->audiostream); } - 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; + if (call->videostream){ + _clear_early_media_destinations(call,(MediaStream*)call->videostream); } } -void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ +static void prepare_early_media_forking(LinphoneCall *call){ + /*we need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations*/ + if (call->audiostream){ + rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session,FALSE); + } + if (call->videostream){ + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE); + } +} + +void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescription *result_desc){ + SalMediaDescription *local=call->localdesc; + int i; + for(i=0;inb_streams;++i){ + MSList *elem; + for (elem=result_desc->streams[i].payloads;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if (is_payload_type_number_available(local->streams[i].already_assigned_payloads, payload_type_get_number(pt), NULL)){ + /*new codec, needs to be added to the list*/ + local->streams[i].already_assigned_payloads=ms_list_append(local->streams[i].already_assigned_payloads, payload_type_clone(pt)); + ms_message("LinphoneCall[%p] : payload type %i %s/%i fmtp=%s added to frozen list.", + call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : ""); + } + } + } +} + +void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state){ SalMediaDescription *oldmd=call->resultdesc; - - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; + int md_changed=0; + + + if (!((call->state == LinphoneCallIncomingEarlyMedia) && (linphone_core_get_ring_during_incoming_early_media(lc)))) { + linphone_core_stop_ringing(lc); } - if (new_md!=NULL){ - sal_media_description_ref(new_md); - call->media_pending=FALSE; - }else{ - call->media_pending=TRUE; + if (!new_md) { + ms_error("linphone_core_update_streams() called with null media description"); + return; } + if (call->biggestdesc==NULL || new_md->nb_streams>call->biggestdesc->nb_streams){ + /*we have been offered and now are ready to proceed, or we added a new stream*/ + /*store the media description to remember the mapping of calls*/ + if (call->biggestdesc){ + sal_media_description_unref(call->biggestdesc); + call->biggestdesc=NULL; + } + if (sal_call_is_offerer(call->op)) + call->biggestdesc=sal_media_description_ref(call->localdesc); + else + call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op)); + } + sal_media_description_ref(new_md); call->resultdesc=new_md; - if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){ + if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){ + clear_early_media_destinations(call); + /* we already started media: check if we really need to restart it*/ if (oldmd){ - int md_changed = media_parameters_changed(call, oldmd, new_md); - if ((md_changed & SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) || call->playing_ringbacktone) { + md_changed = media_parameters_changed(call, oldmd, new_md); + if ((md_changed & ( SAL_MEDIA_DESCRIPTION_CODEC_CHANGED + |SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED + |SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED + |SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION ))){ ms_message("Media descriptions are different, need to restart the streams."); + } else if ( call->playing_ringbacktone) { + ms_message("Playing ringback tone, will 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 ); + if (call->videostream && call->camera_enabled) + video_stream_change_camera(call->videostream,linphone_call_get_video_device(call)); #endif } + /*FIXME ZRTP, might be restarted in any cases ? */ 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); } - if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) { + if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) { 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); + if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){ + ms_message("Media ip type has changed, destroying sessions context on call [%p]",call); + ms_media_stream_sessions_uninit(&call->sessions[0]); + ms_media_stream_sessions_uninit(&call->sessions[1]); + } linphone_call_init_media_streams (call); } - if (oldmd) - sal_media_description_unref(oldmd); - - if (new_md) { - bool_t all_muted=FALSE; - bool_t send_ringbacktone=FALSE; - - if (call->audiostream==NULL){ - /*this happens after pausing the call locally. The streams is destroyed and then we wait the 200Ok to recreate it*/ - linphone_call_init_media_streams (call); - } - if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ - send_ringbacktone=TRUE; - } - if (call->state==LinphoneCallIncomingEarlyMedia || - (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ - all_muted=TRUE; - } - linphone_call_start_media_streams(call,all_muted,send_ringbacktone); + + if (call->audiostream==NULL){ + /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ + linphone_call_init_media_streams (call); } + + if (call->params->real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){ + prepare_early_media_forking(call); + } + linphone_call_start_media_streams(call, target_state); + if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ + linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); + } + linphone_call_update_frozen_payloads(call, new_md); + end: + if (oldmd) + sal_media_description_unref(oldmd); + } #if 0 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ @@ -170,7 +218,7 @@ static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, c for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; if (linphone_address_weak_equal(call->log->from,from) && - linphone_address_weak_equal(call->log->to, to)){ + linphone_address_weak_equal(call->log->to, to)){ return TRUE; } } @@ -180,7 +228,7 @@ static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, c 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."); + ms_message("Searching for already_a_call_with_remote_address."); for(elem=lc->calls;elem!=NULL;elem=elem->next){ const LinphoneCall *call=(LinphoneCall*)elem->data; @@ -193,69 +241,111 @@ static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const L return FALSE; } -static bool_t already_a_call_pending(LinphoneCore *lc){ - MSList *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - if (call->state==LinphoneCallIncomingReceived - || call->state==LinphoneCallOutgoingInit - || call->state==LinphoneCallOutgoingProgress - || call->state==LinphoneCallOutgoingEarlyMedia - || call->state==LinphoneCallOutgoingRinging){ - return TRUE; - } - } - return FALSE; -} static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call; - const char *from,*to; - LinphoneAddress *from_addr, *to_addr; - bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE); - + char *alt_contact; + LinphoneAddress *from_addr=NULL; + LinphoneAddress *to_addr=NULL; + LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/ + SalMediaDescription *md; + const char * p_asserted_id; + /* 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); return; } - from=sal_op_get_from(h); - to=sal_op_get_to(h); - from_addr=linphone_address_new(from); - to_addr=linphone_address_new(to); + p_asserted_id = sal_custom_header_find(sal_op_get_recv_custom_header(h),"P-Asserted-Identity"); + /*in some situation, better to trust the network rather than the UAC*/ + if (lp_config_get_int(lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) { + LinphoneAddress *p_asserted_id_addr; + if (!p_asserted_id) { + ms_warning("No P-Asserted-Identity header found so cannot use it for op [%p] instead of from",h); + } else { + p_asserted_id_addr = linphone_address_new(p_asserted_id); + if (!p_asserted_id_addr) { + ms_warning("Unsupported P-Asserted-Identity header for op [%p] ",h); + } else { + ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]",p_asserted_id,sal_op_get_from(h),h); + from_addr=p_asserted_id_addr; + } + } + } - if ((already_a_call_with_remote_address(lc,from_addr) && prevent_colliding_calls) || already_a_call_pending(lc)){ - ms_warning("Receiving another call while one is ringing or initiated, refusing this one with busy message."); + if (!from_addr) + from_addr=linphone_address_new(sal_op_get_from(h)); + to_addr=linphone_address_new(sal_op_get_to(h)); + + if (sal_op_get_privacy(h) == SalPrivacyNone) { + from_address_to_search_if_me=linphone_address_clone(from_addr); + } else if (p_asserted_id) { + from_address_to_search_if_me = linphone_address_new(p_asserted_id); + } else { + ms_warning ("Hidden from identity, don't know if it's me"); + } + + if (from_address_to_search_if_me && already_a_call_with_remote_address(lc,from_address_to_search_if_me)){ + char *addr = linphone_address_as_string(from_addr); + ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr); sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); linphone_address_destroy(from_addr); linphone_address_destroy(to_addr); + linphone_address_destroy(from_address_to_search_if_me); + ms_free(addr); return; + } else if (from_address_to_search_if_me) { + linphone_address_destroy(from_address_to_search_if_me); } - + call=linphone_call_new_incoming(lc,from_addr,to_addr,h); - + + linphone_call_make_local_media_description(call); + sal_call_set_local_media_description(call->op,call->localdesc); + md=sal_call_get_final_media_description(call->op); + if (md){ + if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); + linphone_call_unref(call); + return; + } + } + /* the call is acceptable so we can now add it to our list */ linphone_core_add_call(lc,call); linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ + call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) { /* Defer ringing until the end of the ICE candidates gathering process. */ ms_message("Defer ringing to gather ICE candidates"); @@ -272,56 +362,236 @@ static void call_received(SalOp *h){ linphone_core_notify_incoming_call(lc,call); } +static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md){ + SalMediaDescription *cur_md=call->resultdesc; + int i; + SalStreamDescription *ref_stream,*new_stream; + ms_message("Early media response received from another branch, checking if media can be forked to this new destination."); + + for (i=0;inb_streams;++i){ + if (!sal_stream_description_active(&cur_md->streams[i])) continue; + ref_stream=&cur_md->streams[i]; + new_stream=&md->streams[i]; + if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){ + PayloadType *refpt, *newpt; + refpt=(PayloadType*)ref_stream->payloads->data; + newpt=(PayloadType*)new_stream->payloads->data; + if (strcmp(refpt->mime_type,newpt->mime_type)==0 && refpt->clock_rate==newpt->clock_rate + && payload_type_get_number(refpt)==payload_type_get_number(newpt)){ + MediaStream *ms=NULL; + if (ref_stream->type==SalAudio){ + ms=(MediaStream*)call->audiostream; + }else if (ref_stream->type==SalVideo){ + ms=(MediaStream*)call->videostream; + } + if (ms){ + RtpSession *session=ms->sessions.rtp_session; + const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr; + const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr; + if (ms_is_multicast(rtp_addr)) + ms_message("Multicast addr [%s/%i] does not need auxiliary rtp's destination for call [%p]", + rtp_addr,new_stream->rtp_port,call); + else + rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port); + } + } + } + } +} + +static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) { + 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); + /*we release sound before playing ringback tone*/ + if (call->audiostream) + audio_stream_unprepare_sound(call->audiostream); + if( lc->sound_conf.remote_ring ){ + lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); + } + } +} + static void call_ringing(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); SalMediaDescription *md; - + if (call==NULL) return; - - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Remote ringing.")); - + + /*set privacy*/ + call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + + linphone_core_notify_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 !*/ - 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); - /*we release sound before playing ringback tone*/ - if (call->audiostream) - audio_stream_unprepare_sound(call->audiostream); - lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); + linphone_core_stop_dtmf_stream(lc); + if (call->state==LinphoneCallOutgoingEarlyMedia){ + /*already doing early media */ + return; } + if (lc->ringstream!=NULL) return;/*already ringing !*/ + start_remote_ring(lc, call); ms_message("Remote ringing..."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Remote ringing...")); + linphone_core_notify_display_status(lc,_("Remote ringing...")); linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing"); }else{ /*accept early media */ - if (call->audiostream && audio_stream_started(call->audiostream)){ + if ((call->audiostream && audio_stream_started(call->audiostream)) +#ifdef VIDEO_ENABLED + || (call->videostream && video_stream_started(call->videostream)) +#endif + ) { /*streams already started */ - ms_message("Early media already started."); - return; + try_early_media_forking(call,md); + #ifdef VIDEO_ENABLED + if (call->videostream){ + /*just request for iframe*/ + video_stream_send_vfu(call->videostream); + } + #endif + return; } - if (lc->vtable.show) lc->vtable.show(lc); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Early media.")); + + linphone_core_notify_show_interface(lc); + linphone_core_notify_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); + linphone_core_update_streams(lc,call,md, call->state); + if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) { + if (lc->ringstream != NULL) return; /* Already ringing! */ + start_remote_ring(lc, call); + } } } +static void start_pending_refer(LinphoneCall *call){ + linphone_core_start_refered_call(call->core, call,NULL); +} + +static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *op){ + SalMediaDescription *md, *rmd; + LinphoneCallState next_state = LinphoneCallIdle; + const char *next_state_str = NULL; + LinphoneTaskList tl; + + switch (call->state){/*immediately notify the connected state, even if errors occur after*/ + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + /*immediately notify the connected state*/ + linphone_call_set_state(call,LinphoneCallConnected,"Connected"); + { + char *tmp=linphone_call_get_remote_address_as_string (call); + char *msg=ms_strdup_printf(_("Call answered by %s"),tmp); + linphone_core_notify_display_status(lc,msg); + ms_free(tmp); + ms_free(msg); + } + break; + default: + break; + } + + linphone_task_list_init(&tl); + rmd=sal_call_get_remote_media_description(op); + /*set privacy*/ + call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + /*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/ + if (call->params->internal_call_update) + call->params->internal_call_update = FALSE; + + /* Handle remote ICE attributes if any. */ + if (call->ice_session != NULL && rmd) { + linphone_call_update_ice_from_remote_media_description(call, rmd); + } +#ifdef BUILD_UPNP + if (call->upnp_session != NULL && rmd) { + linphone_core_update_upnp_from_remote_media_description(call, rmd); + } +#endif //BUILD_UPNP + + md=sal_call_get_final_media_description(op); + if (md == NULL && call->prevstate == LinphoneCallOutgoingEarlyMedia && call->resultdesc != NULL){ + ms_message("Using early media SDP since none was received with the 200 OK"); + md = call->resultdesc; + } + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ + md = NULL; + } + if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/ + switch (call->state){ + case LinphoneCallResuming: + linphone_core_notify_display_status(lc,_("Call resumed.")); + /*intentionally no break*/ + case LinphoneCallConnected: + if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call); + /*intentionally no break*/ + case LinphoneCallUpdating: + case LinphoneCallUpdatedByRemote: + if (!sal_media_description_has_dir(call->localdesc, SalStreamInactive) && + (sal_media_description_has_dir(md,SalStreamRecvOnly) || + sal_media_description_has_dir(md,SalStreamInactive))){ + next_state = LinphoneCallPausedByRemote; + next_state_str = "Call paused by remote"; + }else{ + if (!call->current_params->in_conference) + lc->current_call=call; + next_state = LinphoneCallStreamsRunning; + next_state_str = "Streams running"; + } + break; + case LinphoneCallEarlyUpdating: + next_state_str = "Early update accepted"; + next_state = call->prevstate; + break; + case LinphoneCallPausing: + /*when we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is. + Our streams are all send-only (with music), soundcard and camera are never used*/ + next_state = LinphoneCallPaused; + next_state_str = "Call paused"; + if (call->refer_pending) + linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call); + break; + default: + ms_error("call_accepted(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state)); + break; + } + + if (next_state != LinphoneCallIdle){ + linphone_call_update_remote_session_id_and_ver(call); + linphone_core_update_ice_state_in_call_stats(call); + linphone_core_update_streams(lc, call, md, next_state); + linphone_call_fix_call_parameters(call); + linphone_call_set_state(call, next_state, next_state_str); + }else{ + ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state)); + } + }else{ /*invalid or no SDP*/ + switch (call->prevstate){ + /*send a bye only in case of early states*/ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + ms_error("Incompatible SDP answer received, need to abort the call"); + linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings...")); + break; + /*otherwise we are able to resume previous state*/ + default: + ms_message("Incompatible SDP answer received, restoring previous state [%s]",linphone_call_state_to_string(call->prevstate)); + linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters.")); + break; + } + } + linphone_task_list_run(&tl); + linphone_task_list_free(&tl); +} + /* * could be reach : * - when the call is accepted @@ -330,182 +600,159 @@ static void call_ringing(SalOp *h){ static void call_accepted(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - SalMediaDescription *md; - if (call==NULL){ - ms_warning("No call to accept."); + if (call == NULL){ + ms_warning("call_accepted: call does no longer exist."); return ; } - - /* Handle remote ICE attributes if any. */ - if (call->ice_session != NULL) { - linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - } -#ifdef BUILD_UPNP - if (call->upnp_session != NULL) { - linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - } -#endif //BUILD_UPNP - - md=sal_call_get_final_media_description(op); - call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - - if (call->state==LinphoneCallOutgoingProgress || - call->state==LinphoneCallOutgoingRinging || - call->state==LinphoneCallOutgoingEarlyMedia){ - linphone_call_set_state(call,LinphoneCallConnected,"Connected"); - if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call); - } - if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){ - linphone_call_update_remote_session_id_and_ver(call); - if (sal_media_description_has_dir(md,SalStreamSendOnly) || - sal_media_description_has_dir(md,SalStreamInactive)){ - if (lc->vtable.display_status){ - char *tmp=linphone_call_get_remote_address_as_string (call); - char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp); - lc->vtable.display_status(lc,msg); - ms_free(tmp); - ms_free(msg); - } - linphone_core_update_streams (lc,call,md); - linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); - if (call->refer_pending) - linphone_core_start_refered_call(lc,call); - }else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){ - /*we are put on hold when the call is initially accepted */ - if (lc->vtable.display_status){ - char *tmp=linphone_call_get_remote_address_as_string (call); - char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp); - lc->vtable.display_status(lc,msg); - ms_free(tmp); - ms_free(msg); - } - linphone_core_update_streams (lc,call,md); - linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote"); - }else{ - if (call->state!=LinphoneCallUpdating){ - if (call->state==LinphoneCallResuming){ - if (lc->vtable.display_status){ - lc->vtable.display_status(lc,_("Call resumed.")); - } - }else{ - if (lc->vtable.display_status){ - char *tmp=linphone_call_get_remote_address_as_string (call); - char *msg=ms_strdup_printf(_("Call answered by %s."),tmp); - lc->vtable.display_status(lc,msg); - ms_free(tmp); - ms_free(msg); - } - } - } - linphone_core_update_streams (lc,call,md); - if (!call->current_params.in_conference) - lc->current_call=call; - linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running"); - } - }else{ - /*send a bye*/ - ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); - linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings...")); - } -} - -static void call_ack(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (call==NULL){ - ms_warning("No call to be ACK'd"); - return ; - } - if (call->media_pending){ - SalMediaDescription *md=sal_call_get_final_media_description(op); - if (md && !sal_media_description_empty(md)){ - linphone_core_update_streams (lc,call,md); - linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); - }else{ - /*send a bye*/ - ms_error("Incompatible SDP response received in ACK, need to abort the call"); - linphone_core_abort_call(lc,call,"No codec intersection"); - return; - } - } -} - -static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ - SalMediaDescription *md; - SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op); - if ((rmd!=NULL) && (call->ice_session!=NULL)) { - linphone_core_update_ice_from_remote_media_description(call,rmd); - linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session); - } -#ifdef BUILD_UPNP - if(call->upnp_session != NULL) { - linphone_core_update_upnp_from_remote_media_description(call, rmd); - linphone_core_update_local_media_description_from_upnp(call->localdesc,call->upnp_session); - } -#endif //BUILD_UPNP - 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)) - linphone_core_update_streams(lc,call,md); + process_call_accepted(lc, call, op); } static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ - call_accept_update(lc,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); + linphone_core_notify_display_status(lc,_("We have been resumed.")); + _linphone_core_accept_call_update(lc,call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)"); } static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ - call_accept_update(lc,call); + LinphoneCallParams *params; + /* we are being paused */ - if(lc->vtable.display_status) - lc->vtable.display_status(lc,_("We are paused by other party.")); - linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote"); -} - -static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){ - if(lc->vtable.display_status) - lc->vtable.display_status(lc,_("Call is updated by remote.")); - call->defer_update=FALSE; - linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); - if (call->defer_update==FALSE){ - linphone_core_accept_call_update(lc,call,NULL); + linphone_core_notify_display_status(lc,_("We are paused by other party.")); + params = linphone_call_params_copy(call->params); + if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) { + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive); } + _linphone_core_accept_call_update(lc,call,params,LinphoneCallPausedByRemote,"Call paused by remote"); + linphone_call_params_unref(params); } -/* this callback is called when an incoming re-INVITE modifies the session*/ -static void call_updating(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); +/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ +static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){ SalMediaDescription *rmd=sal_call_get_remote_media_description(op); - - if (rmd==NULL){ - /* case of a reINVITE without SDP */ - call_accept_update(lc,call); - call->media_pending=TRUE; - return; - } - + + call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE); + switch(call->state){ case LinphoneCallPausedByRemote: if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){ call_resumed(lc,call); - }else call_paused_by_remote(lc,call); + }else{ + /*we are staying in PausedByRemote*/ + linphone_core_notify_display_status(lc,_("Call is updated by remote.")); + linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); + if (call->defer_update == FALSE){ + linphone_core_accept_call_update(lc,call,NULL); + } + } break; + /*SIP UPDATE CASE*/ + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingEarlyMedia: + if (is_update) { + linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote"); + _linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate)); + } + break; case LinphoneCallStreamsRunning: case LinphoneCallConnected: if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){ call_paused_by_remote(lc,call); }else{ - call_updated_by_remote(lc,call); + linphone_core_notify_display_status(lc,_("Call is updated by remote.")); + linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); + if (call->defer_update == FALSE){ + linphone_core_accept_call_update(lc,call,NULL); + } } break; - default: - call_accept_update(lc,call); + case LinphoneCallPaused: + /*we'll remain in pause state but accept the offer anyway according to default parameters*/ + _linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state)); + break; + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + case LinphoneCallUpdatedByRemote: + sal_call_decline(call->op,SalReasonInternalError,NULL); + /*no break*/ + case LinphoneCallIdle: + case LinphoneCallOutgoingInit: + case LinphoneCallEnd: + case LinphoneCallIncomingReceived: + case LinphoneCallOutgoingProgress: + case LinphoneCallRefered: + case LinphoneCallError: + case LinphoneCallReleased: + case LinphoneCallEarlyUpdatedByRemote: + case LinphoneCallEarlyUpdating: + ms_warning("Receiving reINVITE or UPDATE while in state [%s], should not happen.",linphone_call_state_to_string(call->state)); + break; + } +} + +/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ +static void call_updating(SalOp *op, bool_t is_update){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + SalMediaDescription *rmd=sal_call_get_remote_media_description(op); + + if (!call) { + ms_error("call_updating(): call doesn't exist anymore"); + return ; + } + if (call->state!=LinphoneCallPaused){ + /*Refresh the local description, but in paused state, we don't change anything.*/ + linphone_call_make_local_media_description(call); + sal_call_set_local_media_description(call->op,call->localdesc); + } + if (rmd == NULL){ + /* case of a reINVITE or UPDATE without SDP */ + call->expect_media_in_ack = TRUE; + sal_call_accept(op); /*respond with an offer*/ + /*don't do anything else in this case, wait for the ACK to receive to notify the app*/ + }else { + SalMediaDescription *md; + SalMediaDescription *prev_result_desc=call->resultdesc; + + call->expect_media_in_ack = FALSE; + + 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 (is_update && prev_result_desc && md){ + int diff=sal_media_description_equals(prev_result_desc,md); + if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){ + ms_warning("Cannot accept this update, it is changing parameters that require user approval"); + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/ + return; + } + } + call_updated(lc, call, op, is_update); + } +} + + +static void call_ack(SalOp *op){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + + if (call == NULL){ + ms_warning("call_ack(): no call for which an ack is expected"); + return; + } + if (call->expect_media_in_ack){ + switch(call->state){ + case LinphoneCallStreamsRunning: + case LinphoneCallPausedByRemote: + linphone_call_set_state(call, LinphoneCallUpdatedByRemote, "UpdatedByRemote"); + break; + default: + break; + } + process_call_accepted(lc, call, op); } } @@ -514,31 +761,31 @@ static void call_terminated(SalOp *op, const char *from){ LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call==NULL) return; - + switch(linphone_call_get_state(call)){ case LinphoneCallEnd: case LinphoneCallError: - ms_warning("call_terminated: ignoring."); + ms_warning("call_terminated: already terminated, ignoring."); return; break; case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: - call->reason=LinphoneReasonNotAnswered; + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL); break; default: break; } ms_message("Current call terminated..."); + if (call->refer_pending){ + linphone_core_start_refered_call(lc,call,NULL); + } //we stop the call only if we have this current call or if we are in call if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; + linphone_core_stop_ringing(lc); } linphone_call_stop_media_streams(call); - if (lc->vtable.show!=NULL) - lc->vtable.show(lc); - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Call terminated.")); + linphone_core_notify_show_interface(lc); + linphone_core_notify_display_status(lc,_("Call terminated.")); #ifdef BUILD_UPNP linphone_call_delete_upnp_session(call); @@ -547,115 +794,161 @@ static void call_terminated(SalOp *op, const char *from){ linphone_call_set_state(call, LinphoneCallEnd,"Call ended"); } -static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ +static int resume_call_after_failed_transfer(LinphoneCall *call){ + if (call->was_automatically_paused && call->state==LinphoneCallPausing) + return BELLE_SIP_CONTINUE; /*was still in pausing state*/ + + if (call->was_automatically_paused && call->state==LinphoneCallPaused){ + if (sal_op_is_idle(call->op)){ + linphone_core_resume_call(call->core,call); + }else { + ms_message("resume_call_after_failed_transfer(), salop was busy"); + return BELLE_SIP_CONTINUE; + } + } + linphone_call_unref(call); + return BELLE_SIP_STOP; +} + +static void call_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + const SalErrorInfo *ei=sal_op_get_error_info(op); char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ char *msg600=_("User does not want to be disturbed."); char *msg603=_("Call declined."); - const char *msg=details; + const char *msg=ei->full_string; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCall *referer=call->referer; if (call==NULL){ - ms_warning("Call faillure reported on already cleaned call ?"); + ms_warning("Call faillure reported on already terminated call."); return ; } - - if (lc->vtable.show) lc->vtable.show(lc); - if (error==SalErrorNoResponse){ - msg=_("No response."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - }else if (error==SalErrorProtocol){ - msg=details ? details : _("Protocol error."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc, msg); - }else if (error==SalErrorFailure){ - switch(sr){ - case SalReasonDeclined: - msg=msg603; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg603); - break; - case SalReasonBusy: - msg=msg486; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg486); - break; - case SalReasonRedirect: - msg=_("Redirected"); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonTemporarilyUnavailable: - msg=msg480; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg480); - break; - case SalReasonNotFound: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonDoNotDisturb: - msg=msg600; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg600); - break; - case SalReasonMedia: - //media_encryption_mandatory - if (call->params.media_encryption == LinphoneMediaEncryptionSRTP && - !linphone_core_is_media_encryption_mandatory(lc)) { - int i; - ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP"); - linphone_call_stop_media_streams(call); - if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){ - /* 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_notify_show_interface(lc); + switch(ei->reason){ + case SalReasonNone: + break; + case SalReasonRequestTimeout: + msg=_("Request timeout."); + linphone_core_notify_display_status(lc,msg); + break; + case SalReasonDeclined: + msg=msg603; + linphone_core_notify_display_status(lc,msg603); + break; + case SalReasonBusy: + msg=msg486; + linphone_core_notify_display_status(lc,msg486); + break; + case SalReasonRedirect: + { + linphone_call_stop_media_streams(call); + if ( call->state==LinphoneCallOutgoingInit + || call->state==LinphoneCallOutgoingProgress + || call->state==LinphoneCallOutgoingRinging /*push case*/ + || call->state==LinphoneCallOutgoingEarlyMedia){ + LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); + if( redirection_to ){ + char* url = linphone_address_as_string(redirection_to); + ms_warning("Redirecting call [%p] to %s",call, url); + ms_free(url); + if( call->log->to != NULL ) { + linphone_address_unref(call->log->to); } + call->log->to = linphone_address_ref(redirection_to); + linphone_core_restart_invite(lc, call); return; } - msg=_("Incompatible media parameters."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - default: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Call failed.")); + } + msg=_("Redirected"); + linphone_core_notify_display_status(lc,msg); } + break; + case SalReasonTemporarilyUnavailable: + msg=msg480; + linphone_core_notify_display_status(lc,msg480); + break; + case SalReasonNotFound: + linphone_core_notify_display_status(lc,msg); + break; + case SalReasonDoNotDisturb: + msg=msg600; + linphone_core_notify_display_status(lc,msg600); + break; + case SalReasonUnsupportedContent: /*state == LinphoneCallOutgoingInit) + || (call->state == LinphoneCallOutgoingProgress) + || (call->state == LinphoneCallOutgoingRinging) /* Push notification case */ + || (call->state == LinphoneCallOutgoingEarlyMedia)) { + int i; + for (i = 0; i < call->localdesc->nb_streams; i++) { + if (!sal_stream_description_active(&call->localdesc->streams[i])) continue; + if (call->params->media_encryption == LinphoneMediaEncryptionSRTP) { + if (call->params->avpf_enabled == TRUE) { + if (i == 0) ms_message("Retrying call [%p] with SAVP", call); + call->params->avpf_enabled = FALSE; + linphone_core_restart_invite(lc, call); + return; + } else if (!linphone_core_is_media_encryption_mandatory(lc)) { + if (i == 0) ms_message("Retrying call [%p] with AVP", call); + call->params->media_encryption = LinphoneMediaEncryptionNone; + memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); + linphone_core_restart_invite(lc, call); + return; + } + } else if (call->params->avpf_enabled == TRUE) { + if (i == 0) ms_message("Retrying call [%p] with AVP", call); + call->params->avpf_enabled = FALSE; + linphone_core_restart_invite(lc, call); + return; + } + } + } + msg=_("Incompatible media parameters."); + linphone_core_notify_display_status(lc,msg); + break; + default: + linphone_core_notify_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 errors 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)); + linphone_call_set_state(call, call->prevstate,ei->full_string); + 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; - 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."); - } else { - linphone_call_set_state(call,LinphoneCallError,msg); + if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){ + if (ei->reason==SalReasonDeclined){ + linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); + }else{ + linphone_call_set_state(call,LinphoneCallError,ei->full_string); + } + if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason)); + } + + if (referer){ + /*notify referer of the failure*/ + linphone_core_notify_refer_state(lc,referer,call); + /*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/ + linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer"); } } @@ -663,113 +956,79 @@ static void call_released(SalOp *op){ LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call!=NULL){ linphone_call_set_state(call,LinphoneCallReleased,"Call released"); - }else ms_error("call_released() for already destroyed call ?"); + }else{ + /*we can arrive here when the core manages call at Sal level without creating a LinphoneCall object. Typicially: + * - when declining an incoming call with busy because maximum number of calls is reached. + */ + } } -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)); +static void auth_failure(SalOp *op, SalAuthInfo* info) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneAuthInfo *ai=NULL; - 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( info != NULL ){ + ai = (LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); - 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){ + ms_message("%s/%s/%s authentication fails.",info->realm,info->username,info->domain); + /*ask again for password if auth info was already supplied but apparently not working*/ + linphone_core_notify_auth_info_requested(lc,info->realm,info->username,info->domain); } } - - 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); - if (ai){ - ms_message("%s/%s authentication works.",realm,username); - ai->works=TRUE; - } } static void register_success(SalOp *op, bool_t registered){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; - - if (cfg->deletion_date!=0){ - ms_message("Registration success for removed proxy config, ignored"); + + if (!cfg){ + ms_message("Registration success for deleted proxy config, ignored"); return; } - linphone_proxy_config_set_error(cfg,LinphoneReasonNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , - registered ? "Registration sucessful" : "Unregistration done"); - if (lc->vtable.display_status){ + registered ? "Registration successful" : "Unregistration done"); + { if (registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); - lc->vtable.display_status(lc,msg); + linphone_core_notify_display_status(lc,msg); ms_free(msg); } - + } -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ +static void register_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); + const char *details=ei->full_string; if (cfg==NULL){ ms_warning("Registration failed for unknown proxy config."); return ; } - if (cfg->deletion_date!=0){ - ms_message("Registration failed for removed proxy config, ignored"); - return; - } if (details==NULL) details=_("no response timeout"); - - if (lc->vtable.display_status) { - char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details ); - lc->vtable.display_status(lc,msg); + + { + char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details); + linphone_core_notify_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); + + if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError) + && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); + } else { + 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; } } @@ -788,8 +1047,7 @@ static void vfu_request(SalOp *op){ static void dtmf_received(SalOp *op, char dtmf){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, call, dtmf); + linphone_core_notify_dtmf_received(lc, call, dtmf); } static void refer_received(Sal *sal, SalOp *op, const char *referto){ @@ -802,21 +1060,14 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ call->refer_to=ms_strdup(referto); call->refer_pending=TRUE; linphone_call_set_state(call,LinphoneCallRefered,"Refered"); - if (lc->vtable.display_status){ + { char *msg=ms_strdup_printf(_("We are transferred to %s"),referto); - lc->vtable.display_status(lc,msg); + linphone_core_notify_display_status(lc,msg); ms_free(msg); } - if (call->state!=LinphoneCallPaused){ - ms_message("Automatically pausing current call to accept transfer."); - linphone_core_pause_call(lc,call); - call->was_automatically_paused=TRUE; - /*then we will start the refered when the pause is accepted, in order to serialize transactions within the dialog. - * Indeed we need to avoid to send a NOTIFY to inform about of state of the refered call while the pause isn't completed. - **/ - }else linphone_core_start_refered_call(lc,call); - }else if (lc->vtable.refer_received){ - lc->vtable.refer_received(lc,referto); + if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL); + }else { + linphone_core_notify_refer_received(lc,referto); } } @@ -844,30 +1095,39 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ static void text_received(SalOp *op, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - if (is_duplicate_msg(lc,msg->message_id)==FALSE){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){ linphone_core_message_received(lc,op,msg); } + sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code)); + if (!call) sal_op_release(op); } -static void notify(SalOp *op, const char *from, const char *msg){ +static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) { + LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_core_is_composing_received(lc, op, is_composing); + sal_op_release(op); +} + +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 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 notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, 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); + linphone_notify_recv(lc,op,ss,model); } -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 subscribe_received(SalOp *op, const char *from){ +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); } @@ -887,6 +1147,62 @@ static void ping_reply(SalOp *op){ } } +static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) { + const char *chain_file = lp_config_get_string(lc->config,"sip","client_cert_chain", 0); + const char *key_file = lp_config_get_string(lc->config,"sip","client_cert_key", 0);; + +#ifndef _WIN32 + { + // 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; + 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 { + { + linphone_core_notify_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); @@ -927,23 +1243,118 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta return LinphoneChatMessageStateIdle; } -static int op_equals(LinphoneCall *a, SalOp *b) { - return a->op !=b; /*return 0 if equals*/ -} static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); - const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc); - - if (chat_msg && chat_msg->cb) { - chat_msg->cb(chat_msg - ,chatStatusSal2Linphone(status) - ,chat_msg->cb_ud); + + if (chat_msg == NULL) { + // Do not handle delivery status for isComposing messages. + return; } - 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); + + chat_msg->state=chatStatusSal2Linphone(status); + linphone_chat_message_update_state(chat_msg); + + if (chat_msg && (chat_msg->cb || (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)))) { + ms_message("Notifying text delivery with status %s",linphone_chat_message_state_to_string(chat_msg->state)); + if (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)(chat_msg, chat_msg->state); + } else { + /* Legacy */ + chat_msg->cb(chat_msg,chat_msg->state,chat_msg->cb_ud); + } + } + if (status != SalTextDeliveryInProgress) { /*only release op if not in progress*/ + linphone_chat_message_destroy(chat_msg); + } +} + +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){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(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{ + if (lev->subscription_state==LinphoneSubscriptionActive && ei->reason==SalReasonIOError){ + linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress); + } + else 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)); + + if (lev==NULL) { + /*out of subscribe notify */ + lev=linphone_event_new_with_out_of_dialog_op(lc,op,LinphoneSubscriptionOutgoing,eventname); + } + { + LinphoneContent *ct=linphone_content_from_sal_body(body); + if (ct) linphone_core_notify_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){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); + + if (lev==NULL) return; + if (ei->reason==SalReasonNone){ + if (!lev->terminating) + linphone_event_set_publish_state(lev,LinphonePublishOk); + else + linphone_event_set_publish_state(lev,LinphonePublishCleared); + }else{ + if (lev->publish_state==LinphonePublishOk){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else{ + 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); + }else if (linphone_event_get_subscription_state(lev)==LinphoneSubscriptionActive){ + linphone_event_set_state(lev,LinphoneSubscriptionExpiring); } } @@ -956,8 +1367,7 @@ SalCallbacks linphone_sal_callbacks={ call_terminated, call_failure, call_released, - auth_requested, - auth_success, + auth_failure, register_success, register_failure, vfu_request, @@ -965,12 +1375,22 @@ SalCallbacks linphone_sal_callbacks={ refer_received, text_received, text_delivery_update, - notify, - notify_presence, + is_composing_received, 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 b9894ea8f..990f06998 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -21,54 +21,550 @@ * 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" +#include "belle-sip/belle-sip.h" +#include "lime.h" +#include "ortp/b64.h" -/** - * @addtogroup chatroom - * @{ - */ +#include +#include +#include -/** - * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org - * @param lc #LinphoneCore object - * @param to destination address for messages - * @return #LinphoneChatRoom where messaging can take place. - */ -LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){ - LinphoneAddress *parsed_url=NULL; +#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 +#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 +#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 - if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){ - LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1); - cr->lc=lc; - cr->peer=linphone_address_as_string(parsed_url); - cr->peer_url=parsed_url; - lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr); - return cr; +#define FILE_TRANSFER_KEY_SIZE 32 + + +static void linphone_chat_message_release(LinphoneChatMessage *msg); + +static LinphoneChatMessageCbs * linphone_chat_message_cbs_new(void) { + return belle_sip_object_new(LinphoneChatMessageCbs); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessageCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessageCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +LinphoneChatMessageCbs * linphone_chat_message_cbs_ref(LinphoneChatMessageCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_chat_message_cbs_unref(LinphoneChatMessageCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void *linphone_chat_message_cbs_get_user_data(const LinphoneChatMessageCbs *cbs) { + return cbs->user_data; +} + +void linphone_chat_message_cbs_set_user_data(LinphoneChatMessageCbs *cbs, void *ud) { + cbs->user_data = ud; +} + +LinphoneChatMessageCbsMsgStateChangedCb linphone_chat_message_cbs_get_msg_state_changed(const LinphoneChatMessageCbs *cbs) { + return cbs->msg_state_changed; +} + +void linphone_chat_message_cbs_set_msg_state_changed(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsMsgStateChangedCb cb) { + cbs->msg_state_changed = cb; +} + +LinphoneChatMessageCbsFileTransferRecvCb linphone_chat_message_cbs_get_file_transfer_recv(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_recv; +} + +void linphone_chat_message_cbs_set_file_transfer_recv(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferRecvCb cb) { + cbs->file_transfer_recv = cb; +} + +LinphoneChatMessageCbsFileTransferSendCb linphone_chat_message_cbs_get_file_transfer_send(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_send; +} + +void linphone_chat_message_cbs_set_file_transfer_send(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferSendCb cb) { + cbs->file_transfer_send = cb; +} + +LinphoneChatMessageCbsFileTransferProgressIndicationCb linphone_chat_message_cbs_get_file_transfer_progress_indication(const LinphoneChatMessageCbs *cbs) { + return cbs->file_transfer_progress_indication; +} + +void linphone_chat_message_cbs_set_file_transfer_progress_indication(LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsFileTransferProgressIndicationCb cb) { + cbs->file_transfer_progress_indication = cb; +} + + +static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg); + +static void process_io_error_upload(void *data, const belle_sip_io_error_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + ms_error("I/O Error during file upload to %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room); + linphone_chat_message_cancel_file_transfer(msg); +} +static void process_auth_requested_upload(void *data, belle_sip_auth_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + ms_error("Error during file upload: auth requested to connect %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room); + linphone_chat_message_cancel_file_transfer(msg); +} + +static void process_io_error_download(void *data, const belle_sip_io_error_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + ms_error("I/O Error during file download %s - msg [%p] chat room[%p]", msg->external_body_url, msg, msg->chat_room); + msg->state = LinphoneChatMessageStateFileTransferError; + if (msg->cb) { + msg->cb(msg, msg->state, msg->cb_ud); + } + if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state); + } +} +static void process_auth_requested_download(void *data, belle_sip_auth_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + msg->state = LinphoneChatMessageStateFileTransferError; + ms_error("Error during file download : auth requested to get %s - msg [%p] chat room[%p]", msg->external_body_url, msg, msg->chat_room); + if (msg->cb) { + msg->cb(msg, msg->state, msg->cb_ud); + } + if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state); + } +} + +static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + if (!chatMsg->http_request || belle_http_request_is_cancelled(chatMsg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", chatMsg, __FUNCTION__); + return; + } + if (linphone_chat_message_cbs_get_file_transfer_progress_indication(chatMsg->callbacks)) { + linphone_chat_message_cbs_get_file_transfer_progress_indication(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, offset, total); + } else { + /* Legacy: call back given by application level */ + linphone_core_notify_file_transfer_progress_indication(chatMsg->chat_room->lc, chatMsg, chatMsg->file_transfer_information, offset, total); + } +} + +static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + char *buf = (char *)buffer; + + if (!chatMsg->http_request || belle_http_request_is_cancelled(chatMsg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", chatMsg, __FUNCTION__); + return BELLE_SIP_STOP; + } + + /* if we've not reach the end of file yet, ask for more data*/ + if (offsetfile_transfer_information)){ + char *plainBuffer = NULL; + + if (linphone_content_get_key(chatMsg->file_transfer_information) != NULL) { /* if we have a key to cipher the message, use it! */ + /* if this chunk is not the last one, the lenght must be a multiple of block cipher size(16 bytes)*/ + if (offset+*size < linphone_content_get_size(chatMsg->file_transfer_information)) { + *size -=(*size%16); + } + plainBuffer = (char *)malloc(*size); + } + + /* get data from call back */ + if (linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)) { + LinphoneBuffer *lb = linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, offset, *size); + if (lb == NULL) { + *size = 0; + } else { + *size = linphone_buffer_get_size(lb); + memcpy(plainBuffer?plainBuffer:buf, linphone_buffer_get_content(lb), *size); + linphone_buffer_unref(lb); + } + } else { + /* Legacy */ + linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer?plainBuffer:buf, size); + } + + if (linphone_content_get_key(chatMsg->file_transfer_information) != NULL) { /* if we have a key to cipher the message, use it! */ + lime_encryptFile(linphone_content_get_cryptoContext_address(chatMsg->file_transfer_information), (unsigned char *)linphone_content_get_key(chatMsg->file_transfer_information), *size, plainBuffer, (char*)buffer); + free(plainBuffer); + /* check if we reach the end of file */ + if (offset+*size >= linphone_content_get_size(chatMsg->file_transfer_information)) { + /* conclude file ciphering by calling it context with a zero size */ + lime_encryptFile(linphone_content_get_cryptoContext_address(chatMsg->file_transfer_information), NULL, 0, NULL, NULL); + } + } + } + + return BELLE_SIP_CONTINUE; +} + +static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + + /* check the answer code */ + if (event->response){ + int code=belle_http_response_get_status_code(event->response); + if (code == 204) { /* this is the reply to the first post to the server - an empty message */ + /* start uploading the file */ + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_sip_multipart_body_handler_t *bh; + char* ua; + char *first_part_header; + belle_sip_body_handler_t *first_part_bh; + + /* shall we encrypt the file */ + if (linphone_core_lime_for_file_sharing_enabled(msg->chat_room->lc)) { + char keyBuffer[FILE_TRANSFER_KEY_SIZE]; /* temporary storage of generated key: 192 bits of key + 64 bits of initial vector */ + /* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */ + sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE); + linphone_content_set_key(msg->file_transfer_information, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */ + /* temporary storage for the Content-disposition header value : use a generic filename to not leak it + * Actual filename stored in msg->file_transfer_information->name will be set in encrypted message sended to the */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\""); + } else { + /* temporary storage for the Content-disposition header value */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(msg->file_transfer_information)); + } + + /* create a user body handler to take care of the file and add the content disposition and content-type headers */ + if (msg->file_transfer_filepath != NULL) { + first_part_bh=(belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath,NULL,msg); + } else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) { + first_part_bh=(belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( + linphone_content_get_buffer(msg->file_transfer_information), + linphone_content_get_size(msg->file_transfer_information), + NULL,msg); + } else { + first_part_bh=(belle_sip_body_handler_t *)belle_sip_user_body_handler_new(linphone_content_get_size(msg->file_transfer_information),NULL,NULL,linphone_chat_message_file_transfer_on_send_body,msg); + } + belle_sip_body_handler_add_header(first_part_bh, belle_sip_header_create("Content-disposition", first_part_header)); + belle_sip_free(first_part_header); + belle_sip_body_handler_add_header(first_part_bh, (belle_sip_header_t *)belle_sip_header_content_type_create(linphone_content_get_type(msg->file_transfer_information), linphone_content_get_subtype(msg->file_transfer_information))); + + /* insert it in a multipart body handler which will manage the boundaries of multipart message */ + bh=belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh); + + /* create the http request: do not include the message header at this point, it is done by bellesip when setting the multipart body handler in the message */ + ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); + uri=belle_generic_uri_parse(linphone_core_get_file_transfer_server(msg->chat_room->lc)); + if (msg->http_request) belle_sip_object_unref(msg->http_request); + msg->http_request=belle_http_request_create("POST", + uri, + belle_sip_header_create("User-Agent",ua), + NULL); + belle_sip_object_ref(msg->http_request); /* keep a reference to the http request to be able to cancel it during upload */ + ms_free(ua); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request),BELLE_SIP_BODY_HANDLER(bh)); + cbs.process_response=linphone_chat_message_process_response_from_post_file; + cbs.process_io_error=process_io_error_upload; + cbs.process_auth_requested=process_auth_requested_upload; + l=belle_http_request_listener_create_from_callbacks(&cbs,msg); + belle_http_provider_send_request(msg->chat_room->lc->http_provider,msg->http_request,l); + } + + if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */ + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + belle_sip_object_unref(msg->http_request); + msg->http_request = NULL; + + /* if we have an encryption key for the file, we must insert it into the message and restore the correct filename */ + if (linphone_content_get_key(msg->file_transfer_information) != NULL) { + /* parse the message body */ + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for : add a file-key children node */ + xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; /* need to parse the children node to update the file-name one */ + /* convert key to base64 */ + int b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0); + char *keyb64 = (char *)malloc(b64Size+1); + int xmlStringLength; + + b64Size = b64_encode(linphone_content_get_key(msg->file_transfer_information), FILE_TRANSFER_KEY_SIZE, keyb64, b64Size); + keyb64[b64Size] = '\0'; /* libxml need a null terminated string */ + + /* add the node containing the key to the file-info node */ + xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlFree(typeAttribute); + free(keyb64); + + /* look for the file-name node and update its content */ + while (fileInfoNodeChildren!=NULL) { + if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { /* we found a the file-name node, update its content with the real filename */ + /* update node content */ + xmlNodeSetContent(fileInfoNodeChildren, (const xmlChar *)(linphone_content_get_name(msg->file_transfer_information))); + break; + } + fileInfoNodeChildren = fileInfoNodeChildren->next; + } + + + /* dump the xml into msg->message */ + xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, "UTF-8", 0); + + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + } else { /* no encryption key, transfer in plain, just copy the message sent by server */ + msg->message = ms_strdup(body); + } + + msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); + msg->state = LinphoneChatMessageStateFileTransferDone; + if (msg->cb) { + msg->cb(msg, msg->state, msg->cb_ud); + } + if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state); + } + _linphone_chat_room_send_message(msg->chat_room, msg); + } + } +} + + +static void _linphone_chat_message_destroy(LinphoneChatMessage* msg); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessage,belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_chat_message_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + +void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason){ + lc->chat_deny_code=deny_reason; +} + +void linphone_core_enable_chat(LinphoneCore *lc){ + lc->chat_deny_code=LinphoneReasonNone; +} + +bool_t linphone_core_chat_enabled(const LinphoneCore *lc){ + return lc->chat_deny_code!=LinphoneReasonNone; +} + +const MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) { + return lc->chatrooms; +} + +static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ + return linphone_address_weak_equal(cr->peer_url,from); +} + +static void _linphone_chat_room_destroy(LinphoneChatRoom *obj); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatRoom); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_chat_room_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + +static LinphoneChatRoom * _linphone_core_create_chat_room(LinphoneCore *lc, LinphoneAddress *addr) { + LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom); + cr->lc = lc; + cr->peer = linphone_address_as_string(addr); + cr->peer_url = addr; + cr->unread_count = -1; + lc->chatrooms = ms_list_append(lc->chatrooms, (void *)cr); + return cr; +} + +static LinphoneChatRoom * _linphone_core_create_chat_room_from_url(LinphoneCore *lc, const char *to) { + LinphoneAddress *parsed_url = NULL; + if ((parsed_url = linphone_core_interpret_url(lc, to)) != NULL) { + return _linphone_core_create_chat_room(lc, parsed_url); } return NULL; } - -/** - * Destroy a LinphoneChatRoom. - * @param cr #LinphoneChatRoom object - */ -void linphone_chat_room_destroy(LinphoneChatRoom *cr){ - LinphoneCore *lc=cr->lc; - lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); + +LinphoneChatRoom * _linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneChatRoom *cr=NULL; + MSList *elem; + for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ + cr=(LinphoneChatRoom*)elem->data; + if (linphone_chat_room_matches(cr,addr)){ + break; + } + cr=NULL; + } + return cr; +} + +static 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_from_url(lc,to); + } + return ret; +} + +LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr); + if (!ret) { + ret = _linphone_core_create_chat_room(lc, linphone_address_clone(addr)); + } + return ret; +} + +void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr){ + if (ms_list_find(lc->chatrooms, cr)){ + lc->chatrooms = ms_list_remove(cr->lc->chatrooms, cr); + linphone_chat_room_delete_history(cr); + linphone_chat_room_unref(cr); + }else{ + ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.", + cr); + } + +} + +LinphoneChatRoom * linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) { + return _linphone_core_get_or_create_chat_room(lc, to); +} + +static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) { + if (cr->composing_idle_timer) { + if(cr-> lc && cr->lc->sal) + sal_cancel_timer(cr->lc->sal, cr->composing_idle_timer); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + } +} + +static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->composing_refresh_timer) { + if(cr->lc && cr->lc->sal) + sal_cancel_timer(cr->lc->sal, cr->composing_refresh_timer); + belle_sip_object_unref(cr->composing_refresh_timer); + cr->composing_refresh_timer = NULL; + } +} + +static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->remote_composing_refresh_timer) { + if(cr->lc && cr->lc->sal) + sal_cancel_timer(cr->lc->sal, cr->remote_composing_refresh_timer); + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + } +} + +static void _linphone_chat_room_destroy(LinphoneChatRoom *cr){ + ms_list_free_with_data(cr->transient_messages, (void (*)(void*))linphone_chat_message_release); + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + linphone_chat_room_delete_remote_composing_refresh_timer(cr); + if (cr->lc != NULL) { + if (ms_list_find(cr->lc->chatrooms, cr)){ + ms_error("LinphoneChatRoom[%p] is destroyed while still being used by the LinphoneCore. This is abnormal." + " linphone_core_get_chat_room() doesn't give a reference, there is no need to call linphone_chat_room_unref(). " + "In order to remove a chat room from the core, use linphone_core_delete_chat_room().", + cr); + } + cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms, cr); + } linphone_address_destroy(cr->peer_url); ms_free(cr->peer); } +void linphone_chat_room_destroy(LinphoneChatRoom *cr) { + linphone_chat_room_unref(cr); +} + +void linphone_chat_room_release(LinphoneChatRoom *cr) { + cr->lc = NULL; + linphone_chat_room_unref(cr); +} + +LinphoneChatRoom * linphone_chat_room_ref(LinphoneChatRoom *cr) { + belle_sip_object_ref(cr); + return cr; +} + +void linphone_chat_room_unref(LinphoneChatRoom *cr) { + belle_sip_object_unref(cr); +} + +void * linphone_chat_room_get_user_data(const LinphoneChatRoom *cr) { + return cr->user_data; +} + +void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) { + cr->user_data = ud; +} + + 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); + linphone_chat_message_ref(msg); + /* Check if we shall upload a file to a server */ + if (msg->file_transfer_information != NULL && msg->content_type == NULL) { + /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + const char *transfer_server = linphone_core_get_file_transfer_server(cr->lc); + + if (transfer_server == NULL) { + ms_warning("Cannot send file transfer message: no file transfer server configured."); + return; + } + uri=belle_generic_uri_parse(transfer_server); + + msg->http_request=belle_http_request_create("POST", + uri, + NULL, + NULL, + NULL); + belle_sip_object_ref(msg->http_request); /* keep a reference on the request to be able to cancel it */ + cbs.process_response=linphone_chat_message_process_response_from_post_file; + cbs.process_io_error=process_io_error_upload; + cbs.process_auth_requested=process_auth_requested_upload; + l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ + belle_http_provider_send_request(cr->lc->http_provider,msg->http_request,l); + linphone_chat_message_unref(msg); + return; + } + if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){ if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){ if (call->state==LinphoneCallConnected || @@ -78,26 +574,75 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM call->state==LinphoneCallPausedByRemote){ ms_message("send SIP message through the existing call."); op = call->op; - call->pending_message=msg; + identity=linphone_core_find_best_identity(cr->lc,linphone_call_get_remote_address(call)); } } } + 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); + msg->op = op = sal_op_new(cr->lc->sal); + linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0)); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ - 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); - sal_message_send(op,identity,cr->peer,content_type, NULL); + sal_message_send(op,identity,cr->peer,content_type, NULL, NULL); ms_free(content_type); } else { - sal_text_send(op, identity, cr->peer,msg->message); + char *peer_uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + const char * content_type; + + if (linphone_core_lime_enabled(cr->lc)) { + linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */ + if (msg->content_type && strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) { + content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml"; /* it's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml*/ + } else { + content_type = "xml/cipher"; + } + } else { + content_type = msg->content_type; + } + + if (content_type == NULL) { + sal_text_send(op, identity, cr->peer,msg->message); + } else { + sal_message_send(op, identity, cr->peer, content_type, msg->message, peer_uri); + } + ms_free(peer_uri); + } + + msg->dir=LinphoneChatMessageOutgoing; + msg->from=linphone_address_new(identity); + msg->storage_id=linphone_chat_message_store(msg); + + if(cr->unread_count >= 0 && !msg->is_read) cr->unread_count++; + + // add to transient list + cr->transient_messages = ms_list_append(cr->transient_messages, linphone_chat_message_ref(msg)); + + if (cr->is_composing == LinphoneIsComposingActive) { + cr->is_composing = LinphoneIsComposingIdle; + } + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + linphone_chat_message_unref(msg); +} + +void linphone_chat_message_update_state(LinphoneChatMessage* chat_msg ) { + linphone_chat_message_store_state(chat_msg); + + if( chat_msg->state == LinphoneChatMessageStateDelivered + || chat_msg->state == LinphoneChatMessageStateNotDelivered ){ + // message is not transient anymore, we can remove it from our transient list and unref it : + chat_msg->chat_room->transient_messages = ms_list_remove(chat_msg->chat_room->transient_messages, chat_msg); + linphone_chat_message_unref(chat_msg); } } @@ -111,233 +656,696 @@ 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 - if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message); - if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg); - + if (msg->message){ + /*legacy API*/ + linphone_core_notify_text_message_received(lc, cr, msg->from, msg->message); + } + linphone_core_notify_message_received(lc, cr,msg); + cr->remote_is_composing = LinphoneIsComposingIdle; + linphone_core_notify_is_composing_received(cr->lc, cr); } void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){ - MSList *elem; LinphoneChatRoom *cr=NULL; LinphoneAddress *addr; - char *cleanfrom; LinphoneChatMessage* msg; const SalCustomHeader *ch; - + addr=linphone_address_new(sal_msg->from); linphone_address_clean(addr); - for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ - cr=(LinphoneChatRoom*)elem->data; - if (linphone_chat_room_matches(cr,addr)){ - break; + cr=linphone_core_get_chat_room(lc,addr); + + if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */ + xmlChar *file_url = NULL; + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + + msg = linphone_chat_room_create_message(cr, NULL); /* create a message with empty body */ + msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ + msg->file_transfer_information = linphone_content_new(); + + /* parse the message body to get all informations from it */ + xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); + + cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { + xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + linphone_content_set_size(msg->file_transfer_information, strtol((const char*)fileSizeString, NULL, 10)); + xmlFree(fileSizeString); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + linphone_content_set_name(msg->file_transfer_information, (const char *)xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1)); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { + xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int contentTypeIndex = 0; + char *type; + char *subtype; + while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') { + contentTypeIndex++; + } + type = ms_strndup((char *)contentType, contentTypeIndex); + subtype = ms_strdup(((char *)contentType+contentTypeIndex+1)); + linphone_content_set_type(msg->file_transfer_information, type); + linphone_content_set_subtype(msg->file_transfer_information, subtype); + ms_free(subtype); + ms_free(type); + xmlFree(contentType); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) { /* there is a key in the message: file has been encrypted */ + /* convert the key from base 64 */ + xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int keyLength = b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); + uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); + /* decode the key into local key buffer */ + b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); + linphone_content_set_key(msg->file_transfer_information, (char *)keyBuffer, keyLength); /* duplicate key value into the linphone content private structure */ + xmlFree(keyb64); + free(keyBuffer); + } + + cur=cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } } - cr=NULL; + xmlFreeDoc(xmlMessageBody); + + linphone_chat_message_set_external_body_url(msg, (const char *)file_url); + xmlFree(file_url); + } else { /* message is not rcs file transfer, create it with provided sal_msg->text as ->message */ + msg = linphone_chat_room_create_message(cr, sal_msg->text); } - cleanfrom=linphone_address_as_string(addr); - if (cr==NULL){ - /* create a new chat room */ - cr=linphone_core_create_chat_room(lc,cleanfrom); - } - msg = linphone_chat_room_create_message(cr, sal_msg->text); linphone_chat_message_set_from(msg, cr->peer_url); + + { + LinphoneAddress *to; + to=sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(lc)); + msg->to=to; + } + msg->time=sal_msg->time; - ch=sal_op_get_custom_header(op); + msg->state=LinphoneChatMessageStateDelivered; + msg->is_read=FALSE; + 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); + msg->storage_id=linphone_chat_message_store(msg); + + if(cr->unread_count < 0) cr->unread_count = 1; + else cr->unread_count++; + linphone_chat_room_message_received(cr,lc,msg); - ms_free(cleanfrom); + linphone_chat_message_unref(msg); +} + +static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + cr->remote_is_composing = LinphoneIsComposingIdle; + linphone_core_notify_is_composing_received(cr->lc, cr); + return BELLE_SIP_STOP; +} + +static const char *iscomposing_prefix = "/xsi:isComposing"; + +static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr iscomposing_object; + const char *state_str = NULL; + const char *refresh_str = NULL; + int refresh_duration = lp_config_get_int(cr->lc->config, "sip", "composing_remote_refresh_timeout", COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT); + int i; + LinphoneIsComposingState state = LinphoneIsComposingIdle; + + if (linphone_create_xml_xpath_context(xml_ctx) < 0) return; + + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix); + if (iscomposing_object != NULL){ + if(iscomposing_object->nodesetval != NULL) { + for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i); + state_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (state_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i); + refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + } + } + xmlXPathFreeObject(iscomposing_object); + } + + if (state_str != NULL) { + if (strcmp(state_str, "active") == 0) { + state = LinphoneIsComposingActive; + if (refresh_str != NULL) { + refresh_duration = atoi(refresh_str); + } + if (!cr->remote_composing_refresh_timer) { + cr->remote_composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_remote_refresh_composing_expired, cr, refresh_duration * 1000, "composing remote refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->remote_composing_refresh_timer, refresh_duration * 1000); + } + } else { + linphone_chat_room_delete_remote_composing_refresh_timer(cr); + } + + cr->remote_is_composing = state; + linphone_core_notify_is_composing_received(cr->lc, cr); + linphone_free_xml_text_content(state_str); + } + if (refresh_str != NULL) { + linphone_free_xml_text_content(refresh_str); + } +} + +static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const char *text) { + xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); + xml_ctx->doc = xmlReadDoc((const unsigned char*)text, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + process_im_is_composing_notification(cr, xml_ctx); + } else { + ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); + } + linphone_xmlparsing_context_destroy(xml_ctx); +} + +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { + LinphoneAddress *addr = linphone_address_new(is_composing->from); + LinphoneChatRoom *cr = _linphone_core_get_chat_room(lc, addr); + if (cr != NULL) { + linphone_chat_room_notify_is_composing(cr, is_composing->text); + } + linphone_address_destroy(addr); +} + +bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { + return (cr->remote_is_composing == LinphoneIsComposingActive) ? TRUE : FALSE; } -/** - * Returns back pointer to LinphoneCore object. -**/ LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){ return cr->lc; } -/** - * Assign a user pointer to the chat room. -**/ -void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){ - cr->user_data=ud; +LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr){ + return cr->lc; } -/** - * Retrieve the user pointer associated with the chat room. -**/ -void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){ - return cr->user_data; -} - -/** - * get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom - * @param cr #LinphoneChatRoom object - * @return #LinphoneAddress peer address - */ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) { return cr->peer_url; } -/** - * Create a message attached to a dedicated chat room; - * @param cr the chat room. - * @param message text message, NULL if absent. - * @return a new #LinphoneChatMessage - */ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) { - LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); + LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); + msg->callbacks=linphone_chat_message_cbs_new(); msg->chat_room=(LinphoneChatRoom*)cr; msg->message=message?ms_strdup(message):NULL; + msg->is_read=TRUE; + msg->content_type = NULL; /* this property is used only when transfering file */ + msg->file_transfer_information = NULL; /* this property is used only when transfering file */ + msg->http_request = NULL; return msg; } -/** - * Send a message to peer member of this chat room. - * @param cr #LinphoneChatRoom object - * @param msg #LinphoneChatMessage message to be sent - * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL - * @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) { +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 = belle_sip_object_new(LinphoneChatMessage); + msg->callbacks=linphone_chat_message_cbs_new(); + 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; + msg->content_type = NULL; /* this property is used only when transfering file */ + msg->file_transfer_information = NULL; /* this property is used only when transfering file */ + 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; +} + +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; _linphone_chat_room_send_message(cr, msg); } -/** - * Returns a #LinphoneChatMessageState as a string. - */ -const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { - switch (state) { - case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle"; - case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress"; - case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered"; - case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; - default: return "Unknown state"; - } - +void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + msg->state = LinphoneChatMessageStateInProgress; + _linphone_chat_room_send_message(cr, msg); +} + +static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"isComposing", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi", + NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xsi", (const xmlChar *)"schemaLocation", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:im-composing iscomposing.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"state", + (cr->is_composing == LinphoneIsComposingActive) ? (const xmlChar *)"active" : (const xmlChar *)"idle"); + } + if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) { + char refresh_str[4] = { 0 }; + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + snprintf(refresh_str, sizeof(refresh_str), "%u", refresh_timeout); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str); + } + if (err >= 0) { + /* Close the "isComposing" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + return content; +} + +static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) { + SalOp *op = NULL; + const char *identity = NULL; + char *content = NULL; + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url); + if (proxy) + identity = linphone_proxy_config_get_identity(proxy); + else + identity = linphone_core_get_primary_contact(cr->lc); + /*sending out of calls*/ + op = sal_op_new(cr->lc->sal); + linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0)); + + content = linphone_chat_room_create_is_composing_xml(cr); + if (content != NULL) { + sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content, NULL); + ms_free(content); + sal_op_unref(op); + } +} + +static int linphone_chat_room_stop_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + cr->is_composing = LinphoneIsComposingIdle; + linphone_chat_room_send_is_composing_notification(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + return BELLE_SIP_STOP; +} + +static int linphone_chat_room_refresh_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + linphone_chat_room_send_is_composing_notification(cr); + return BELLE_SIP_CONTINUE; +} + +void linphone_chat_room_compose(LinphoneChatRoom *cr) { + int idle_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_idle_timeout", COMPOSING_DEFAULT_IDLE_TIMEOUT); + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + if (cr->is_composing == LinphoneIsComposingIdle) { + cr->is_composing = LinphoneIsComposingActive; + linphone_chat_room_send_is_composing_notification(cr); + if (!cr->composing_refresh_timer) { + cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, refresh_timeout * 1000, "composing refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->composing_refresh_timer, refresh_timeout * 1000); + } + if (!cr->composing_idle_timer) { + cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, idle_timeout * 1000, "composing idle timeout"); + } + } + belle_sip_source_set_timeout(cr->composing_idle_timer, idle_timeout * 1000); +} + +const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) { + switch (state) { + case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle"; + case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress"; + case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered"; + case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; + case LinphoneChatMessageStateFileTransferError:return "LinphoneChatMessageStateFileTransferError"; + case LinphoneChatMessageStateFileTransferDone: return "LinphoneChatMessageStateFileTransferDone "; + } + return NULL; } -/** - * Returns the chatroom this message belongs to. -**/ LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){ return msg->chat_room; } -/** - * Returns the peer (remote) address for the message. -**/ const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { return linphone_chat_room_get_peer_address(msg->chat_room); } -/** - *User pointer set function - */ void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) { message->message_userdata=ud; } -/** - * User pointer get function - */ void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) { return message->message_userdata; } -/** - * Linphone message can carry external body as defined by rfc2017 - * @param message #LinphoneChatMessage - * @return external body url or NULL if not present. - */ const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) { return message->external_body_url; } -/** - * Linphone message can carry external body as defined by rfc2017 - * - * @param message a LinphoneChatMessage - * @param url ex: access-type=URL; URL="http://www.foo.com/file" - */ -void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) { +void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message, const char* url) { if (message->external_body_url) { ms_free(message->external_body_url); } message->external_body_url=url?ms_strdup(url):NULL; } -/** - * Set origin of the message - *@param message #LinphoneChatMessage obj - *@param from #LinphoneAddress origin of this message (copied) - */ -void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) { +const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message){ + return message->appdata; +} + +void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data){ + if ( message->appdata ){ + ms_free(message->appdata); + } + message->appdata = data? ms_strdup(data) : NULL; + linphone_chat_message_store_appdata(message); +} + + +const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage*message) { + return message->file_transfer_information; +} + +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const uint8_t *buffer, size_t size){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + + if (!chatMsg->http_request || belle_http_request_is_cancelled(chatMsg->http_request)) { + ms_warning("Cancelled request for msg [%p], ignoring %s", chatMsg, __FUNCTION__); + return; + } + + /* first call may be with a zero size, ignore it */ + if (size == 0) { + return; + } + + if (linphone_content_get_key(chatMsg->file_transfer_information) != NULL) { /* we have a key, we must decrypt the file */ + /* get data from callback to a plainBuffer */ + char *plainBuffer = (char *)malloc(size); + lime_decryptFile(linphone_content_get_cryptoContext_address(chatMsg->file_transfer_information), (unsigned char *)linphone_content_get_key(chatMsg->file_transfer_information), size, plainBuffer, (char *)buffer); + if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data((unsigned char *)plainBuffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + /* legacy: call back given by application level */ + linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size); + } + free(plainBuffer); + } else { /* regular file, no deciphering */ + if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) { + LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size); + linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + /* Legacy: call back given by application level */ + linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size); + } + } + + return; +} + + +static LinphoneContent* linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t* message ){ + LinphoneContent *content = linphone_content_new(); + + belle_sip_header_content_length_t* content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(message, "Content-Length")); + belle_sip_header_content_type_t* content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(message, "Content-Type")); + const char* type = NULL,*subtype = NULL; + + linphone_content_set_name(content, ""); + + if( content_type_hdr ){ + type = belle_sip_header_content_type_get_type(content_type_hdr); + subtype = belle_sip_header_content_type_get_subtype(content_type_hdr); + ms_message("Extracted content type %s / %s from header", type?type:"", subtype?subtype:""); + if( type ) linphone_content_set_type(content, type); + if( subtype ) linphone_content_set_subtype(content, subtype); + } + + if( content_length_hdr ){ + linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr)); + ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content)); + } + + return content; +} + +static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event){ + if (event->response){ + /*we are receiving a response, set a specific body handler to acquire the response. + * if not done, belle-sip will create a memory body handler, the default*/ + LinphoneChatMessage *message=(LinphoneChatMessage *)belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message"); + belle_sip_message_t* response = BELLE_SIP_MESSAGE(event->response); + size_t body_size = 0; + + if( message->file_transfer_information == NULL ){ + ms_warning("No file transfer information for message %p: creating...", message); + message->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response); + } + + if( message->file_transfer_information ){ + body_size = linphone_content_get_size(message->file_transfer_information); + } + + if (message->file_transfer_filepath == NULL) { + belle_sip_message_set_body_handler( + (belle_sip_message_t*)event->response, + (belle_sip_body_handler_t*)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message) + ); + } else { + belle_sip_body_handler_t *bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(message->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, message); + if (belle_sip_body_handler_get_size(bh) == 0) { + /* If the size of the body has not been initialized from the file stat, use the one from the file_transfer_information. */ + belle_sip_body_handler_set_size(bh, body_size); + } + belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, bh); + } + } +} + +static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event){ + /* check the answer code */ + if (event->response){ + int code=belle_http_response_get_status_code(event->response); + if (code==200) { + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + /* if the file was encrypted, finish the decryption and free context */ + if (linphone_content_get_key(chatMsg->file_transfer_information) != NULL) { + lime_decryptFile(linphone_content_get_cryptoContext_address(chatMsg->file_transfer_information), NULL, 0, NULL, NULL); + } + /* file downloaded succesfully, call again the callback with size at zero */ + if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) { + LinphoneBuffer *lb = linphone_buffer_new(); + linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb); + linphone_buffer_unref(lb); + } else { + linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0); + } + chatMsg->state = LinphoneChatMessageStateFileTransferDone; + if (chatMsg->cb) { + chatMsg->cb(chatMsg, chatMsg->state, chatMsg->cb_ud); + } + if (linphone_chat_message_cbs_get_msg_state_changed(chatMsg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(chatMsg->callbacks)(chatMsg, chatMsg->state); + } + } + } +} + +void linphone_chat_message_download_file(LinphoneChatMessage *message) { + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + const char *url=message->external_body_url; + char* ua; + + if (url == NULL) { + ms_error("Cannot download file from chat message [%p] because url is NULL",message); + return; + } + ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); + uri=belle_generic_uri_parse(url); + + message->http_request=belle_http_request_create("GET", + uri, + belle_sip_header_create("User-Agent",ua), + NULL); + belle_sip_object_ref(message->http_request); /* keep a reference on the request to be able to cancel the download */ + ms_free(ua); + + cbs.process_response_headers=linphone_chat_process_response_headers_from_get_file; + cbs.process_response=linphone_chat_process_response_from_get_file; + cbs.process_io_error=process_io_error_download; + cbs.process_auth_requested=process_auth_requested_download; + l=belle_http_request_listener_create_from_callbacks(&cbs, (void *)message); + belle_sip_object_data_set(BELLE_SIP_OBJECT(message->http_request),"message",(void *)message,NULL); + message->state = LinphoneChatMessageStateInProgress; /* start the download, status is In Progress */ + belle_http_provider_send_request(message->chat_room->lc->http_provider,message->http_request,l); +} + +void linphone_chat_message_start_file_download(LinphoneChatMessage *message, LinphoneChatMessageStateChangedCb status_cb, void *ud) { + message->cb = status_cb; + message->cb_ud = ud; + linphone_chat_message_download_file(message); +} + +void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) { + if (msg->http_request) { + if (!belle_http_request_is_cancelled(msg->http_request)) { + ms_message("Cancelling file transfer %s - msg [%p] chat room[%p]", (msg->external_body_url==NULL)?linphone_core_get_file_transfer_server(msg->chat_room->lc):msg->external_body_url, msg, msg->chat_room); + + belle_http_provider_cancel_request(msg->chat_room->lc->http_provider, msg->http_request); + belle_sip_object_unref(msg->http_request); + msg->http_request = NULL; + msg->state = LinphoneChatMessageStateNotDelivered; + if (msg->cb) { + msg->cb(msg, msg->state, msg->cb_ud); + } + if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) { + linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state); + } + } + } else { + ms_message("No existing file transfer - nothing to cancel"); + } +} + + +void linphone_chat_message_set_from_address(LinphoneChatMessage* message, const LinphoneAddress* from) { if(message->from) linphone_address_destroy(message->from); message->from=linphone_address_clone(from); } -/** - * Get origin of the message - *@param message #LinphoneChatMessage obj - *@return #LinphoneAddress - */ -LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) { +const LinphoneAddress* linphone_chat_message_get_from_address(const LinphoneChatMessage* message) { return message->from; } -/** - * Get the time the message was sent. - */ +void linphone_chat_message_set_to_address(LinphoneChatMessage* message, const LinphoneAddress* to) { + if(message->to) linphone_address_destroy(message->to); + message->to=linphone_address_clone(to); +} + +const LinphoneAddress* linphone_chat_message_get_to_address(const LinphoneChatMessage* message){ + if (message->to) return message->to; + if (message->dir==LinphoneChatMessageOutgoing){ + return message->chat_room->peer_url; + } + return NULL; +} + +LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message){ + return message->dir==LinphoneChatMessageOutgoing ? message->from : message->to; +} + time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) { return message->time; } -/** - * Get text part of this message - * @return text or NULL if no text. - */ +LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message) { + return message->state; +} + const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) { return message->message; } -/** - * Add custom headers to the message. - * @param message the message - * @param header_name name of the header_name - * @param header_value header value -**/ void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value){ message->custom_headers=sal_custom_header_append(message->custom_headers,header_name,header_value); } -/** - * Retrieve a custom header value given its name. - * @param message the message - * @param header_name header name searched -**/ const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name){ return sal_custom_header_find(message->custom_headers,header_name); } -/** - * Duplicate a LinphoneChatMessage -**/ +bool_t linphone_chat_message_is_read(LinphoneChatMessage* message) { + return message->is_read; +} + +bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message) { + return message->dir == LinphoneChatMessageOutgoing; +} + +unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message) { + return message->storage_id; +} + LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) { /*struct _LinphoneChatMessage { char* message; @@ -347,31 +1355,98 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) void* message_userdata; char* external_body_url; LinphoneAddress* from; + time_t time; + SalCustomHeader *custom_headers; + LinphoneChatMessageState state; };*/ LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message); if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url); + if (msg->appdata) new_message->appdata = ms_strdup(msg->appdata); new_message->cb=msg->cb; new_message->cb_ud=msg->cb_ud; new_message->message_userdata=msg->message_userdata; 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); + if (msg->file_transfer_filepath) new_message->file_transfer_filepath=ms_strdup(msg->file_transfer_filepath); + if (msg->file_transfer_information) new_message->file_transfer_information=linphone_content_copy(msg->file_transfer_information); return new_message; } -/** - * Destroys a LinphoneChatMessage. -**/ -void linphone_chat_message_destroy(LinphoneChatMessage* msg) { +void linphone_chat_message_destroy(LinphoneChatMessage* msg){ + belle_sip_object_unref(msg); +} + +static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) { + if (msg->op) sal_op_release(msg->op); if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); + if (msg->appdata) ms_free(msg->appdata); if (msg->from) linphone_address_destroy(msg->from); + if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); - ms_free(msg); + if (msg->content_type) ms_free(msg->content_type); + if (msg->file_transfer_information) { + linphone_content_unref(msg->file_transfer_information); + } + if (msg->file_transfer_filepath != NULL) { + ms_free(msg->file_transfer_filepath); + } + linphone_chat_message_cbs_unref(msg->callbacks); +} + +LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg){ + belle_sip_object_ref(msg); + return msg; +} + +void linphone_chat_message_unref(LinphoneChatMessage *msg){ + belle_sip_object_unref(msg); +} + +static void linphone_chat_message_release(LinphoneChatMessage *msg){ + /*mark the chat message as orphan (it has no chat room anymore), and unref it*/ + msg->chat_room = NULL; + linphone_chat_message_unref(msg); +} + +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){ + return linphone_error_info_from_sal_op(msg->op); +} + +LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) { + return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } -/** - * @} - */ +void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) { + if (msg->file_transfer_filepath != NULL) { + ms_free(msg->file_transfer_filepath); + } + msg->file_transfer_filepath = ms_strdup(filepath); +} +const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) { + return msg->file_transfer_filepath; +} +LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg) { + return msg->callbacks; +} + +LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content) { + LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); + msg->callbacks=linphone_chat_message_cbs_new(); + msg->chat_room=(LinphoneChatRoom*)cr; + msg->message = NULL; + msg->is_read=TRUE; + msg->file_transfer_information = linphone_content_copy(initial_content); + msg->dir=LinphoneChatMessageOutgoing; + linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc))); + msg->content_type=NULL; /* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */ + msg->http_request=NULL; /* this will store the http request during file upload to the server */ + return msg; +} diff --git a/coreapi/conference.c b/coreapi/conference.c index c98392e95..5479c8315 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -22,7 +22,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 "private.h" #include "lpconfig.h" @@ -41,6 +41,7 @@ static void conference_check_init(LinphoneConference *ctx, int samplerate){ MSAudioConferenceParams params; params.samplerate=samplerate; ctx->conf=ms_audio_conference_new(¶ms); + ctx->terminated=FALSE; } } @@ -74,7 +75,7 @@ void linphone_core_conference_check_uninit(LinphoneCore *lc){ if (ctx->conf){ int remote_count=remote_participants_count(ctx); ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx)); - if (remote_count==1){ + if (remote_count==1 && !ctx->terminated){ convert_conference_to_call(lc); } if (remote_count==0){ @@ -86,7 +87,7 @@ void linphone_core_conference_check_uninit(LinphoneCore *lc){ ctx->record_endpoint=NULL; } } - + if (ms_audio_conference_get_size(ctx->conf)==0){ ms_audio_conference_destroy(ctx->conf); ctx->conf=NULL; @@ -98,8 +99,8 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){ LinphoneCore *lc=call->core; LinphoneConference *conf=&lc->conf_ctx; MSAudioEndpoint *ep; - call->params.has_video = FALSE; - call->camera_active = FALSE; + call->params->has_video = FALSE; + call->camera_enabled = FALSE; ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE); ms_audio_conference_add_member(conf->conf,ep); ms_audio_conference_mute_member(conf->conf,ep,muted); @@ -109,7 +110,7 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){ void linphone_call_remove_from_conf(LinphoneCall *call){ LinphoneCore *lc=call->core; LinphoneConference *conf=&lc->conf_ctx; - + ms_audio_conference_remove_member(conf->conf,call->endpoint); ms_audio_endpoint_release_from_stream(call->endpoint); call->endpoint=NULL; @@ -127,12 +128,12 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){ /*create a dummy audiostream in order to extract the local part of it */ /* network address and ports have no meaning and are not used here. */ AudioStream *st=audio_stream_new(65000,65001,FALSE); - MSSndCard *playcard=lc->sound_conf.lsd_card ? + MSSndCard *playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; MSSndCard *captcard=lc->sound_conf.capt_sndcard; const MSAudioConferenceParams *params=ms_audio_conference_get_params(conf->conf); conf->local_dummy_profile=make_dummy_profile(params->samplerate); - + audio_stream_start_full(st, conf->local_dummy_profile, "127.0.0.1", 65000, @@ -150,13 +151,13 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){ conf->local_participant=st; conf->local_endpoint=ms_audio_endpoint_get_from_stream(st,FALSE); ms_audio_conference_add_member(conf->conf,conf->local_endpoint); - + } /** * Returns the sound volume (mic input) of the local participant of the conference. * @param lc the linphone core - * @returns the measured input volume expressed in dbm0. + * @return the measured input volume expressed in dbm0. **/ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ LinphoneConference *conf=&lc->conf_ctx; @@ -165,7 +166,7 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ float vol=0; ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); return vol; - + } return LINPHONE_VOLUME_DB_LOWEST; } @@ -174,37 +175,42 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ * Merge a call into a conference. * @param lc the linphone core * @param call an established call, either in LinphoneCallStreamsRunning or LinphoneCallPaused state. - * + * * If this is the first call that enters the conference, the virtual conference will be created automatically. * If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference. * If the call was in paused state, then it is automatically resumed when entering into the conference. - * - * @returns 0 if successful, -1 otherwise. + * + * @return 0 if successful, -1 otherwise. **/ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ - LinphoneCallParams params; LinphoneConference *conf=&lc->conf_ctx; - - if (call->current_params.in_conference){ + + if (call->current_params->in_conference){ ms_error("Already in conference"); return -1; } conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000)); - call->params.in_conference=TRUE; - call->params.has_video=FALSE; - call->params.media_encryption=LinphoneMediaEncryptionNone; - params=call->params; - if (call->state==LinphoneCallPaused) + + if (call->state==LinphoneCallPaused){ + call->params->in_conference=TRUE; + call->params->has_video=FALSE; linphone_core_resume_call(lc,call); - else if (call->state==LinphoneCallStreamsRunning){ - /*this will trigger a reINVITE that will later redraw the streams */ + }else if (call->state==LinphoneCallStreamsRunning){ + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + params->in_conference=TRUE; + params->has_video=FALSE; + if (call->audiostream || call->videostream){ - linphone_call_stop_media_streams (call); /*free the audio & video local resources*/ + linphone_call_stop_media_streams(call); /*free the audio & video local resources*/ + linphone_call_init_media_streams(call); } if (call==lc->current_call){ lc->current_call=NULL; } - linphone_core_update_call(lc,call,¶ms); + /*this will trigger a reINVITE that will later redraw the streams */ + /*FIXME probably a bit too much to just redraw streams !*/ + linphone_core_update_call(lc,call,params); + linphone_call_params_destroy(params); add_local_endpoint(conf,lc); }else{ ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state)); @@ -217,8 +223,8 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a int err=0; char *str; - if (!call->current_params.in_conference){ - if (call->params.in_conference){ + if (!call->current_params->in_conference){ + if (call->params->in_conference){ ms_warning("Not (yet) in conference, be patient"); return -1; }else{ @@ -226,24 +232,26 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a return -1; } } - call->params.in_conference=FALSE; + call->params->in_conference=FALSE; str=linphone_call_get_remote_address_as_string(call); ms_message("%s will be removed from conference", str); ms_free(str); if (active){ + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + params->in_conference=FALSE; // reconnect local audio with this call if (linphone_core_is_in_conference(lc)){ ms_message("Leaving conference for reconnecting with unique call."); linphone_core_leave_conference(lc); } ms_message("Updating call to actually remove from conference"); - err=linphone_core_update_call(lc,call,&call->params); + err=linphone_core_update_call(lc,call,params); + linphone_call_params_destroy(params); } else{ ms_message("Pausing call to actually remove from conference"); - err=linphone_core_pause_call(lc,call); + err=_linphone_core_pause_call(lc,call); } - return err; } @@ -259,7 +267,7 @@ static int convert_conference_to_call(LinphoneCore *lc){ while (calls) { LinphoneCall *rc=(LinphoneCall*)calls->data; calls=calls->next; - if (rc->params.in_conference) { // not using current_param + if (rc->params->in_conference) { // not using current_param bool_t active_after_removed=linphone_core_is_in_conference(lc); err=remove_from_conference(lc, rc, active_after_removed); break; @@ -272,16 +280,16 @@ static int convert_conference_to_call(LinphoneCore *lc){ * Remove a call from the conference. * @param lc the linphone core * @param call a call that has been previously merged into the conference. - * + * * After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state. * If one single remote participant is left alone together with the local user in the conference after the removal, then the conference is * automatically transformed into a simple call in StreamsRunning state. * The conference's resources are then automatically destroyed. - * + * * In other words, unless linphone_core_leave_conference() is explicitely called, the last remote participant of a conference is automatically * put in a simple call in running state. - * - * @returns 0 if successful, -1 otherwise. + * + * @return 0 if successful, -1 otherwise. **/ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ int err; @@ -303,11 +311,6 @@ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ return err; } -/** - * Indicates whether the local participant is part of the conference. - * @param lc the linphone core - * @returns TRUE if the local participant is in the conference, FALSE otherwise. -**/ bool_t linphone_core_is_in_conference(const LinphoneCore *lc){ return lc->conf_ctx.local_participant!=NULL; } @@ -316,7 +319,7 @@ bool_t linphone_core_is_in_conference(const LinphoneCore *lc){ * Moves the local participant out of the conference. * @param lc the linphone core * When the local participant is out of the conference, the remote participants can continue to talk normally. - * @returns 0 if successful, -1 otherwise. + * @return 0 if successful, -1 otherwise. **/ int linphone_core_leave_conference(LinphoneCore *lc){ LinphoneConference *conf=&lc->conf_ctx; @@ -328,13 +331,13 @@ int linphone_core_leave_conference(LinphoneCore *lc){ /** * Moves the local participant inside the conference. * @param lc the linphone core - * - * Makes the local participant to join the conference. + * + * Makes the local participant to join the conference. * Typically, the local participant is by default always part of the conference when joining an active call into a conference. * However, by calling linphone_core_leave_conference() and linphone_core_enter_conference() the application can decide to temporarily * move out and in the local participant from the conference. - * - * @returns 0 if successful, -1 otherwise + * + * @return 0 if successful, -1 otherwise **/ int linphone_core_enter_conference(LinphoneCore *lc){ LinphoneConference *conf; @@ -342,7 +345,7 @@ int linphone_core_enter_conference(LinphoneCore *lc){ return -1; } if (lc->current_call != NULL) { - linphone_core_pause_call(lc, lc->current_call); + _linphone_core_pause_call(lc, lc->current_call); } conf=&lc->conf_ctx; if (conf->local_participant==NULL) add_local_endpoint(conf,lc); @@ -352,17 +355,17 @@ int linphone_core_enter_conference(LinphoneCore *lc){ /** * Add all calls into a conference. * @param lc the linphone core - * + * * Merge all established calls (either in LinphoneCallStreamsRunning or LinphoneCallPaused) into a conference. - * - * @returns 0 if successful, -1 otherwise + * + * @return 0 if successful, -1 otherwise **/ int linphone_core_add_all_to_conference(LinphoneCore *lc) { MSList *calls=lc->calls; while (calls) { LinphoneCall *call=(LinphoneCall*)calls->data; calls=calls->next; - if (!call->current_params.in_conference) { + if (!call->current_params->in_conference) { linphone_core_add_to_conference(lc, call); } } @@ -373,17 +376,20 @@ int linphone_core_add_all_to_conference(LinphoneCore *lc) { /** * Terminates the conference and the calls associated with it. * @param lc the linphone core - * + * * All the calls that were merged to the conference are terminated, and the conference resources are destroyed. - * - * @returns 0 if successful, -1 otherwise + * + * @return 0 if successful, -1 otherwise **/ int linphone_core_terminate_conference(LinphoneCore *lc) { MSList *calls=lc->calls; + LinphoneConference *conf=&lc->conf_ctx; + conf->terminated=TRUE; + while (calls) { LinphoneCall *call=(LinphoneCall*)calls->data; calls=calls->next; - if (call->current_params.in_conference) { + if (call->current_params->in_conference) { linphone_core_terminate_call(lc, call); } } @@ -393,11 +399,11 @@ int linphone_core_terminate_conference(LinphoneCore *lc) { /** * Returns the number of participants to the conference, including the local participant. * @param lc the linphone core - * + * * Typically, after merging two calls into the conference, there is total of 3 participants: * the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls. - * - * @returns the number of participants to the conference + * + * @return the number of participants to the conference **/ int linphone_core_get_conference_size(LinphoneCore *lc) { LinphoneConference *conf=&lc->conf_ctx; diff --git a/coreapi/contact_providers_priv.h b/coreapi/contact_providers_priv.h new file mode 100644 index 000000000..b3d667df6 --- /dev/null +++ b/coreapi/contact_providers_priv.h @@ -0,0 +1,67 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CONTACT_PROVIDERS_PRIV_H +#define CONTACT_PROVIDERS_PRIV_H + +#include "private.h" +#include "linphonecore.h" + +/* Base for contact search and contact provider */ + +struct _LinphoneContactSearch{ + belle_sip_object_t base; + ContactSearchID id; + char* predicate; + ContactSearchCallback cb; + void* data; +}; + +#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) + + +struct _LinphoneContactProvider { + belle_sip_object_t base; + LinphoneCore* lc; +}; + +#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider) + +typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data ); +typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request ); + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t) + const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */ + + /* pure virtual methods: inheriting objects must implement these */ + LinphoneContactProviderStartSearchMethod begin_search; + LinphoneContactProviderCancelSearchMethod cancel_search; +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + +/* LDAP search and contact providers */ + + +#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch) + +#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + + +#endif // CONTACT_PROVIDERS_PRIV_H diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c new file mode 100644 index 000000000..2ee037c78 --- /dev/null +++ b/coreapi/contactprovider.c @@ -0,0 +1,138 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "contact_providers_priv.h" +#include "contactprovider.h" +#include + +/* ############################ * + * LinphoneContactSearchRequest * + * ############################ */ + +void linphone_contact_search_init(LinphoneContactSearch* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + static unsigned int request_id_counter = 1; + obj->id = request_id_counter++; // unique id + obj->predicate = ms_strdup(predicate?predicate:""); + obj->cb = cb; + obj->data = cb_data; +} + +static void linphone_contact_search_destroy( LinphoneContactSearch* req) { + if( req->predicate ) ms_free(req->predicate); +} + +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj) +{ + return obj->id; +} + +const char*linphone_contact_search_get_predicate(LinphoneContactSearch* obj) +{ + return obj->predicate; +} + +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends) +{ + if( req->cb ) req->cb(req, friends, req->data); +} + +int linphone_contact_search_compare(const void* a, const void* b) { + LinphoneContactSearch *ra=((LinphoneContactSearch*)a); + LinphoneContactSearch *rb=((LinphoneContactSearch*)b); + return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise +} + +LinphoneContactSearch*linphone_contact_search_ref(void* obj) +{ + return LINPHONE_CONTACT_SEARCH(belle_sip_object_ref(obj)); +} + +void linphone_ldap_contact_search_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +LinphoneContactSearch* linphone_contact_search_cast(void* obj) +{ + return LINPHONE_CONTACT_SEARCH(obj); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactSearch); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_contact_search_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + + + +/* ####################### * + * LinphoneContactProvider * + * ####################### */ + + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc){ + obj->lc = lc; +} + +static void contact_provider_destroy(LinphoneContactProvider* obj){ + (void)obj; +} + +LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* data) +{ + return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->begin_search( LINPHONE_CONTACT_PROVIDER(obj), predicate, cb, data); +} + +unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch* request) +{ + return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->cancel_search( LINPHONE_CONTACT_PROVIDER(obj), request); +} + +LinphoneContactProvider* linphone_contact_provider_ref(void* obj) +{ + return LINPHONE_CONTACT_PROVIDER(belle_sip_object_ref(obj)); +} + +void linphone_contact_provider_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +LinphoneContactProvider*linphone_contact_provider_cast(void* obj) +{ + return LINPHONE_CONTACT_PROVIDER(obj); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider); +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider) + { + BELLE_SIP_VPTR_INIT(LinphoneContactProvider,belle_sip_object_t,TRUE), + (belle_sip_object_destroy_t) contact_provider_destroy, + NULL,/*no clone*/ + NULL,/*no marshal*/ + }, + "", + // Pure virtual + NULL, /* begin_search -> pure virtual */ + NULL /* cancel_search -> pure virtual */ +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h new file mode 100644 index 000000000..d5c016562 --- /dev/null +++ b/coreapi/contactprovider.h @@ -0,0 +1,43 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "linphonecore.h" + +/* LinphoneContactSearchRequest */ + +void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, ContactSearchCallback cb, void* cb_data); +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj); +const char* linphone_contact_search_get_predicate(LinphoneContactSearch* obj); +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends); +LINPHONE_PUBLIC LinphoneContactSearch* linphone_contact_search_ref(void* obj); +void linphone_contact_search_unref(void* obj); +LinphoneContactSearch* linphone_contact_search_cast( void*obj ); + +/* LinphoneContactProvider */ + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc); +LinphoneCore* linphone_contact_provider_get_core(LinphoneContactProvider* obj); +const char* linphone_contact_provider_get_name(LinphoneContactProvider* obj); +LinphoneContactProvider* linphone_contact_provider_ref(void* obj); +LINPHONE_PUBLIC void linphone_contact_provider_unref(void* obj); +LINPHONE_PUBLIC LinphoneContactProvider* linphone_contact_provider_cast( void*obj ); + +LINPHONE_PUBLIC LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* data); +unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj, + LinphoneContactSearch* request); diff --git a/coreapi/content.c b/coreapi/content.c new file mode 100644 index 000000000..9f5cd4fee --- /dev/null +++ b/coreapi/content.c @@ -0,0 +1,243 @@ +/* +linphone +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "private.h" + + + +static void linphone_content_destroy(LinphoneContent *content) { + if (content->owned_fields == TRUE) { + if (content->lcp.type) belle_sip_free(content->lcp.type); + if (content->lcp.subtype) belle_sip_free(content->lcp.subtype); + if (content->lcp.data) belle_sip_free(content->lcp.data); + if (content->lcp.encoding) belle_sip_free(content->lcp.encoding); + if (content->lcp.name) belle_sip_free(content->lcp.name); + if (content->lcp.key) belle_sip_free(content->lcp.key); + /* note : crypto context is allocated/destroyed by the encryption function */ + } +} + +static void linphone_content_clone(LinphoneContent *obj, const LinphoneContent *ref) { + obj->owned_fields = TRUE; + linphone_content_set_type(obj, linphone_content_get_type(ref)); + linphone_content_set_subtype(obj, linphone_content_get_subtype(ref)); + linphone_content_set_encoding(obj, linphone_content_get_encoding(ref)); + linphone_content_set_name(obj, linphone_content_get_name(ref)); + linphone_content_set_key(obj, linphone_content_get_key(ref), linphone_content_get_key_size(ref)); + if (linphone_content_get_buffer(ref) != NULL) { + linphone_content_set_buffer(obj, linphone_content_get_buffer(ref), linphone_content_get_size(ref)); + } else { + linphone_content_set_size(obj, linphone_content_get_size(ref)); + } +} + + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContent); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneContent, belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_content_destroy, + (belle_sip_object_clone_t)linphone_content_clone, + NULL, // marshal + TRUE +); + + +LinphoneContent * linphone_core_create_content(LinphoneCore *lc) { + return linphone_content_new(); +} + +LinphoneContent * linphone_content_ref(LinphoneContent *content) { + belle_sip_object_ref(content); + return content; +} + +void linphone_content_unref(LinphoneContent *content) { + belle_sip_object_unref(content); +} + +void *linphone_content_get_user_data(const LinphoneContent *content) { + return content->user_data; +} + +void linphone_content_set_user_data(LinphoneContent *content, void *ud) { + content->user_data = ud; +} + +const char * linphone_content_get_type(const LinphoneContent *content) { + return content->lcp.type; +} + +void linphone_content_set_type(LinphoneContent *content, const char *type) { + if (content->lcp.type != NULL) { + belle_sip_free(content->lcp.type); + content->lcp.type = NULL; + } + if (type != NULL) { + content->lcp.type = belle_sip_strdup(type); + } +} + +const char * linphone_content_get_subtype(const LinphoneContent *content) { + return content->lcp.subtype; +} + +void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) { + if (content->lcp.subtype != NULL) { + belle_sip_free(content->lcp.subtype); + content->lcp.subtype = NULL; + } + if (subtype != NULL) { + content->lcp.subtype = belle_sip_strdup(subtype); + } +} + +void * linphone_content_get_buffer(const LinphoneContent *content) { + return content->lcp.data; +} + +void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size) { + content->lcp.size = size; + content->lcp.data = belle_sip_malloc(size + 1); + memcpy(content->lcp.data, buffer, size); + ((char *)content->lcp.data)[size] = '\0'; +} + +const char * linphone_content_get_string_buffer(const LinphoneContent *content) { + return (char *)content->lcp.data; +} + +void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer) { + content->lcp.size = strlen(buffer); + content->lcp.data = belle_sip_strdup(buffer); +} + +size_t linphone_content_get_size(const LinphoneContent *content) { + return content->lcp.size; +} + +void linphone_content_set_size(LinphoneContent *content, size_t size) { + content->lcp.size = size; +} + +const char * linphone_content_get_encoding(const LinphoneContent *content) { + return content->lcp.encoding; +} + +void linphone_content_set_encoding(LinphoneContent *content, const char *encoding) { + if (content->lcp.encoding != NULL) { + belle_sip_free(content->lcp.encoding); + content->lcp.encoding = NULL; + } + if (encoding != NULL) { + content->lcp.encoding = belle_sip_strdup(encoding); + } +} + +const char * linphone_content_get_name(const LinphoneContent *content) { + return content->lcp.name; +} + +void linphone_content_set_name(LinphoneContent *content, const char *name) { + if (content->lcp.name != NULL) { + belle_sip_free(content->lcp.name); + content->lcp.name = NULL; + } + if (name != NULL) { + content->lcp.name = belle_sip_strdup(name); + } +} + +size_t linphone_content_get_key_size(const LinphoneContent *content) { + return content->lcp.keyLength; +} + +const char * linphone_content_get_key(const LinphoneContent *content) { + return content->lcp.key; +} + +void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength) { + if (content->lcp.key != NULL) { + belle_sip_free(content->lcp.key); + content->lcp.key = NULL; + } + if (key != NULL) { + content->lcp.key = belle_sip_malloc(keyLength); + memcpy(content->lcp.key, key, keyLength); + } +} + +/* crypto context is managed(allocated/freed) by the encryption function, so provide the address of field in the private structure */ +void ** linphone_content_get_cryptoContext_address(LinphoneContent *content) { + return &(content->lcp.cryptoContext); +} + + +LinphoneContent * linphone_content_new(void) { + LinphoneContent *content = belle_sip_object_new(LinphoneContent); + belle_sip_object_ref(content); + content->owned_fields = TRUE; + content->lcp.cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */ + return content; +} + +LinphoneContent * linphone_content_copy(const LinphoneContent *ref) { + return (LinphoneContent *)belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(ref))); +} + +LinphoneContent * linphone_content_from_sal_body(const SalBody *ref) { + if (ref && ref->type) { + LinphoneContent *content = linphone_content_new(); + linphone_content_set_type(content, ref->type); + linphone_content_set_subtype(content, ref->subtype); + linphone_content_set_encoding(content, ref->encoding); + if (ref->data != NULL) { + linphone_content_set_buffer(content, ref->data, ref->size); + } else { + linphone_content_set_size(content, ref->size); + } + return content; + } + return NULL; +} + +SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content) { + if (content && linphone_content_get_type(content)) { + body->type = linphone_content_get_type(content); + body->subtype = linphone_content_get_subtype(content); + body->data = linphone_content_get_buffer(content); + body->size = linphone_content_get_size(content); + body->encoding = linphone_content_get_encoding(content); + return body; + } + return NULL; +} + + + +LinphoneContent * linphone_content_private_to_linphone_content(const LinphoneContentPrivate *lcp) { + LinphoneContent *content = belle_sip_object_new(LinphoneContent); + memcpy(&content->lcp, lcp, sizeof(LinphoneContentPrivate)); + content->owned_fields = FALSE; + return content; +} + +LinphoneContentPrivate * linphone_content_to_linphone_content_private(const LinphoneContent *content) { + return (LinphoneContentPrivate *)&content->lcp; +} diff --git a/coreapi/content.h b/coreapi/content.h new file mode 100644 index 000000000..1e21138eb --- /dev/null +++ b/coreapi/content.h @@ -0,0 +1,231 @@ +/* +content.h +Copyright (C) 2010-2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef LINPHONE_CONTENT_H_ +#define LINPHONE_CONTENT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup misc + * @{ + */ + +/** + * The LinphoneContent object holds data that can be embedded in a signaling message. +**/ +struct _LinphoneContent; +/** + * The LinphoneContent object holds data that can be embedded in a signaling message. +**/ +typedef struct _LinphoneContent LinphoneContent; + +/** + * @deprecated Use LinphoneContent objects instead of this structure. + */ +struct _LinphoneContentPrivate{ + char *type; /** +#include +#include + + +/** + * @addtogroup misc + * @{ +**/ + + +LinphoneDictionary* linphone_dictionary_new() +{ + return belle_sip_dict_create(); +} + +LinphoneDictionary* linphone_dictionary_clone(const LinphoneDictionary* src) +{ + LinphoneDictionary* cloned = linphone_dictionary_new(); + if( cloned ){ + belle_sip_dict_clone(src, cloned); + } + return cloned; +} + +LinphoneDictionary* linphone_dictionary_ref(LinphoneDictionary* obj) +{ + return BELLE_SIP_DICT(belle_sip_object_ref(obj)); +} + +void linphone_dictionary_unref(LinphoneDictionary *obj) +{ + belle_sip_object_unref(obj); +} + +void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value) +{ + belle_sip_dict_set_int(obj, key, value); +} + +int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value) +{ + return belle_sip_dict_get_int(obj, key, default_value); +} + +void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value) +{ + belle_sip_dict_set_string(obj, key, value); +} + +const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value) +{ + return belle_sip_dict_get_string(obj, key, default_value); +} + +void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value) +{ + belle_sip_dict_set_int64(obj, key, value); +} + +int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value) +{ + return belle_sip_dict_get_int64(obj, key, default_value); +} + +int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key) +{ + return belle_sip_dict_remove(obj, key); +} + +void linphone_dictionary_clear(LinphoneDictionary* obj) +{ + belle_sip_dict_clear(obj); +} + +int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key) +{ + return belle_sip_dict_haskey(obj, key); +} + +void linphone_dictionary_foreach(const LinphoneDictionary* obj, void (*apply_func)(const char*, void*, void*), void* userdata) +{ + return belle_sip_dict_foreach(obj, apply_func, userdata); +} + +struct lp_config_to_dict { + const char* section; + const LpConfig* config; + LinphoneDictionary* dict; +}; + +static void lp_config_section_to_dict_cb(const char*key, struct lp_config_to_dict* userdata) +{ + const char* value = lp_config_get_string(userdata->config, userdata->section, key, ""); + linphone_dictionary_set_string(userdata->dict, key, value); +} + +LinphoneDictionary* lp_config_section_to_dict(const LpConfig* lpconfig, const char* section) +{ + LinphoneDictionary* dict = NULL; + struct lp_config_to_dict fd; + fd.config = lpconfig; + fd.section = section; + + dict = linphone_dictionary_new(); + fd.dict = dict; + + lp_config_for_each_entry(lpconfig, section, + (void (*)(const char*, void*))lp_config_section_to_dict_cb, + &fd); + + return dict; +} + +struct lp_config_from_dict { + const char* section; + LpConfig* config; +}; + +static void lp_config_dict_dump_cb( const char* key, void* value, void* userdata) +{ + struct lp_config_from_dict* fd= (struct lp_config_from_dict*)userdata; + lp_config_set_string(fd->config, fd->section, key, (const char*)value); +} + +void lp_config_load_dict_to_section(LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict) +{ + struct lp_config_from_dict pvdata = { section, lpconfig }; + linphone_dictionary_foreach(dict,lp_config_dict_dump_cb, &pvdata); +} + + + +/** + * @} +**/ diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index f0f009747..bff0a00f1 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -29,37 +29,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void ecc_init_filters(EcCalibrator *ecc){ unsigned int rate; + int channels = 1; + int ecc_channels = 1; MSTickerParams params={0}; params.name="Echo calibrator"; params.prio=MS_TICKER_PRIO_HIGH; ecc->ticker=ms_ticker_new_with_params(¶ms); - ecc->sndread=ms_snd_card_create_reader(ecc->play_card); + ecc->sndread=ms_snd_card_create_reader(ecc->capt_card); ms_filter_call_method(ecc->sndread,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ms_filter_call_method(ecc->sndread,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(ecc->sndread,MS_FILTER_SET_NCHANNELS,&ecc_channels); + ms_filter_call_method(ecc->sndread,MS_FILTER_GET_NCHANNELS,&channels); ecc->read_resampler=ms_filter_new(MS_RESAMPLE_ID); ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_SAMPLE_RATE,&rate); ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate); + ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_NCHANNELS,&ecc_channels); + ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels); ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID); ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); - ecc->rec=ms_filter_new(MS_FILE_REC_ID); + ecc->rec=ms_filter_new(MS_VOID_SINK_ID); ms_filter_link(ecc->sndread,0,ecc->read_resampler,0); ms_filter_link(ecc->read_resampler,0,ecc->det,0); ms_filter_link(ecc->det,0,ecc->rec,0); - ecc->play=ms_filter_new(MS_FILE_PLAYER_ID); + ecc->play=ms_filter_new(MS_VOID_SOURCE_ID); ecc->gen=ms_filter_new(MS_DTMF_GEN_ID); ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ecc->write_resampler=ms_filter_new(MS_RESAMPLE_ID); - ecc->sndwrite=ms_snd_card_create_writer(ecc->capt_card); + ecc->sndwrite=ms_snd_card_create_writer(ecc->play_card); ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_NCHANNELS,&ecc_channels); + ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_NCHANNELS,&channels); ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate); ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate); + ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_NCHANNELS,&ecc_channels); + ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels); ms_filter_link(ecc->play,0,ecc->gen,0); ms_filter_link(ecc->gen,0,ecc->write_resampler,0); @@ -67,10 +77,17 @@ static void ecc_init_filters(EcCalibrator *ecc){ ms_ticker_attach(ecc->ticker,ecc->sndread); ms_ticker_attach(ecc->ticker,ecc->play); - + + if (ecc->audio_init_cb != NULL) { + (*ecc->audio_init_cb)(ecc->cb_data); + } } static void ecc_deinit_filters(EcCalibrator *ecc){ + if (ecc->audio_uninit_cb != NULL) { + (*ecc->audio_uninit_cb)(ecc->cb_data); + } + ms_ticker_detach(ecc->ticker,ecc->sndread); ms_ticker_detach(ecc->ticker,ecc->play); @@ -133,8 +150,11 @@ static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, voi static void ecc_play_tones(EcCalibrator *ecc){ MSDtmfGenCustomTone tone; MSToneDetectorDef expected_tone; + + memset(&tone,0,sizeof(tone)); + memset(&expected_tone,0,sizeof(expected_tone)); - ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc); + ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE); /* configure the tones to be scanned */ @@ -161,28 +181,28 @@ static void ecc_play_tones(EcCalibrator *ecc){ /*play an initial tone to startup the audio playback/capture*/ - tone.frequency=140; + tone.frequencies[0]=140; tone.duration=1000; tone.amplitude=0.5; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_sleep(2); - ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc); + ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE); /* play the three tones*/ - tone.frequency=2000; + tone.frequencies[0]=2000; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - tone.frequency=2300; + tone.frequencies[0]=2300; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_usleep(300000); - tone.frequency=2500; + tone.frequencies[0]=2500; tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_sleep(1); @@ -219,12 +239,15 @@ static void * ecc_thread(void *p){ return NULL; } -EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, unsigned int rate, LinphoneEcCalibrationCallback cb, void *cb_data ){ +EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, unsigned int rate, LinphoneEcCalibrationCallback cb, + LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data){ EcCalibrator *ecc=ms_new0(EcCalibrator,1); ecc->rate=rate; ecc->cb=cb; ecc->cb_data=cb_data; + ecc->audio_init_cb=audio_init_cb; + ecc->audio_uninit_cb=audio_uninit_cb; ecc->capt_card=capt_card; ecc->play_card=play_card; ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc); @@ -240,7 +263,8 @@ void ec_calibrator_destroy(EcCalibrator *ecc){ ms_free(ecc); } -int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data){ +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){ @@ -248,7 +272,7 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration return -1; } 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,cb_data); + 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..836b929a7 --- /dev/null +++ b/coreapi/event.c @@ -0,0 +1,368 @@ +/* +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 LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit"; + case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending"; + case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive"; + case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated"; + case LinphoneSubscriptionError: return "LinphoneSubscriptionError"; + case LinphoneSubscriptionExpiring: return "LinphoneSubscriptionExpiring"; + } + return NULL; +} + +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, int expires){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal)); + lev->expires=expires; + return lev; +} + +static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op); + lev->is_out_of_dialog_op=is_out_of_dialog; + return lev; +} + +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { + return linphone_event_new_with_op_base(lc,op,dir,name,FALSE); +} + +LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { + return linphone_event_new_with_op_base(lc,op,dir,name,TRUE); +} + +void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){ + 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; + linphone_core_notify_subscription_state_changed(lev->lc,lev,state); + if (state==LinphoneSubscriptionTerminated){ + linphone_event_unref(lev); + } + } +} + +void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){ + 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; + linphone_core_notify_publish_state_changed(lev->lc,lev,state); + switch(state){ + case LinphonePublishCleared: + if (lev->expires!=-1) + linphone_event_unref(lev); + break; + case LinphonePublishOk: + case LinphonePublishError: + if (lev->expires==-1) + linphone_event_unref(lev); + break; + case LinphonePublishNone: + case LinphonePublishProgress: + case LinphonePublishExpiring: + /*nothing special to do*/ + break; + } + + } +} + +LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){ + return lev->publish_state; +} + +const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){ + return linphone_error_info_from_sal_op(lev->op); +} + +LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ + return linphone_error_info_get_reason(linphone_event_get_error_info(lev)); +} + +LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ + LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires); + linphone_configure_op(lc,lev->op,resource,NULL,TRUE); + sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); + return lev; +} + +LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires); + linphone_event_send_subscribe(lev,body); + return lev; +} + + +int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ + SalBody salbody; + int err; + + if (lev->dir!=LinphoneSubscriptionOutgoing){ + ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription."); + return -1; + } + switch (lev->subscription_state){ + case LinphoneSubscriptionIncomingReceived: + case LinphoneSubscriptionTerminated: + case LinphoneSubscriptionOutgoingInit: + ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state)); + return -1; + break; + case LinphoneSubscriptionNone: + case LinphoneSubscriptionActive: + case LinphoneSubscriptionExpiring: + case LinphoneSubscriptionError: + case LinphoneSubscriptionPending: + /*those states are ok*/ + break; + } + + if (lev->send_custom_headers){ + sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->send_custom_headers=NULL; + }else sal_op_set_sent_custom_header(lev->op,NULL); + + err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body)); + if (err==0){ + if (lev->subscription_state==LinphoneSubscriptionNone) + linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit); + } + return err; +} + +int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ + return linphone_event_send_subscribe(lev,body); +} + +int linphone_event_accept_subscription(LinphoneEvent *lev){ + 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_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ + LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires); + linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0)); + sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); + return lev; +} + +static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){ + SalBody salbody; + int err; + + if (lev->dir!=LinphoneSubscriptionInvalidDir){ + ms_error("linphone_event_update_publish(): this is not a PUBLISH event."); + return -1; + } + if (lev->send_custom_headers){ + sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->send_custom_headers=NULL; + }else sal_op_set_sent_custom_header(lev->op,NULL); + err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body)); + if (err==0){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else if (notify_err){ + linphone_event_set_publish_state(lev,LinphonePublishError); + } + return err; +} + +LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + int err; + LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires); + err=_linphone_event_send_publish(lev,body,FALSE); + if (err==-1){ + linphone_event_unref(lev); + lev=NULL; + } + return lev; +} + + +int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){ + return _linphone_event_send_publish(lev,body,TRUE); +} + +int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) { + return linphone_event_send_publish(lev,body); +} + +void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ + ev->userdata=up; +} + +void *linphone_event_get_user_data(const LinphoneEvent *ev){ + return ev->userdata; +} + +void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){ + ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value); +} + +const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){ + const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op); + return sal_custom_header_find(ch,name); +} + + +void linphone_event_terminate(LinphoneEvent *lev){ + lev->terminating=TRUE; + if (lev->dir==LinphoneSubscriptionIncoming){ + sal_notify_close(lev->op); + }else if (lev->dir==LinphoneSubscriptionOutgoing){ + sal_unsubscribe(lev->op); + } + + if (lev->publish_state!=LinphonePublishNone){ + if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){ + sal_publish(lev->op,NULL,NULL,NULL,0,NULL); + }else sal_op_stop_refreshing(lev->op); + linphone_event_set_publish_state(lev,LinphonePublishCleared); + return; + } + + 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); + 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){ + if (lev->is_out_of_dialog_op){ + return (LinphoneAddress*)sal_op_get_to_address(lev->op); + }else{ + return (LinphoneAddress*)sal_op_get_from_address(lev->op); + } +} + +const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){ + if (lev->is_out_of_dialog_op){ + return (LinphoneAddress*)sal_op_get_from_address(lev->op); + }else{ + return (LinphoneAddress*)sal_op_get_to_address(lev->op); + } +} + +LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){ + return lev->lc; +} + diff --git a/coreapi/event.h b/coreapi/event.h new file mode 100644 index 000000000..fe3f984de --- /dev/null +++ b/coreapi/event.h @@ -0,0 +1,307 @@ +/* +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 event_api + * @{ +**/ + +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, /**< Incoming subscription. */ + LinphoneSubscriptionOutgoing, /**< Outgoing subscription. */ + LinphoneSubscriptionInvalidDir /**< Invalid subscription direction. */ +}; + +/** + * Typedef alias for _LinphoneSubscriptionDir +**/ +typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir; + +/** + * Enum for subscription states. +**/ +enum _LinphoneSubscriptionState{ + LinphoneSubscriptionNone, /**< Initial state, should not be used.**/ + LinphoneSubscriptionOutgoingProgress, /**refresh_generic_subscribe property is set to 0.*/ +}; +/*typo compatibility*/ +#define LinphoneSubscriptionOutoingInit LinphoneSubscriptionOutgoingInit + +#define LinphoneSubscriptionOutgoingInit LinphoneSubscriptionOutgoingProgress +/** + * Typedef for subscription state enum. +**/ +typedef enum _LinphoneSubscriptionState LinphoneSubscriptionState; + +LINPHONE_PUBLIC const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state); + +/** + * Enum for publish states. +**/ +enum _LinphonePublishState{ + LinphonePublishNone, /**< Initial state, do not use**/ + LinphonePublishProgress, /**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; @@ -90,42 +92,27 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){ MSList *elem; for (elem=l;elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend*)elem->data; - if (lf->insub==op) return lf; + if (ms_list_find(lf->insubs, op)) return lf; } return NULL; } 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; - - 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); + LinphoneCore *lc=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,23 +121,21 @@ 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); + LinphoneFriend *obj=belle_sip_object_new(LinphoneFriend); obj->pol=LinphoneSPAccept; - obj->status=LinphoneStatusOffline; + obj->presence=NULL; obj->subscribe=TRUE; - return obj; + 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; @@ -159,13 +144,19 @@ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ return NULL; } fr=linphone_friend_new(); - if (linphone_friend_set_addr(fr,linphone_address)<0){ - linphone_friend_destroy(fr); - return NULL; - } + 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->user_data=data; +} + +void* linphone_friend_get_user_data(const LinphoneFriend *lf){ + return lf->user_data; +} + bool_t linphone_friend_in_list(const LinphoneFriend *lf){ return lf->lc!=NULL; } @@ -187,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); @@ -200,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; } @@ -233,55 +226,25 @@ 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; +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){ + MSList *elem; + if (lf->insubs){ + char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("Want to notify %s",addr); + ms_free(addr); + } + for(elem=lf->insubs; elem!=NULL; elem=elem->next){ + SalOp *op = (SalOp*)elem->data; + sal_notify_presence(op,(SalPresenceModel *)presence); } - return SalPresenceOffline; } -void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){ - 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); - } +void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){ + lf->insubs = ms_list_append(lf->insubs, op); +} + +void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){ + lf->insubs = ms_list_remove(lf->insubs, op); } static void linphone_friend_unsubscribe(LinphoneFriend *lf){ @@ -291,32 +254,49 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ } } -void linphone_friend_close_subscriptions(LinphoneFriend *lf){ - linphone_friend_unsubscribe(lf); - if (lf->insub){ - sal_notify_close(lf->insub); - +static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ + if (lf->outsub!=NULL) { + LinphoneCore *lc=lf->lc; + sal_op_release(lf->outsub); + lf->outsub=NULL; + lf->subscribe_active=FALSE; + /*notify application that we no longer know the presence activity */ + if (lf->presence != NULL) { + linphone_presence_model_unref(lf->presence); + } + lf->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,"unknown activity"); + linphone_core_notify_notify_presence_received(lc,lf); } + lf->initial_subscribes_sent=FALSE; } -void linphone_friend_destroy(LinphoneFriend *lf){ - if (lf->insub) { - sal_op_release(lf->insub); - lf->insub=NULL; - } +void linphone_friend_close_subscriptions(LinphoneFriend *lf){ + linphone_friend_unsubscribe(lf); + ms_list_for_each(lf->insubs, (MSIterateFunc) sal_notify_presence_close); + +} + +static void _linphone_friend_destroy(LinphoneFriend *lf){ + lf->insubs = ms_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release); if (lf->outsub){ 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); } 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; } @@ -326,43 +306,153 @@ 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){ return lf->info; } +/* + * updates the subscriptions. + * If only_when_registered is TRUE, subscribe will be sent only if the friend's corresponding proxy config is in registered. + * Otherwise if the proxy config goes to unregistered state, the subscription refresh will be suspended. + * An optional proxy whose state has changed can be passed to optimize the processing. +**/ +void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *proxy, bool_t only_when_registered){ + int can_subscribe=1; + + if (only_when_registered && (fr->subscribe || fr->subscribe_active)){ + LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(fr->lc,fr->uri); + if (proxy && proxy!=cfg) return; + if (cfg && cfg->state!=LinphoneRegistrationOk){ + char *tmp=linphone_address_as_string(fr->uri); + ms_message("Friend [%s] belongs to proxy config with identity [%s], but this one isn't registered. Subscription is suspended.", + tmp,linphone_proxy_config_get_identity(cfg)); + ms_free(tmp); + can_subscribe=0; + } + } + if (can_subscribe && fr->subscribe && fr->subscribe_active==FALSE){ + ms_message("Sending a new SUBSCRIBE"); + __linphone_friend_do_subscribe(fr); + }else if (can_subscribe && fr->subscribe_active && !fr->subscribe){ + linphone_friend_unsubscribe(fr); + }else if (!can_subscribe && fr->outsub){ + fr->subscribe_active=FALSE; + sal_op_stop_refreshing(fr->outsub); + } +} + void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ + LinphonePresenceModel *model; + 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; } - if (fr->subscribe && fr->subscribe_active==FALSE){ - ms_message("Sending a new SUBSCRIBE"); - __linphone_friend_do_subscribe(fr); - } + if (fr->lc) + linphone_friend_update_subscribes(fr,NULL,linphone_core_should_subscribe_friends_only_when_registered(fr->lc)); ms_message("linphone_friend_apply() done."); lc->bl_refresh=TRUE; fr->commit=FALSE; @@ -377,6 +467,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); @@ -389,30 +487,51 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) if (tmp) ms_free(tmp); return ; } - lc->friends=ms_list_append(lc->friends,lf); + lc->friends=ms_list_append(lc->friends,linphone_friend_ref(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){ +void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered){ const MSList *elem; for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *f=(LinphoneFriend*)elem->data; - if (f->commit) - linphone_friend_apply(f,lc); + linphone_friend_update_subscribes(f,cfg,only_when_registered); } } +bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1); +} + +void linphone_core_send_initial_subscribes(LinphoneCore *lc){ + if (lc->initial_subscribes_sent) return; + lc->initial_subscribes_sent=TRUE; + linphone_core_update_friends_subscriptions(lc,NULL,linphone_core_should_subscribe_friends_only_when_registered(lc)); +} + +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){ + 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){ if (lf->refkey!=NULL){ ms_free(lf->refkey); @@ -428,40 +547,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; - const char *it_username; - const char *it_host; - 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; - it_username=linphone_address_get_username(lf->uri); - 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; } @@ -504,18 +605,18 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde int a; LinphoneFriend *lf; LpConfig *config=lc->config; - + sprintf(item,"friend_%i",index); - + if (!lp_config_has_section(config,item)){ return NULL; } - + tmp=lp_config_get_string(config,item,"url",NULL); if (tmp==NULL) { return NULL; } - lf=linphone_friend_new_with_addr(tmp); + lf=linphone_friend_new_with_address(tmp); if (lf==NULL) { return NULL; } @@ -526,7 +627,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde } a=lp_config_get_int(config,item,"subscribe",0); linphone_friend_send_subscribe(lf,a); - + linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL)); return lf; } @@ -551,9 +652,9 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, char key[50]; char *tmp; const char *refkey; - + sprintf(key,"friend_%i",index); - + if (lf==NULL){ lp_config_clean_section(config,key); return; @@ -586,3 +687,29 @@ void linphone_core_write_friends_config(LinphoneCore* lc) linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */ } +LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr){ + return fr->lc; +} + +LinphoneFriend *linphone_friend_ref(LinphoneFriend *lf) { + belle_sip_object_ref(lf); + return lf; +} + +void linphone_friend_unref(LinphoneFriend *lf) { + belle_sip_object_unref(lf); +} + +/* DEPRECATED */ +void linphone_friend_destroy(LinphoneFriend *lf) { + linphone_friend_unref(lf); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriend); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriend, belle_sip_object_t, + (belle_sip_object_destroy_t) _linphone_friend_destroy, + NULL, // clone + NULL, // marshal + FALSE +); \ No newline at end of file diff --git a/coreapi/gitversion.cmake b/coreapi/gitversion.cmake new file mode 100644 index 000000000..23fecb10c --- /dev/null +++ b/coreapi/gitversion.cmake @@ -0,0 +1,39 @@ +############################################################################ +# gitversion.cmake +# Copyright (C) 2014 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. +# +############################################################################ + +if(GIT_EXECUTABLE) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --always + WORKING_DIRECTORY ${WORK_DIR} + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#define LIBLINPHONE_GIT_VERSION \"${GIT_REVISION}\"" + OUTPUT_FILE ${OUTPUT_DIR}/liblinphone_gitversion.h + ) +else() + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#define LIBLINPHONE_GIT_VERSION \"unknown\"" + OUTPUT_FILE ${OUTPUT_DIR}/liblinphone_gitversion.h + ) +endif() diff --git a/coreapi/help/CMakeLists.txt b/coreapi/help/CMakeLists.txt new file mode 100644 index 000000000..fa6915d8f --- /dev/null +++ b/coreapi/help/CMakeLists.txt @@ -0,0 +1,45 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +find_package(Doxygen) + +if(DOXYGEN_FOUND) + if(DOXYGEN_DOT_FOUND) + set(top_srcdir ${CMAKE_SOURCE_DIR}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + file(GLOB DOC_INPUT_FILES + [^.]*.c + [^.]*.dox + ../[^.]*.h + ../[^.]*.c + ) + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/doc/html/index.html" + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${DOC_INPUT_FILES} + ) + add_custom_target(doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/doc/html/index.html") + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc/html" "${CMAKE_CURRENT_BINARY_DIR}/doc/xml" + DESTINATION "share/doc/linphone-${LINPHONE_VERSION}") + else() + message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.") + endif() +endif() diff --git a/coreapi/help/Doxyfile.in b/coreapi/help/Doxyfile.in index 03dbf91a0..12facea9b 100644 --- a/coreapi/help/Doxyfile.in +++ b/coreapi/help/Doxyfile.in @@ -34,7 +34,7 @@ DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 -ALIASES = +ALIASES = mslist{1}="A list of \ref \1 objects. \xmlonly \1 \endxmlonly" OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES @@ -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..479d2b31d 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -1,7 +1,7 @@ EXTRA_DIST=Doxyfile.in doxygen.dox -SOURCES=doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h +SOURCES=doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h # html doc @@ -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,28 +21,40 @@ $(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 filetransfer helloworld_SOURCES=helloworld.c LINPHONE_TUTOS=$(helloworld_SOURCES) helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(MEDIASTREAMER_LIBS) \ - $(ORTP_LIBS) + $(ORTP_LIBS) \ + $(BELLESIP_LIBS) registration_SOURCES=registration.c LINPHONE_TUTOS+=$(registration_SOURCES) @@ -57,24 +70,33 @@ 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) + +filetransfer_SOURCES=filetransfer.c +LINPHONE_TUTOS+=$(filetransfer_SOURCES) + +filetransfer_LDADD=$(helloworld_LDADD) AM_CFLAGS=\ + -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ + $(STRICT_OPTIONS_CC) \ -DIN_LINPHONE \ $(ORTP_CFLAGS) \ - $(OSIP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ - $(EXOSIP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ $(IPV6_CFLAGS) \ -DORTP_INET6 \ - $(VIDEO_CFLAGS) + $(VIDEO_CFLAGS) \ + $(BELLESIP_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..cd7f13d52 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -1,7 +1,7 @@ /* buddy_status -Copyright (C) 2010 Belledonne Communications SARL +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 @@ -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)); @@ -70,7 +73,7 @@ static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *friend, * Registration state notification callback */ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ - printf("New registration state %s for user id [%s] at proxy [%s]\n" + printf("New registration state %s for user id [%s] at proxy [%s]" ,linphone_registration_state_to_string(cstate) ,linphone_proxy_config_get_identity(cfg) ,linphone_proxy_config_get_addr(cfg)); @@ -84,6 +87,8 @@ int main(int argc, char *argv[]){ char* identity=NULL; char* password=NULL; + LinphoneFriend* my_friend=NULL; + /* takes sip uri identity from the command line arguments */ if (argc>1){ dest_friend=argv[1]; @@ -101,13 +106,13 @@ int main(int argc, char *argv[]){ #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 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*/ /* @@ -120,13 +125,13 @@ int main(int argc, char *argv[]){ LinphoneProxyConfig* proxy_cfg = linphone_proxy_config_new(); /*parse identity*/ LinphoneAddress *from = linphone_address_new(identity); + LinphoneAuthInfo *info; 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); /*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*/ } @@ -149,10 +154,9 @@ int main(int argc, char *argv[]){ while( running && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationProgress); } - 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 +168,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 +177,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/chatroom.c b/coreapi/help/chatroom.c index 51fc4a237..62d75bab9 100644 --- a/coreapi/help/chatroom.c +++ b/coreapi/help/chatroom.c @@ -1,7 +1,7 @@ /* linphone -Copyright (C) 2010 Belledonne Communications SARL +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 @@ -55,7 +55,7 @@ int main(int argc, char *argv[]){ LinphoneCoreVTable vtable={0}; char* dest_friend=NULL; - + LinphoneChatRoom* chat_room; /* takes sip uri identity from the command line arguments */ if (argc>1){ @@ -67,7 +67,7 @@ int main(int argc, char *argv[]){ #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 text_received callback in order to get notifications about incoming message. @@ -81,7 +81,7 @@ int main(int argc, char *argv[]){ /*Next step is to create a chat root*/ - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend); + chat_room = linphone_core_get_chat_room_from_uri(lc,dest_friend); linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/ @@ -92,7 +92,6 @@ int main(int argc, char *argv[]){ } printf("Shutting down...\n"); - linphone_chat_room_destroy(chat_room); linphone_core_destroy(lc); printf("Exited\n"); return 0; diff --git a/coreapi/help/doxygen.dox b/coreapi/help/doxygen.dox index 8b2e6b7b9..a8baa5138 100644 --- a/coreapi/help/doxygen.dox +++ b/coreapi/help/doxygen.dox @@ -53,6 +53,11 @@ /** * @defgroup media_parameters Controlling media parameters + * Multicast + *
Call using rtp multicast addresses are supported for both audio and video with some limitations. Limitations are, no stun, no ice, no encryption. + *
  • Incoming call with multicast address are automatically accepted. The called party switches in a media receive only mode. + *
  • Outgoing call willing to send media to a multicast address can activate multicast using \link linphone_core_enable_video_multicast\endlink or + *\link linphone_core_enable_audio_multicast\endlink . The calling party switches in a media listen send only mode. **/ /** @@ -61,7 +66,7 @@ *like \link linphone_proxy_config_set_server_addr() proxy address \endlink , \link linphone_proxy_config_set_identity() user id \endlink, \link linphone_proxy_config_expires() refresh period \endlink, and so on. *
    A created proxy config using linphone_proxy_config_new(), once configured, must be added to #LinphoneCore using function linphone_core_add_proxy_config(). *
    It is recommended to set a default \link #LinphoneProxyConfig proxy config \endlink using function linphone_core_set_default_proxy(). Once done, if \link #LinphoneProxyConfig a proxy config \endlink has been configured with attribute \link linphone_proxy_config_enable_register() enable register \endlink , next call to linphone_core_iterate() triggers a SIP register. - *
    Registration status is reported by #LinphoneRegistrationStateCb. + *
    Registration status is reported by LinphoneCoreRegistrationStateChangedCb. *
    *
    This pseudo code demonstrates basic registration operations: *
    \code @@ -96,7 +101,7 @@ } \endcode *
    Authentication: - *
    Most of the time, registration requires \ref authentication "authentication" to succed. #LinphoneAuthInfo info must be either added to #LinphoneCore using function linphone_core_add_auth_info() before #LinphoneProxyConfig is added to Linphone core, or on demand from call back #AuthInfoRequested . + *
    Most of the time, registration requires \ref authentication "authentication" to succeed. #LinphoneAuthInfo info must be either added to #LinphoneCore using function linphone_core_add_auth_info() before #LinphoneProxyConfig is added to Linphone core, or on demand from call back #LinphoneCoreAuthInfoRequestedCb. *
    *
    Unregistration: *
    Unregistration or any changes to #LinphoneProxyConfig must be first started by a call to function linphone_proxy_config_edit() and validated by function linphone_proxy_config_done() @@ -152,7 +157,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 @@ -203,7 +208,7 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre * While initiating the second call, the first one is automatically paused. * Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant * (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together. - * This must be done by adding the two calls to the conference using \link linphone_call_add_to_conference() \endlink + * This must be done by adding the two calls to the conference using \link linphone_core_add_to_conference() \endlink * * Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that * they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state. @@ -216,6 +221,12 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre * **/ + +/** + * @defgroup event_api Managing generic subscriptions and publishes + * The LinphoneEvent api allows application to control subscriptions, receive notifications and make publish to peers, in a generic manner. + */ + /** * @defgroup misc Miscenalleous: logs, version strings, config storage **/ @@ -270,7 +281,7 @@ and register a keep-alive handler for periodically refreshing the registration. }]; \endcode
  • Incoming call notification while in background mode -
    Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCallStateCb. Here under a speudo code for this operation: +
    Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCoreCallStateChangedCb. Here under a speudo code for this operation: \code if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) { // Create a new notification diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c new file mode 100644 index 000000000..21cb19115 --- /dev/null +++ b/coreapi/help/filetransfer.c @@ -0,0 +1,203 @@ + +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** + * @defgroup chatroom_tuto Chat room and messaging + * @ingroup tutorials + *This program is a _very_ simple usage example of liblinphone, + *desmonstrating how to send/receive SIP MESSAGE from a sip uri identity passed from the command line. + *
    Argument must be like sip:jehan@sip.linphone.org . + *
    + *ex chatroom sip:jehan@sip.linphone.org + *
    + *@include chatroom.c + + * + */ + +#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; +} +/** + * function invoked to report file transfer progress. + * */ +static void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { + const LinphoneAddress* from_address = linphone_chat_message_get_from(message); + const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); + printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)((offset *100)/total) + ,(linphone_chat_message_is_outgoing(message)?"sent":"received") + , linphone_content_get_type(content) + , linphone_content_get_subtype(content) + ,(linphone_chat_message_is_outgoing(message)?"to":"from") + , address); + free(address); +} +/** + * function invoked when a file transfer is received. + **/ +static void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer){ + FILE* file=NULL; + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk, creating file*/ + file = fopen("receive_file.dump","wb"); + linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/ + } + + file = (FILE*)linphone_chat_message_get_user_data(message); + if (linphone_buffer_is_empty(buffer)) { + printf("File transfert completed\n"); + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + fclose(file); + running=FALSE; + } else { /* store content on a file*/ + if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==-1){ + ms_warning("file_transfer_received() write failed: %s",strerror(errno)); + } + } +} + +char big_file [128000]; + +/* + * function called when the file transfer is initiated. file content should be feed into object LinphoneContent + * */ +static LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){ + size_t size_to_send = MIN(size, sizeof(big_file) - offset); + if (size == 0) return linphone_buffer_new(); /*end of file*/ + return linphone_buffer_new_from_data((uint8_t *)big_file + offset, size_to_send); +} + +/* + * Call back to get delivery status of a message + * */ +static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + const LinphoneAddress* to_address = linphone_chat_message_get_to(msg); + char *to = linphone_address_as_string(to_address); + printf("File transfer sent to [%s] delivery status is [%s] \n" , to + , linphone_chat_message_state_to_string(state)); + free(to); +} + +/* + * Call back called when a message is received + */ +static void message_received(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + const LinphoneContent *file_transfer_info = linphone_chat_message_get_file_transfer_information(msg); + printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", linphone_content_get_name(file_transfer_info), (long int)linphone_content_get_size(file_transfer_info)); + + linphone_chat_message_start_file_download(msg, linphone_file_transfer_state_changed, NULL); + +} + +LinphoneCore *lc; +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + + const char* dest_friend=NULL; + int i; + const char* big_file_content="big file"; + LinphoneChatRoom* chat_room; + LinphoneContent* content; + LinphoneChatMessage* chat_message; + LinphoneChatMessageCbs *cbs; + + /*seting dummy file content to something*/ + for (i=0;i + *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; + LinphoneProxyConfig* proxy_cfg; + LinphoneAddress *from; + LinphoneAuthInfo *info; + const char* server_addr; + + /* 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); + + /*create proxy config*/ + proxy_cfg = linphone_proxy_config_new(); + /*parse identity*/ + 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; + } + 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*/ + 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){ + LinphoneContentPrivate content; + content.type="application"; + content.subtype="goodxml"; + content.data="really cool"; + content.size=strlen((const char*)content.data); + linphone_event_notify(data->ev,LINPHONE_CONTENT(&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..8dbab6440 100644 --- a/coreapi/help/registration.c +++ b/coreapi/help/registration.c @@ -1,7 +1,7 @@ /* linphone -Copyright (C) 2010 Belledonne Communications SARL +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 @@ -60,9 +60,13 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo LinphoneCore *lc; int main(int argc, char *argv[]){ LinphoneCoreVTable vtable={0}; + LinphoneProxyConfig* proxy_cfg; + LinphoneAddress *from; + LinphoneAuthInfo *info; char* identity=NULL; char* password=NULL; + const char* server_addr; /* takes sip uri identity from the command line arguments */ if (argc>1){ @@ -79,7 +83,7 @@ int main(int argc, char *argv[]){ #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. @@ -91,30 +95,28 @@ int main(int argc, char *argv[]){ */ lc=linphone_core_new(&vtable,NULL,NULL,NULL); - LinphoneProxyConfig* proxy_cfg; /*create proxy config*/ proxy_cfg = linphone_proxy_config_new(); /*parse identity*/ - LinphoneAddress *from = linphone_address_new(identity); + 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); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - } + 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*/ + // configure proxy entries + linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/ + 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*/ + 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*/ /* main loop for receiving notifications and doing background linphonecore work: */ diff --git a/coreapi/info.c b/coreapi/info.c new file mode 100644 index 000000000..f33a16997 --- /dev/null +++ b/coreapi/info.c @@ -0,0 +1,124 @@ +/*************************************************************************** + * 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; +}; + + +/** + * Destroy a LinphoneInfoMessage +**/ +void linphone_info_message_destroy(LinphoneInfoMessage *im){ + if (im->content) linphone_content_unref(im->content); + if (im->headers) sal_custom_header_free(im->headers); + ms_free(im); +} + + +LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig){ + LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); + if (orig->content) im->content=linphone_content_copy(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){ + im->content=linphone_content_copy(content); +} + +/** + * Returns the info message's content as a #LinphoneContent structure. +**/ +const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im){ + return (im->content && linphone_content_get_type(im->content)) ? im->content : NULL; +} + +void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, 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) info->content=linphone_content_from_sal_body(body); + linphone_core_notify_info_received(lc,call,info); + linphone_info_message_destroy(info); + } +} diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c new file mode 100644 index 000000000..75b6b19a1 --- /dev/null +++ b/coreapi/ldap/ldapprovider.c @@ -0,0 +1,830 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ldapprovider.h" +#include "private.h" +#include "lpconfig.h" +#include "contact_providers_priv.h" +#include "mediastreamer2/mscommon.h" +#include + +#ifdef BUILD_LDAP +#include +#include + + +#define MAX_RUNNING_REQUESTS 10 +#define FILTER_MAX_SIZE 512 + +struct LDAPFriendData { + char* name; + char* sip; +}; + +struct _LinphoneLDAPContactProvider +{ + LinphoneContactProvider base; + LinphoneDictionary* config; + + LDAP* ld; + MSList* requests; + unsigned int req_count; + + // bind transaction + bool_t connected; + ms_thread_t bind_thread; + + // config + int use_tls; + const char* auth_method; + const char* username; + const char* password; + const char* server; + const char* bind_dn; + + const char* sasl_authname; + const char* sasl_realm; + + const char* base_object; + const char* sip_attr; + const char* name_attr; + const char* filter; + + char** attributes; + + int timeout; + int deref_aliases; + int max_results; + +}; + +struct _LinphoneLDAPContactSearch +{ + LinphoneContactSearch base; + LDAP* ld; + int msgid; + char* filter; + bool_t complete; + MSList* found_entries; + unsigned int found_count; +}; + + +/* ************************* + * LinphoneLDAPContactSearch + * *************************/ + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) +{ + LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); + LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); + + linphone_contact_search_init(base, predicate, cb, cb_data); + + search->ld = cp->ld; + + search->filter = ms_malloc(FILTER_MAX_SIZE); + snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); + search->filter[FILTER_MAX_SIZE-1] = 0; + + return search; +} + +void linphone_ldap_contact_search_destroy_friend( void* entry ) +{ + linphone_friend_destroy((LinphoneFriend*)entry); +} + +unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj) +{ + return obj->found_count; +} + +static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) +{ + //ms_message("~LinphoneLDAPContactSearch(%p)", obj); + ms_list_for_each(obj->found_entries, linphone_ldap_contact_search_destroy_friend); + obj->found_entries = ms_list_free(obj->found_entries); + if( obj->filter ) ms_free(obj->filter); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch); +BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, + (belle_sip_object_destroy_t)linphone_ldap_contact_search_destroy, + NULL, + NULL, + TRUE +); + + +/* *************************** + * LinphoneLDAPContactProvider + * ***************************/ + +static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid ); +static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); +static bool_t linphone_ldap_contact_provider_iterate(void *data); +static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact); +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req); + +static void linphone_ldap_contact_provider_destroy_request_cb(void *req) +{ + belle_sip_object_unref(req); +} + +static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) +{ + //ms_message("linphone_ldap_contact_provider_destroy"); + linphone_core_remove_iterate_hook(LINPHONE_CONTACT_PROVIDER(obj)->lc, linphone_ldap_contact_provider_iterate,obj); + + // clean pending requests + ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request_cb); + + if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); + obj->ld = NULL; + + if( obj->config ) linphone_dictionary_unref(obj->config); + + linphone_ldap_contact_provider_conf_destroy(obj); +} + +static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) +{ + if( strcmp(attr_name, obj->name_attr ) == 0 ){ + lf->name = ms_strdup(attr_value); + } else if( strcmp(attr_name, obj->sip_attr) == 0 ) { + lf->sip = ms_strdup(attr_value); + } + + // return 1 if the structure has enough data to create a linphone friend + if( lf->name && lf->sip ) + return 1; + else + return 0; + +} + +static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message ) +{ + int msgtype = ldap_msgtype(message); + + switch(msgtype){ + + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_EXTENDED: + { + LDAPMessage *entry = ldap_first_entry(obj->ld, message); + LinphoneCore* lc = LINPHONE_CONTACT_PROVIDER(obj)->lc; + + while( entry != NULL ){ + + struct LDAPFriendData ldap_data = {0}; + bool_t contact_complete = FALSE; + BerElement* ber = NULL; + char* attr = ldap_first_attribute(obj->ld, entry, &ber); + + while( attr ){ + struct berval** values = ldap_get_values_len(obj->ld, entry, attr); + struct berval** it = values; + + while( values && *it && (*it)->bv_val && (*it)->bv_len ) + { + contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); + if( contact_complete ) break; + + it++; + } + + if( values ) ldap_value_free_len(values); + ldap_memfree(attr); + + if( contact_complete ) break; + + attr = ldap_next_attribute(obj->ld, entry, ber); + } + + if( contact_complete ) { + LinphoneAddress* la = linphone_core_interpret_url(lc, ldap_data.sip); + if( la ){ + LinphoneFriend* lf = linphone_core_create_friend(lc); + linphone_friend_set_address(lf, la); + linphone_friend_set_name(lf, ldap_data.name); + req->found_entries = ms_list_append(req->found_entries, lf); + req->found_count++; + //ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); + ms_free(ldap_data.sip); + ms_free(ldap_data.name); + linphone_address_destroy(la); + } + } + + if( ber ) ber_free(ber, 0); + + entry = ldap_next_entry(obj->ld, entry); + } + } + break; + + case LDAP_RES_SEARCH_RESULT: + { + // this one is received when a request is finished + req->complete = TRUE; + linphone_contact_search_invoke_cb(LINPHONE_CONTACT_SEARCH(req), req->found_entries); + } + break; + + + default: ms_message("[LDAP] Unhandled message type %x", msgtype); break; + } +} + +static bool_t linphone_ldap_contact_provider_iterate(void *data) +{ + LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); + if( obj->ld && obj->connected && (obj->req_count > 0) ){ + + // never block + struct timeval timeout = {0,0}; + LDAPMessage* results = NULL; + + int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results); + + switch( ret ){ + case -1: + { + ms_warning("Error in ldap_result : returned -1 (req_count %d): %s", obj->req_count, ldap_err2string(errno)); + break; + } + case 0: break; // nothing to do + + case LDAP_RES_BIND: + { + ms_error("iterate: unexpected LDAP_RES_BIND"); + break; + } + case LDAP_RES_EXTENDED: + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_REFERENCE: + case LDAP_RES_INTERMEDIATE: + case LDAP_RES_SEARCH_RESULT: + { + LDAPMessage* message = ldap_first_message(obj->ld, results); + LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message)); + while( message != NULL ){ + linphone_ldap_contact_provider_handle_search_result(obj, req, message ); + message = ldap_next_message(obj->ld, message); + } + if( req && ret == LDAP_RES_SEARCH_RESULT) + linphone_ldap_contact_provider_cancel_search( + LINPHONE_CONTACT_PROVIDER(obj), + LINPHONE_CONTACT_SEARCH(req)); + break; + } + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODDN: + case LDAP_RES_COMPARE: + default: + ms_message("Unhandled LDAP result %x", ret); + break; + } + + if( results ) + ldap_msgfree(results); + } + + if( obj->ld && obj->connected ){ + // check for pending searches + unsigned int i; + + for( i=0; ireq_count; i++){ + LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i ); + if( search && search->msgid == 0){ + int ret; + ms_message("Found pending search %p (for %s), launching...", search, search->filter); + ret = linphone_ldap_contact_provider_perform_search(obj, search); + if( ret != LDAP_SUCCESS ){ + linphone_ldap_contact_provider_cancel_search( + LINPHONE_CONTACT_PROVIDER(obj), + LINPHONE_CONTACT_SEARCH(search)); + } + } + } + } + + return TRUE; +} + +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) +{ + if(obj->attributes){ + int i=0; + for( ; obj->attributes[i]; i++){ + ms_free(obj->attributes[i]); + } + ms_free(obj->attributes); + } +} + +static char* required_config_keys[] = { + // connection + "server", + "use_tls", + "auth_method", + "username", + "password", + "bind_dn", + "sasl_authname", + "sasl_realm", + + // search + "base_object", + "filter", + "name_attribute", + "sip_attribute", + "attributes", + + // misc + "timeout", + "max_results", + "deref_aliases", + NULL +}; + +static bool_t linphone_ldap_contact_provider_valid_config(const LinphoneDictionary* dict) +{ + char** config_name = required_config_keys; + + bool_t valid = TRUE; + bool_t has_key; + + while(*config_name ){ + has_key = linphone_dictionary_haskey(dict, *config_name); + if( !has_key ) ms_error("Missing LDAP config value for '%s'", *config_name); + valid &= has_key; + config_name++; + } + return valid; +} + +static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, const LinphoneDictionary* dict) +{ + char* attributes_list, *saveptr, *attr; + unsigned int attr_count = 0, attr_idx = 0, i; + + if( !linphone_ldap_contact_provider_valid_config(dict) ) return; + + // free any pre-existing attributes values + linphone_ldap_contact_provider_conf_destroy(obj); + if( obj->config ) linphone_dictionary_unref(obj->config); + + // clone new config into the dictionary + obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict)); + +#if 0 // until sasl auth is set up, force anonymous auth. + linphone_dictionary_set_string(obj->config, "auth_method", "ANONYMOUS"); +#endif + + obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0); + obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10); + obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0); + obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50); + obj->auth_method = linphone_dictionary_get_string(obj->config, "auth_method", "ANONYMOUS"); + obj->username = linphone_dictionary_get_string(obj->config, "username", ""); + obj->password = linphone_dictionary_get_string(obj->config, "password", ""); + obj->bind_dn = linphone_dictionary_get_string(obj->config, "bind_dn", ""); + obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com"); + obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://localhost"); + obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*"); + obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName"); + obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile"); + obj->sasl_authname = linphone_dictionary_get_string(obj->config, "sasl_authname", ""); + obj->sasl_realm = linphone_dictionary_get_string(obj->config, "sasl_realm", ""); + + /* + * parse the attributes list + */ + attributes_list = ms_strdup( + linphone_dictionary_get_string(obj->config, + "attributes", + "telephoneNumber,givenName,sn,mobile,homePhone") + ); + + // count attributes: + for( i=0; attributes_list[i]; i++) { + if( attributes_list[i] == ',') attr_count++; + } + + // 1 more for the first attr without ',', the other for the null-finished list + obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); + + attr = strtok_r( attributes_list, ",", &saveptr ); + while( attr != NULL ){ + obj->attributes[attr_idx] = ms_strdup(attr); + attr_idx++; + attr = strtok_r(NULL, ",", &saveptr); + } + if( attr_idx != attr_count+1) ms_error("Invalid attribute number!!! %d expected, got %d", attr_count+1, attr_idx); + + ms_free(attributes_list); +} + +static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, + unsigned flags, + void *defaults, + void *sasl_interact) +{ + sasl_interact_t *interact = (sasl_interact_t*)sasl_interact; + LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(defaults); + ms_message("bind_interact called: ld %p, flags %x, default %p, interact %p", + ld, flags, defaults, sasl_interact); + + if( ld == NULL ) return LDAP_PARAM_ERROR; + + while( interact->id != SASL_CB_LIST_END ) { + + const char *dflt = interact->defresult; + + switch( interact->id ) { + case SASL_CB_GETREALM: + ms_message("* SASL_CB_GETREALM -> %s", obj->sasl_realm); + dflt = obj->sasl_realm; + break; + case SASL_CB_AUTHNAME: + ms_message("* SASL_CB_AUTHNAME -> %s", obj->sasl_authname); + dflt = obj->sasl_authname; + break; + case SASL_CB_USER: + ms_message("* SASL_CB_USER -> %s", obj->username); + dflt = obj->username; + break; + case SASL_CB_PASS: + ms_message("* SASL_CB_PASS (hidden)"); + dflt = obj->password; + break; + default: + ms_message("SASL interact asked for unknown id %lx\n",interact->id); + } + interact->result = (dflt && *dflt) ? dflt : (const char*)""; + interact->len = strlen( (const char*)interact->result ); + + interact++; + } + return LDAP_SUCCESS; +} + +static void* ldap_bind_thread_func( void*arg) +{ + LinphoneLDAPContactProvider* obj = linphone_ldap_contact_provider_ref(arg); + const char* auth_mechanism = obj->auth_method; + int ret; + + if( (strcmp(auth_mechanism, "ANONYMOUS") == 0) || (strcmp(auth_mechanism, "SIMPLE") == 0) ) + { + struct berval passwd = { strlen(obj->password), ms_strdup(obj->password)}; + auth_mechanism = LDAP_SASL_SIMPLE; + ret = ldap_sasl_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + &passwd, + NULL, + NULL, + NULL); + + ms_free(passwd.bv_val); + } + else + { + + ms_message("LDAP interactive bind"); + ret = ldap_sasl_interactive_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + NULL,NULL, + LDAP_SASL_QUIET, + linphone_ldap_contact_provider_bind_interact, + obj); + } + + if( ret == LDAP_SUCCESS ) { + ms_message("LDAP bind OK"); + obj->connected = 1; + } else { + int err; + ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); + ms_error("ldap_sasl_bind error returned %x, err %x (%s), auth_method: %s", + ret, err, ldap_err2string(err), auth_mechanism ); + } + + obj->bind_thread = 0; + linphone_ldap_contact_provider_unref(obj); + return (void*)0; +} + +static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +{ + // perform the bind in an alternate thread, so that we don't stall the main loop + ms_thread_create(&obj->bind_thread, NULL, ldap_bind_thread_func, obj); + return 0; +} + +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj) +{ + return obj->max_results; +} + +static void linphone_ldap_contact_provider_config_dump_cb(const char*key, void* value, void* userdata) +{ + ms_message("- %s -> %s", key, (const char* )value); +} + +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config) +{ + LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); + int proto_version = LDAP_VERSION3; + + linphone_contact_provider_init((LinphoneContactProvider*)obj, lc); + + ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); + + if( !linphone_ldap_contact_provider_valid_config(config) ) { + ms_error( "Invalid configuration for LDAP, aborting creation"); + belle_sip_object_unref(obj); + obj = NULL; + } else { + int ret; + linphone_dictionary_foreach( config, linphone_ldap_contact_provider_config_dump_cb, 0 ); + linphone_ldap_contact_provider_loadconfig(obj, config); + + ret = ldap_initialize(&(obj->ld),obj->server); + + if( ret != LDAP_SUCCESS ){ + ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret)); + belle_sip_object_unref(obj); + obj = NULL; + } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ + ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); + belle_sip_object_unref(obj); + obj = NULL; + } else { + // prevents blocking calls to bind() when the server is invalid, but this is not working for now.. + // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509 + //ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); + + // register our hook into iterate so that LDAP can do its magic asynchronously. + linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); + } + } + return obj; +} + +/** + * Search an LDAP request in the list of current LDAP requests to serve, only taking + * the msgid as a key to search. + */ +static int linphone_ldap_request_entry_compare_weak(const void*a, const void* b) +{ + const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a; + const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b; + return !(ra->msgid == rb->msgid); // 0 if equal +} + +/** + * Search an LDAP request in the list of current LDAP requests to serve, with strong search + * comparing both msgid and request pointer + */ +static int linphone_ldap_request_entry_compare_strong(const void*a, const void* b) +{ + const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a; + const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b; + return !(ra->msgid == rb->msgid) && !(ra == rb); +} + +static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid ) +{ + LinphoneLDAPContactSearch dummy = {}; + MSList* list_entry; + dummy.msgid = msgid; + + list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy); + if( list_entry ) return list_entry->data; + else return NULL; +} + +static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) +{ + LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); + LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); + int ret = 1; + + MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req); + if( list_entry ) { + ms_message("Delete search %p", req); + ldap_cp->requests = ms_list_remove_link(ldap_cp->requests, list_entry); + ldap_cp->req_count--; + ret = 0; // return OK if we found it in the monitored requests + } else { + ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid); + } + belle_sip_object_unref(req); // unref request even if not found + return ret; +} + +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req) +{ + int ret = -1; + struct timeval timeout = { obj->timeout, 0 }; + + if( req->msgid == 0 ){ + ms_message ( "Calling ldap_search_ext with predicate '%s' on base '%s', ld %p, attrs '%s', maxres = %d", req->filter, obj->base_object, obj->ld, obj->attributes[0], obj->max_results ); + ret = ldap_search_ext(obj->ld, + obj->base_object,// base from which to start + LDAP_SCOPE_SUBTREE, + req->filter, // search predicate + obj->attributes, // which attributes to get + 0, // 0 = get attrs AND value, 1 = get attrs only + NULL, + NULL, + &timeout, // server timeout for the search + obj->max_results,// max result number + &req->msgid ); + + if( ret != LDAP_SUCCESS ){ + ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); + } else { + ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", req, req->msgid); + } + + } else { + ms_warning( "LDAP Search already performed for %s, msgid %d", req->filter, req->msgid); + } + return ret; +} + +static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data ) +{ + bool_t connected = obj->connected; + LinphoneLDAPContactSearch* request; + + // if we're not yet connected, bind + if( !connected ) { + if( !obj->bind_thread ) linphone_ldap_contact_provider_bind(obj); + } + + request = linphone_ldap_contact_search_create( obj, predicate, cb, cb_data ); + + if( connected ){ + int ret = linphone_ldap_contact_provider_perform_search(obj, request); + ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request ); + if( ret != LDAP_SUCCESS ){ + belle_sip_object_unref(request); + request = NULL; + } + } else { + ms_message("Delayed search, wait for connection"); + } + + if( request != NULL ) { + obj->requests = ms_list_append ( obj->requests, request ); + obj->req_count++; + } + + return request; +} + + +static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset) +{ + belle_sip_error_code error = BELLE_SIP_OK; + char **attr; + + error = belle_sip_snprintf(buff, buff_size, offset, "ld:%p,\n", obj->ld); + if(error!= BELLE_SIP_OK) return error; + + error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count); + if(error!= BELLE_SIP_OK) return error; + + error = belle_sip_snprintf(buff, buff_size, offset, + "CONFIG:\n" + "tls: %d \n" + "auth: %s \n" + "user: %s \n" + "pass: %s \n" + "server: %s \n" + "base: %s \n" + "filter: %s \n" + "timeout: %d \n" + "deref: %d \n" + "max_res: %d \n" + "sip_attr:%s \n" + "name_attr:%s \n" + "attrs:\n", + obj->use_tls, obj->auth_method, + obj->username, obj->password, obj->server, + obj->base_object, obj->filter, + obj->timeout, obj->deref_aliases, + obj->max_results, + obj->sip_attr, obj->name_attr); + if(error!= BELLE_SIP_OK) return error; + + attr = obj->attributes; + while( *attr ){ + error = belle_sip_snprintf(buff, buff_size, offset, "- %s\n", *attr); + if(error!= BELLE_SIP_OK) return error; + else attr++; + } + + return error; + +} + +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_ref(void* obj) +{ + return linphone_ldap_contact_provider_cast(belle_sip_object_ref(obj)); +} + + +void linphone_ldap_contact_provider_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +inline LinphoneLDAPContactSearch*linphone_ldap_contact_search_cast(void* obj) +{ + return BELLE_SIP_CAST(obj, LinphoneLDAPContactSearch); +} + + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast(void* obj) +{ + return BELLE_SIP_CAST(obj, LinphoneLDAPContactProvider); +} + +int linphone_ldap_contact_provider_available() +{ + return 1; +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); + +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider) + { + { + BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), + (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, + NULL, + (belle_sip_object_marshal_t)linphone_ldap_contact_provider_marshal + }, + "LDAP", + (LinphoneContactProviderStartSearchMethod)linphone_ldap_contact_provider_begin_search, + (LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search + } +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END + +#else + +/* Stubbed implementation */ + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + return NULL; +} + +unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj){ return 0; } +LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj ){ return NULL; } + + +/* LinphoneLDAPContactProvider */ + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config){ return NULL; } +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj){ return 0; } +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ){ return NULL; } +void linphone_ldap_contact_provider_unref( void* obj ){ } +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ){ return NULL; } + +int linphone_ldap_contact_provider_available(){ return 0; } + + +#endif /* BUILD_LDAP */ + diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h new file mode 100644 index 000000000..066ab7ba8 --- /dev/null +++ b/coreapi/ldap/ldapprovider.h @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "contactprovider.h" + + +typedef struct _LinphoneLDAPContactProvider LinphoneLDAPContactProvider; + +/* LinphoneLDAPContactSearch */ +typedef struct _LinphoneLDAPContactSearch LinphoneLDAPContactSearch; + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, + const char* predicate, + ContactSearchCallback cb, + void* cb_data); + +LINPHONE_PUBLIC unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj); +LINPHONE_PUBLIC LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj ); + + +/* LinphoneLDAPContactProvider */ + +LINPHONE_PUBLIC LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config); +LINPHONE_PUBLIC unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj); +LINPHONE_PUBLIC LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ); +void linphone_ldap_contact_provider_unref( void* obj ); +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ); +LINPHONE_PUBLIC int linphone_ldap_contact_provider_available(); diff --git a/coreapi/lime.c b/coreapi/lime.c new file mode 100644 index 000000000..190ea6be7 --- /dev/null +++ b/coreapi/lime.c @@ -0,0 +1,836 @@ +#include "lime.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_LIME + +#include "linphonecore.h" +#include "ortp/b64.h" +#include "polarssl/gcm.h" + +/* check polarssl version */ +#include + +#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ +#include "polarssl/sha256.h" +#else /* for Polarssl version 1.2 */ +#include "polarssl/sha2.h" +#endif + +/** + * @brief check at runtime if LIME is available + * + * @return TRUE when Lime was fully compiled, FALSE when it wasn't + */ +bool_t lime_is_available() { return TRUE; } + +/** + * @brief convert an hexa char [0-9a-fA-F] into the corresponding unsigned integer value + * Any invalid char will be converted to zero without any warning + * + * @param[in] inputChar a char which shall be in range [0-9a-fA-F] + * + * @return the unsigned integer value in range [0-15] + */ +uint8_t lime_charToByte(uint8_t inputChar) { + /* 0-9 */ + if (inputChar>0x29 && inputChar<0x3A) { + return inputChar - 0x30; + } + + /* a-f */ + if (inputChar>0x60 && inputChar<0x67) { + return inputChar - 0x57; /* 0x57 = 0x61(a) + 0x0A*/ + } + + /* A-F */ + if (inputChar>0x40 && inputChar<0x47) { + return inputChar - 0x37; /* 0x37 = 0x41(a) + 0x0A*/ + } + + /* shall never arrive here, string is not Hex*/ + return 0; + +} + +/** + * @brief convert a byte which value is in range [0-15] into an hexa char [0-9a-fA-F] + * + * @param[in] inputByte an integer which shall be in range [0-15] + * + * @return the hexa char [0-9a-f] corresponding to the input + */ +uint8_t lime_byteToChar(uint8_t inputByte) { + inputByte &=0x0F; /* restrict the input value to range [0-15] */ + /* 0-9 */ + if(inputByte<0x0A) { + return inputByte+0x30; + } + /* a-f */ + return inputByte + 0x57; +} + + +/** + * @brief Convert an hexadecimal string into the corresponding byte buffer + * + * @param[out] outputBytes The output bytes buffer, must have a length of half the input string buffer + * @param[in] inputString The input string buffer, must be hexadecimal(it is not checked by function, any non hexa char is converted to 0) + * @param[in] inputStringLength The lenght in chars of the string buffer, output is half this length + */ +void lime_strToUint8(uint8_t *outputBytes, uint8_t *inputString, uint16_t inputStringLength) { + int i; + for (i=0; i>4)&0x0F); + outputString[2*i+1] = lime_byteToChar(inputBytes[i]&0x0F); + } +} + + + +/** + * @brief Retrieve selfZID from cache + * + * @param[in] cacheBuffer The xmlDoc containing current cache + * @param[out] selfZid The ZID found as a 24 hexa char string null terminated + * + * @return 0 on success, error code otherwise + */ +static int lime_getSelfZid(xmlDocPtr cacheBuffer, uint8_t selfZid[25]) { + xmlNodePtr cur; + xmlChar *selfZidHex; + + if (cacheBuffer == NULL ) { + return LIME_INVALID_CACHE; + } + + cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + } + selfZidHex = NULL; + while (cur!=NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"selfZID"))){ /* self ZID found, extract it */ + selfZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode, 1); + /* copy it to the output buffer and add the null termination */ + memcpy(selfZid, selfZidHex, 24); + selfZid[24]='\0'; + break; + } + cur = cur->next; + } + + /* did we found a ZID? */ + if (selfZidHex == NULL) { + return LIME_INVALID_CACHE; + } + + xmlFree(selfZidHex); + return 0; +} + +int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys) { + xmlNodePtr cur; + + /* parse the file to get all peer matching the sipURI given in associatedKeys*/ + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* reset number of associated keys and their buffer */ + associatedKeys->associatedZIDNumber = 0; + associatedKeys->peerKeys = NULL; + + cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + } + while (cur!=NULL) { /* loop on all peer nodes */ + uint8_t matchingURIFlag = 0; /* this flag is set to one if we found the requested sipURI in the current peer node */ + if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))) { /* found a peer node, check if there is a matching sipURI node in it */ + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode; + matchingURIFlag = 0; + + /* loop on children nodes until the end or we found the matching sipURI */ + while (peerNodeChildren!=NULL && matchingURIFlag==0) { + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"uri")) { /* found a peer an URI node, check the content */ + xmlChar *uriNodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + if (!xmlStrcmp(uriNodeContent, (const xmlChar *)associatedKeys->peerURI)) { /* found a match with requested URI */ + matchingURIFlag=1; + } + xmlFree(uriNodeContent); + } + peerNodeChildren = peerNodeChildren->next; + } + + if (matchingURIFlag == 1) { /* we found a match for the URI in this peer node, extract the keys, session Id and index values */ + /* allocate a new limeKey_t structure to hold the retreived keys */ + limeKey_t *currentPeerKeys = (limeKey_t *)malloc(sizeof(limeKey_t)); + uint8_t itemFound = 0; /* count the item found, we must get all of the requested infos: 5 nodes*/ + uint8_t pvs = 0; + + peerNodeChildren = cur->xmlChildrenNode; /* reset peerNodeChildren to the first child of node */ + while (peerNodeChildren!=NULL && itemFound<5) { + xmlChar *nodeContent = NULL; + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"ZID")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(currentPeerKeys->peerZID, nodeContent, 24); + itemFound++; + } + + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndKey")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(currentPeerKeys->key, nodeContent, 64); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndSId")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(currentPeerKeys->sessionId, nodeContent, 64); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) { + uint8_t sessionIndexBuffer[4]; /* session index is a uint32_t but we first retrieved it as an hexa string, convert it to a 4 uint8_t buffer */ + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(sessionIndexBuffer, nodeContent, 8); + /* convert it back to a uint32_t (MSByte first)*/ + currentPeerKeys->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"pvs")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */ + itemFound++; + } + + xmlFree(nodeContent); + peerNodeChildren = peerNodeChildren->next; + } + + /* check if we have all the requested information and the PVS flag is set to 1 */ + if (itemFound == 5 && pvs == 1) { + associatedKeys->associatedZIDNumber +=1; + /* extend array of pointer to limeKey_t structures to add the one we found */ + associatedKeys->peerKeys = (limeKey_t **)realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *)); + + /* add the new entry at the end */ + associatedKeys->peerKeys[associatedKeys->associatedZIDNumber-1] = currentPeerKeys; + + } else { + free(currentPeerKeys); + } + } + } + cur = cur->next; + } + return 0; +} + +int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) { + uint8_t peerZidHex[25]; + /* to check we collect all the information needed from the cache and that pvs(boolean for previously verified Sas) is set in cache */ + uint8_t itemFound = 0; + uint8_t pvs = 0; + xmlNodePtr cur; + + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* get the given ZID into hex format */ + lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); + peerZidHex[24]='\0'; /* must be a null terminated string */ + + cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + + } + + while (cur!=NULL) { /* loop on all peer nodes */ + if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))){ /* found a peer, check his ZID element */ + xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode->xmlChildrenNode, 1); /* ZID is the first element of peer */ + if (!xmlStrcmp(currentZidHex, (const xmlChar *)peerZidHex)) { /* we found the peer element we are looking for */ + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; + while (peerNodeChildren != NULL && itemFound<4) { /* look for the tag we want to read : rcvKey, rcvSId, rcvIndex and pvs*/ + xmlChar *nodeContent = NULL; + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(associatedKey->key, nodeContent, 64); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvSId")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(associatedKey->sessionId, nodeContent, 64); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) { + uint8_t sessionIndexBuffer[4]; /* session index is a uint32_t but we first retrieved it as an hexa string, convert it to a 4 uint8_t buffer */ + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(sessionIndexBuffer, nodeContent, 8); + /* convert it back to a uint32_t (MSByte first)*/ + associatedKey->sessionIndex = sessionIndexBuffer[3] + (sessionIndexBuffer[2]<<8) + (sessionIndexBuffer[1]<<16) + (sessionIndexBuffer[0]<<24); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"pvs")) { + nodeContent = xmlNodeListGetString(cacheBuffer, peerNodeChildren->xmlChildrenNode, 1); + lime_strToUint8(&pvs, nodeContent, 2); /* pvs is retrieved as a 2 characters hexa string, convert it to an int8 */ + itemFound++; + } + xmlFree(nodeContent); + peerNodeChildren = peerNodeChildren->next; + } + xmlFree(currentZidHex); + break; /* we parsed the peer node we were looking for, get out of the main while */ + } + xmlFree(currentZidHex); + } + cur = cur->next; + } + + /* if we manage to find the correct key information and that pvs is set to 1, return 0 (success) */ + if ((pvs == 1) && (itemFound == 4)) { + return 0; + } + + /* otherwise, key wasn't found or is invalid */ + return LIME_NO_VALID_KEY_FOUND_FOR_PEER; +} + +int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role) { + xmlNodePtr cur; + uint8_t peerZidHex[25]; + uint8_t keyHex[65]; /* key is 32 bytes long -> 64 bytes string + null termination */ + uint8_t sessionIdHex[65]; /* sessionId is 32 bytes long -> 64 bytes string + null termination */ + uint8_t sessionIndexHex[9]; /* sessionInedx is an uint32_t : 4 bytes long -> 8 bytes string + null termination */ + uint8_t itemFound = 0; + + if (cacheBuffer == NULL ) { /* there is no cache return error */ + return LIME_INVALID_CACHE; + } + + /* get the given ZID into hex format */ + lime_int8ToStr(peerZidHex, associatedKey->peerZID, 12); + peerZidHex[24]='\0'; /* must be a null terminated string */ + + cur = xmlDocGetRootElement(cacheBuffer); + /* if we found a root element, parse its children node */ + if (cur!=NULL) + { + cur = cur->xmlChildrenNode; + + } + + /* convert the given tag content to null terminated Hexadecimal strings */ + lime_int8ToStr(keyHex, associatedKey->key, 32); + keyHex[64] = '\0'; + lime_int8ToStr(sessionIdHex, associatedKey->sessionId, 32); + sessionIdHex[64] = '\0'; + sessionIndexHex[0] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>28)&0x0F)); + sessionIndexHex[1] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>24)&0x0F)); + sessionIndexHex[2] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>20)&0x0F)); + sessionIndexHex[3] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>16)&0x0F)); + sessionIndexHex[4] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>12)&0x0F)); + sessionIndexHex[5] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>8)&0x0F)); + sessionIndexHex[6] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex>>4)&0x0F)); + sessionIndexHex[7] = lime_byteToChar((uint8_t)((associatedKey->sessionIndex)&0x0F)); + sessionIndexHex[8] = '\0'; + + while (cur!=NULL && itemFound<3) { /* loop on all peer nodes */ + if ((!xmlStrcmp(cur->name, (const xmlChar *)"peer"))){ /* found a peer, check his ZID element */ + xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, cur->xmlChildrenNode->xmlChildrenNode, 1); /* ZID is the first element of peer */ + if (!xmlStrcmp(currentZidHex, (const xmlChar *)peerZidHex)) { /* we found the peer element we are looking for */ + xmlNodePtr peerNodeChildren = cur->xmlChildrenNode->next; + while (peerNodeChildren != NULL && itemFound<3) { /* look for the tag we want to write */ + if (role == LIME_RECEIVER) { /* writing receiver key */ + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvKey")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)keyHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvSId")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIdHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"rcvIndex")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIndexHex); + itemFound++; + } + } else { /* writing sender key */ + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndKey")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)keyHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndSId")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIdHex); + itemFound++; + } + if (!xmlStrcmp(peerNodeChildren->name, (const xmlChar *)"sndIndex")) { + xmlNodeSetContent(peerNodeChildren, (const xmlChar *)sessionIndexHex); + itemFound++; + } + } + peerNodeChildren = peerNodeChildren->next; + } + } + xmlFree(currentZidHex); + } + cur = cur->next; + } + + + return 0; +} + +/** + * @brief Derive in place the key given in parameter and increment session index + * Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||256) + * + * @param[in/out] key The structure containing the original key which will be overwritten, the sessionId and SessionIndex + * + * @return 0 on success, error code otherwise + */ +static int lime_deriveKey(limeKey_t *key) { + uint8_t inputData[55]; + uint8_t derivedKey[32]; + + if (key == NULL) { + return LIME_UNABLE_TO_DERIVE_KEY; + } + +#if 0 + /*not doing anything yet since key and sessionId are array, not pointers*/ + if ((key->key == NULL) || (key->sessionId == NULL)) { + return LIME_UNABLE_TO_DERIVE_KEY; + } +#endif + + /* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/ + /* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */ + inputData[0] = 0x00; + inputData[1] = 0x00; + inputData[2] = 0x00; + inputData[3] = 0x01; + + memcpy(inputData+4, "MessageKey", 10); + + inputData[14] = 0x00; + + memcpy(inputData+15, key->sessionId, 32); + + inputData[47] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + inputData[48] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + inputData[49] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + inputData[50] = (uint8_t)(key->sessionIndex&0x000000FF); + + inputData[51] = 0x00; + inputData[52] = 0x00; + inputData[53] = 0x01; + inputData[54] = 0x00; + + /* derive the key in a temp buffer */ +#if POLARSSL_VERSION_NUMBER >= 0x01030000 /* for Polarssl version 1.3 */ + sha256_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */ +#else /* for Polarssl version 1.2 */ + sha2_hmac(key->key, 32, inputData, 55, derivedKey, 0); /* last param to zero to select SHA256 and not SHA224 */ +#endif /* POLARSSL_VERSION_NUMBER */ + + /* overwrite the old key with the derived one */ + memcpy(key->key, derivedKey, 32); + + /* increment the session Index */ + key->sessionIndex += 1; + return 0; +} + +void lime_freeKeys(limeURIKeys_t associatedKeys) { + int i; + + /* free all associated keys */ + for (i=0; i< associatedKeys.associatedZIDNumber; i++) { + if (associatedKeys.peerKeys[i] != NULL) { + free(associatedKeys.peerKeys[i]); + associatedKeys.peerKeys[i] = NULL; + } + } + + free(associatedKeys.peerKeys); + + /* free sipURI string */ + free(associatedKeys.peerURI); +} + +int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) { + uint8_t authenticatedData[28]; + gcm_context gcmContext; + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ + memcpy(authenticatedData, selfZID, 12); + memcpy(authenticatedData+12, key->peerZID, 12); + authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF); + + /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ + /* tag is 16 bytes long and is set in the 16 first bytes of the encrypted message */ + gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); + gcm_crypt_and_tag(&gcmContext, GCM_ENCRYPT, messageLength, key->key+24, 8, authenticatedData, 28, plainMessage, encryptedMessage+16, 16, encryptedMessage); + gcm_free(&gcmContext); + + return 0; +} + +int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { + gcm_context *gcmContext; + + if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ + gcmContext = (gcm_context *)malloc(sizeof(gcm_context)); + *cryptoContext = (void *)gcmContext; + gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192); + gcm_starts(gcmContext, GCM_ENCRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */ + } else { /* this is not the first call, get the context */ + gcmContext = (gcm_context *)*cryptoContext; + } + + if (length != 0) { + gcm_update(gcmContext, length, (const unsigned char *)plain, (unsigned char *)cipher); + } else { /* lenght is 0, finish the stream */ + gcm_finish(gcmContext, NULL, 0); /* do not generate tag */ + gcm_free(gcmContext); + free(*cryptoContext); + *cryptoContext = NULL; + } + + return 0; +} + +int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { + gcm_context *gcmContext; + + if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */ + gcmContext = (gcm_context *)malloc(sizeof(gcm_context)); + *cryptoContext = (void *)gcmContext; + gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192); + gcm_starts(gcmContext, GCM_DECRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */ + } else { /* this is not the first call, get the context */ + gcmContext = (gcm_context *)*cryptoContext; + } + + if (length != 0) { + gcm_update(gcmContext, length, (const unsigned char *)cipher, (unsigned char *)plain); + } else { /* lenght is 0, finish the stream */ + gcm_finish(gcmContext, NULL, 0); /* do not generate tag */ + gcm_free(gcmContext); + free(*cryptoContext); + *cryptoContext = NULL; + } + + return 0; +} + + +int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) { + uint8_t authenticatedData[28]; + gcm_context gcmContext; + int retval; + + /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */ + memcpy(authenticatedData, key->peerZID, 12); + memcpy(authenticatedData+12, selfZID, 12); + authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF); + authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF); + authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF); + authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF); + + /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */ + /* tag is 16 bytes long and is the 16 first bytes of the encrypted message */ + gcm_init(&gcmContext, POLARSSL_CIPHER_ID_AES, key->key, 192); + /* messageLength-16 is the length of encrypted data, messageLength include the 16 bytes tag included at the begining of encryptedMessage */ + retval = gcm_auth_decrypt(&gcmContext, messageLength-16, key->key+24, 8, authenticatedData, 28, encryptedMessage, 16, encryptedMessage+16, plainMessage); + gcm_free(&gcmContext); + /* add the null termination char */ + plainMessage[messageLength-16] = '\0'; + + return retval; +} + +int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output) { + uint8_t selfZidHex[25]; + uint8_t selfZid[12]; /* same data but in byte buffer */ + uint32_t encryptedMessageLength; + limeURIKeys_t associatedKeys; + xmlDocPtr xmlOutputMessage; + xmlNodePtr rootNode; + int i; + int xmlStringLength; + + /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ + if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { + return LIME_UNABLE_TO_ENCRYPT_MESSAGE; + } + lime_strToUint8(selfZid, selfZidHex, 24); + + /* encrypted message length is plaintext + 16 for tag */ + encryptedMessageLength = strlen((char *)message) + 16; + + /* retrieve keys associated to the peer URI */ + associatedKeys.peerURI = (uint8_t *)malloc(strlen((char *)peerURI)+1); + strcpy((char *)(associatedKeys.peerURI), (char *)peerURI); + associatedKeys.associatedZIDNumber = 0; + associatedKeys.peerKeys = NULL; + + if (lime_getCachedSndKeysByURI(cacheBuffer, &associatedKeys) != 0) { + lime_freeKeys(associatedKeys); + return LIME_UNABLE_TO_ENCRYPT_MESSAGE; + } + + if (associatedKeys.associatedZIDNumber == 0) { + lime_freeKeys(associatedKeys); + return LIME_NO_VALID_KEY_FOUND_FOR_PEER; + } + + /* create an xml doc to hold the multipart message */ + xmlOutputMessage = xmlNewDoc((const xmlChar *)"1.0"); + /* root tag is "doc" */ + rootNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"doc", NULL); + xmlDocSetRootElement(xmlOutputMessage, rootNode); + /* add the self ZID child */ + xmlNewTextChild(rootNode, NULL, (const xmlChar *)"ZID", selfZidHex); + + /* loop on all keys found */ + for (i=0; i + * peerZID + * session index + * ciphertext + * */ + msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL); + lime_int8ToStr(peerZidHex, currentKey->peerZID, 12); + peerZidHex[24] = '\0'; + sessionIndexHex[0] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>28)&0x0F)); + sessionIndexHex[1] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>24)&0x0F)); + sessionIndexHex[2] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>20)&0x0F)); + sessionIndexHex[3] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>16)&0x0F)); + sessionIndexHex[4] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>12)&0x0F)); + sessionIndexHex[5] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>8)&0x0F)); + sessionIndexHex[6] = lime_byteToChar((uint8_t)((currentKey->sessionIndex>>4)&0x0F)); + sessionIndexHex[7] = lime_byteToChar((uint8_t)((currentKey->sessionIndex)&0x0F)); + sessionIndexHex[8] = '\0'; + + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"pzid", peerZidHex); + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex); + + /* convert the cipherText to base 64 */ + b64Size = b64_encode(NULL, encryptedMessageLength, NULL, 0); + encryptedMessageb64 = (char *)malloc(b64Size+1); + b64Size = b64_encode(encryptedMessage, encryptedMessageLength, encryptedMessageb64, b64Size); + encryptedMessageb64[b64Size] = '\0'; /* libxml need a null terminated string */ + xmlNewTextChild(msgNode, NULL, (const xmlChar *)"text", (const xmlChar *)encryptedMessageb64); + free(encryptedMessage); + free(encryptedMessageb64); + + /* add the message Node into the doc */ + xmlAddChild(rootNode, msgNode); + + /* update the key used */ + lime_deriveKey(currentKey); + lime_setCachedKey(cacheBuffer, currentKey, LIME_SENDER); + } + + /* dump the whole message doc into the output */ + xmlDocDumpFormatMemoryEnc(xmlOutputMessage, output, &xmlStringLength, "UTF-8", 0); + xmlFreeDoc(xmlOutputMessage); + + lime_freeKeys(associatedKeys); + + return 0; +} + +int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { + int retval; + uint8_t selfZidHex[25]; + uint8_t selfZid[12]; /* same data but in byte buffer */ + limeKey_t associatedKey; + xmlChar *peerZidHex = NULL; + xmlNodePtr cur; + uint8_t *encryptedMessage = NULL; + uint32_t encryptedMessageLength = 0; + uint32_t usedSessionIndex = 0; + xmlDocPtr xmlEncryptedMessage; + + if (cacheBuffer == NULL) { + return LIME_INVALID_CACHE; + } + /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ + if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + lime_strToUint8(selfZid, selfZidHex, 24); + + /* parse the message into an xml doc */ + /* make sure we have a valid xml message before trying to parse it */ + if (memcmp(message, "", 38) != 0 ) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } + xmlEncryptedMessage = xmlParseDoc((const xmlChar *)message); + if (xmlEncryptedMessage == NULL) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } + + /* retrieve the sender ZID which is the first child of root */ + cur = xmlDocGetRootElement(xmlEncryptedMessage); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + if ((!xmlStrcmp(cur->name, (const xmlChar *)"ZID"))){ /* sender ZID found, extract it */ + peerZidHex = xmlNodeListGetString(xmlEncryptedMessage, cur->xmlChildrenNode, 1); + /* convert it from hexa string to bytes string and set the result in the associatedKey structure */ + lime_strToUint8(associatedKey.peerZID, peerZidHex, strlen((char *)peerZidHex)); + cur = cur->next; + } + } + + if (peerZidHex != NULL) { + /* get from cache the matching key */ + retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + + if (retval != 0) { + xmlFree(peerZidHex); + xmlFreeDoc(xmlEncryptedMessage); + return retval; + } + + /* retrieve the portion of message which is encrypted with our key */ + while (cur != NULL) { /* loop on all "msg" node in the message */ + xmlNodePtr msgChildrenNode = cur->xmlChildrenNode; + xmlChar *currentZidHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); /* pZID is the first element of msg */ + if (!xmlStrcmp(currentZidHex, (const xmlChar *)selfZidHex)) { /* we found the msg node we are looking for */ + /* get the index (second node in the msg one) */ + xmlChar *sessionIndexHex; + xmlChar *encryptedMessageb64; + + msgChildrenNode = msgChildrenNode->next; + sessionIndexHex = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + usedSessionIndex = (((uint32_t)lime_charToByte(sessionIndexHex[0]))<<28) + | (((uint32_t)lime_charToByte(sessionIndexHex[1]))<<24) + | (((uint32_t)lime_charToByte(sessionIndexHex[2]))<<20) + | (((uint32_t)lime_charToByte(sessionIndexHex[3]))<<16) + | (((uint32_t)lime_charToByte(sessionIndexHex[4]))<<12) + | (((uint32_t)lime_charToByte(sessionIndexHex[5]))<<8) + | (((uint32_t)lime_charToByte(sessionIndexHex[6]))<<4) + | (((uint32_t)lime_charToByte(sessionIndexHex[7]))); + xmlFree(sessionIndexHex); + /* get the encrypted message */ + msgChildrenNode = msgChildrenNode->next; + /* convert the cipherText from base 64 */ + encryptedMessageb64 = xmlNodeListGetString(cacheBuffer, msgChildrenNode->xmlChildrenNode, 1); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), NULL, 0); + encryptedMessage = (uint8_t *)malloc(encryptedMessageLength); + encryptedMessageLength = b64_decode((char *)encryptedMessageb64, strlen((char *)encryptedMessageb64), encryptedMessage, encryptedMessageLength); + xmlFree(encryptedMessageb64); + } + + cur = cur->next; + xmlFree(currentZidHex); + } + } + + xmlFree(peerZidHex); + xmlFreeDoc(xmlEncryptedMessage); + + /* do we have retrieved correctly all the needed data */ + if (encryptedMessage == NULL) { + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + /* shall we derive our key before going for decryption */ + if (usedSessionIndex < associatedKey.sessionIndex) { + /* something wen't wrong with the cache, this shall never happend */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) { + /* we missed to many messages, ask for a cache reset via a ZRTP call */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + while (usedSessionIndex>associatedKey.sessionIndex) { + lime_deriveKey(&associatedKey); + } + + /* decrypt the message */ + *output = (uint8_t *)malloc(encryptedMessageLength - 16 +1); /* plain message is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */ + retval = lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + + free(encryptedMessage); + + if (retval!=0 ) { + free(*output); + *output = NULL; + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + /* update used key */ + lime_deriveKey(&associatedKey); + lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); + + return 0; +} + + +#else /* HAVE_LIME */ + +bool_t lime_is_available() { return FALSE; } +int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { return LIME_NOT_ENABLED;} +int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { return LIME_NOT_ENABLED;} +int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output) { return LIME_NOT_ENABLED;} +int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {return LIME_NOT_ENABLED;} + + +#endif /* HAVE_LIME */ + +char *lime_error_code_to_string(int errorCode) { + switch (errorCode) { + case LIME_INVALID_CACHE: return "Invalid ZRTP cache"; + case LIME_UNABLE_TO_DERIVE_KEY: return "Unable to derive Key"; + case LIME_UNABLE_TO_ENCRYPT_MESSAGE: return "Unable to encrypt message"; + case LIME_UNABLE_TO_DECRYPT_MESSAGE: return "Unable to decrypt message"; + case LIME_NO_VALID_KEY_FOUND_FOR_PEER: return "No valid key found"; + case LIME_INVALID_ENCRYPTED_MESSAGE: return "Invalid encrypted message"; + case LIME_NOT_ENABLED: return "Lime not enabled at build"; + } + return "Unknow error"; + +} diff --git a/coreapi/lime.h b/coreapi/lime.h new file mode 100644 index 000000000..c196a6410 --- /dev/null +++ b/coreapi/lime.h @@ -0,0 +1,186 @@ +#ifndef LIME_H +#define LIME_H + +#define LIME_INVALID_CACHE 0x1001 +#define LIME_UNABLE_TO_DERIVE_KEY 0x1002 +#define LIME_UNABLE_TO_ENCRYPT_MESSAGE 0x1004 +#define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008 +#define LIME_NO_VALID_KEY_FOUND_FOR_PEER 0x1010 +#define LIME_INVALID_ENCRYPTED_MESSAGE 0x1020 +#define LIME_NOT_ENABLED 0x1100 + +/* this define the maximum key derivation number allowed to get the caches back in sync in case of missed messages */ +#define MAX_DERIVATION_NUMBER 100 + +#define LIME_SENDER 0x01 +#define LIME_RECEIVER 0x02 +#include +#include +#include +#include + +#include + +#ifndef LINPHONE_PUBLIC +#define LINPHONE_PUBLIC MS2_PUBLIC +#endif + +/** + * @brief Structure holding all needed material to encrypt/decrypt Messages */ +typedef struct limeKey_struct { + uint8_t key[32]; /**< a 256 bit key used to encrypt/decrypt message */ + uint8_t sessionId[32]; /**< a session id used to derive key */ + uint32_t sessionIndex; /**< an index to count number of derivation */ + uint8_t peerZID[12]; /**< the ZID associated to this key */ +} limeKey_t; + +/** + * @brief Store the differents keys associated to a sipURI */ +typedef struct limeURIKeys_struct { + limeKey_t **peerKeys; /**< an array of all the key material associated to each ZID matching the specified URI */ + uint16_t associatedZIDNumber; /**< previous array length */ + uint8_t *peerURI; /**< the sip URI associated to all the keys, must be a null terminated string */ +} limeURIKeys_t; + +/** + * @brief Get from cache all the senders keys associated to the given URI + * peerKeys field from associatedKeys param must be NULL when calling this function. + * Structure content must then be freed using lime_freeKeys function + * + * @param[in] cacheBuffer The xmlDoc containing current cache + * @param[in/out] associatedKeys Structure containing the peerURI. After this call contains all key material associated to the given URI. Must be then freed through lime_freeKeys function + * + * @return 0 on success, error code otherwise + */ +LINPHONE_PUBLIC int lime_getCachedSndKeysByURI(xmlDocPtr cacheBuffer, limeURIKeys_t *associatedKeys); + +/** + * @brief Get the receiver key associated to the ZID given in the associatedKey parameter + * + * @param[in] cacheBuffer The xmlDoc containing current cache + * @param[in/out] associatedKey Structure containing the peerZID and will store the retrieved key + * + * @return 0 on success, error code otherwise + */ +LINPHONE_PUBLIC int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey); + +/** + * @brief Set in cache the given key material, association is made by ZID contained in the associatedKey parameter + * + * @param[out] cacheBuffer The xmlDoc containing current cache to be updated + * @param[in/out] associatedKey Structure containing the key and ZID to identify the peer node to be updated + * @param[in] role Can be LIME_SENDER or LIME_RECEIVER, specify which key we want to update + * + * @return 0 on success, error code otherwise + */ + +LINPHONE_PUBLIC int lime_setCachedKey(xmlDocPtr cacheBuffer, limeKey_t *associatedKey, uint8_t role); + +/** + * @brief Free all allocated data in the associated keys structure + * Note, this will also free the peerURI string which then must have been allocated + * + * @param[in/out] associatedKeys The structure to be cleaned + * + */ +LINPHONE_PUBLIC void lime_freeKeys(limeURIKeys_t associatedKeys); + +/** + * @brief encrypt a message with the given key + * + * @param[in] key Key to use: first 192 bits are used as key, last 64 bits as init vector + * @param[in] message The string to be encrypted + * @param[in] messageLength The length in bytes of the message to be encrypted + * @param[in] selfZID The self ZID is use in authentication tag computation + * @param[out] encryptedMessage A buffer to hold the output, ouput length is input's one + 16 for the authentication tag + * Authentication tag is set at the begining of the encrypted Message + * + * @return 0 on success, error code otherwise + * + */ +LINPHONE_PUBLIC int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage); + +/** + * @brief Encrypt a file before transfering it to the server, encryption is done in several call, first one will be done with cryptoContext null, last one with length = 0 + * + * @param[in/out] cryptoContext The context used to encrypt the file using AES-GCM. Is created at first call(if null) + * @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector + * @param[in] length Length of data to be encrypted, if 0 it will conclude the encryption + * @param[in] plain Plain data to be encrypted (length bytes) + * @param[out] cipher Output to a buffer allocated by caller, at least length bytes available + * + * @return 0 on success, error code otherwise + * + */ +LINPHONE_PUBLIC int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); + +/** + * @brief Decrypt a file retrieved from server, decryption is done in several call, first one will be done with cryptoContext null, last one with length = 0 + * + * @param[in/out] cryptoContext The context used to decrypt the file using AES-GCM. Is created at first call(if null) + * @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector + * @param[in] length Length of data to be decrypted, if 0 it will conclude the decryption + * @param[out] plain Output to a buffer allocated by caller, at least length bytes available + * @param[in] cipher Cipher text to be decrypted(length bytes) + * + * @return 0 on success, error code otherwise + * + */ +LINPHONE_PUBLIC int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher); + +/** + * @brief decrypt and authentify a message with the given key + * + * @param[in] key Key to use: first 192 bits are used as key, last 64 bits as init vector + * @param[in] message The string to be decrypted + * @param[in] messageLength The length in bytes of the message to be decrypted (this include the 16 bytes tag at the begining of the message) + * @param[in] selfZID The self ZID is use in authentication tag computation + * @param[out] plainMessage A buffer to hold the output, ouput length is input's one - 16 for the authentication tag + 1 for null termination char + * Authentication tag is retrieved at the begining of the encrypted Message + * + * @return 0 on success, error code otherwise + * + */ + +LINPHONE_PUBLIC int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage); + +/** + * @brief create the encrypted multipart xml message from plain text and destination URI + * Retrieve in cache the needed keys which are then updated. Output buffer is allocated and must be freed by caller + * + * @param[in/out] cacheBuffer The xmlDoc containing current cache, get the keys and selfZID from it, updated by this function with derivated keys + * @param[in] message The plain text message to be encrypted + * @param[in] peerURI The destination URI, associated keys will be found in cache + * @param[out] output The output buffer, allocated and set with the encrypted message xml body(null terminated string). Must be freed by caller + * + * @return 0 on success, error code otherwise + */ +LINPHONE_PUBLIC int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t *peerURI, uint8_t **output); + +/** + * @brief decrypt a multipart xml message + * Retrieve in cache the needed key which is then updated. Output buffer is allocated and must be freed by caller + * + * @param[in/out] cacheBuffer The xmlDoc containing current cache, get the key and selfZID from it, updated by this function with derivated keys + * @param[in] message The multipart message, contain one or several part identified by destination ZID, one shall match the self ZID retrieved from cache + * @param[out] output The output buffer, allocated and set with the decrypted message(null terminated string). Must be freed by caller + * + * @return 0 on success, error code otherwise + */ + +LINPHONE_PUBLIC int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output); + +/** + * @brief given a readable version of error code generated by Lime functions + * @param[in] errorCode The error code + * @return a string containing the error description + */ +LINPHONE_PUBLIC char *lime_error_code_to_string(int errorCode); + +/** + * @brief Check if Lime was enabled at build time + * + * @return TRUE if Lime is available, FALSE if not + */ +LINPHONE_PUBLIC bool_t lime_is_available(); +#endif /* LIME_H */ diff --git a/coreapi/linphone_proxy_config.h b/coreapi/linphone_proxy_config.h new file mode 100644 index 000000000..127564504 --- /dev/null +++ b/coreapi/linphone_proxy_config.h @@ -0,0 +1,523 @@ +/* +Copyright (C) 2010-2015 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 LINPHONE_PROXY_CONFIG_H +#define LINPHONE_PROXY_CONFIG_H + +/** + * @addtogroup proxies + * @{ +**/ + +/** + * Creates an empty proxy config. + * @deprecated, use #linphone_core_create_proxy_config instead +**/ +LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void); + +/** + * Acquire a reference to the proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The same proxy config. +**/ +LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_ref(LinphoneProxyConfig *cfg); + +/** + * Release reference to the proxy config. + * @param[in] cfg #LinphoneProxyConfig object. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_unref(LinphoneProxyConfig *cfg); + +/** + * Retrieve the user pointer associated with the proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The user pointer associated with the proxy config. +**/ +LINPHONE_PUBLIC void *linphone_proxy_config_get_user_data(const LinphoneProxyConfig *cfg); + +/** + * Assign a user pointer to the proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] ud The user pointer to associate with the proxy config. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cfg, void *ud); + +/** + * Sets the proxy address + * + * Examples of valid sip proxy address are: + * - IP address: sip:87.98.157.38 + * - IP address with port: sip:87.98.157.38:5062 + * - hostnames : sip:sip.example.net +**/ +LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr); + +/** + * @deprecated Use linphone_proxy_config_set_identity_address() +**/ +LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *cfg, const char *identity); + +/** + * Sets the user identity as a SIP address. + * + * This identity is normally formed with display name, username and domain, such + * as: + * Alice + * The REGISTER messages will have from and to set to this identity. + * +**/ +LINPHONE_PUBLIC int linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *identity); + +/** + * Sets a SIP route. + * When a route is set, all outgoing calls will go to the route's destination if this proxy + * is the default one (see linphone_core_set_default_proxy() ). +**/ +LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route); + +/** + * Sets the registration expiration time in seconds. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, 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[in] cfg #LinphoneProxyConfig object. + * @param val if true, registration will be engaged + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *cfg, bool_t val); + +#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register + +/** + * Starts editing a proxy configuration. + * + * Because proxy configuration must be consistent, applications MUST + * call linphone_proxy_config_edit() before doing any attempts to modify + * proxy configuration (such as identity, proxy address and so on). + * Once the modifications are done, then the application must call + * linphone_proxy_config_done() to commit the changes. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_edit(LinphoneProxyConfig *cfg); + +/** + * Commits modification made to the proxy configuration. +**/ +LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *cfg); + +/** + * 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. + * @param[in] cfg #LinphoneProxyConfig object. + * @param val if true, publish will be engaged + * + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val); + +/** + * Set the publish expiration time in second. + * @param[in] cfg #LinphoneProxyConfig object. + * @param expires in second + * */ +LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *cfg, int expires); + +/** + * get the publish expiration time in second. Default value is the registration expiration value. + * @param[in] cfg #LinphoneProxyConfig object. + * @return expires in second + * */ +LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *cfg); + +/** + * Sets whether liblinphone should replace "+" by international calling prefix in dialed numbers (passed to + * #linphone_core_invite ). +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); + +/** + * Sets a dialing prefix to be automatically prepended when inviting a number with + * linphone_core_invite(); + * This dialing prefix shall usually be the country code of the country where the user is living, without "+". + * +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); + + /** + * Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] enable True to sotre quality statistics and sent them to the collector, false to disable it. + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t enable); + +/** + * Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035. + * @param[in] cfg #LinphoneProxyConfig object. + * @return True if quality repotring is enabled, false otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg); + + /** + * Set the route of the collector end-point when using quality reporting. This SIP address + * should be used on server-side to process packets directly before discarding packets. Collector address + * should be a non existing account and will not receive any messages. + * If NULL, reports will be send to the proxy domain. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] collector route of the collector end-point, if NULL PUBLISH will be sent to the proxy domain. + */ +LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector); + + /** + * Get the route of the collector end-point when using quality reporting. This SIP address + * should be used on server-side to process packets directly before discarding packets. Collector address + * should be a non existing account and will not receive any messages. + * If NULL, reports will be send to the proxy domain. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The SIP address of the collector end-point. + */ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg); + +/** + * Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an + * interval report will be sent to the collector. On call termination, a session report will be sent + * for the remaining period. Value must be 0 (disabled) or positive. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] interval The interval in seconds, 0 means interval reports are disabled. + */ +LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval); + +/** + * Get the interval between interval reports when using quality reporting. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The interval in seconds, 0 means interval reports are disabled. + */ + +LINPHONE_PUBLIC int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg); + +/** + * Get the registration state of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The registration state of the proxy config. +**/ +LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *cfg); + +/** + * @return a boolean indicating that the user is sucessfully registered on the proxy. + * @deprecated Use linphone_proxy_config_get_state() instead. +**/ +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg); + +/** + * Get the domain name of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The domain name of the proxy config. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); + +/** + * Get the realm of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The realm of the proxy config. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg); + +/** + * Set the realm of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] realm New realm value. + * @return The realm of the proxy config. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char * realm); + +/** + * @return the route set for this proxy configuration. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg); + +/** + * @return the SIP identity that belongs to this proxy configuration. +**/ +LINPHONE_PUBLIC const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg); + +/** + * @deprecated use linphone_proxy_config_get_identity_address() +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg); + +/** + * @return TRUE if PUBLISH request is enabled for this proxy. +**/ +LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg); + +/** + * @return the proxy's SIP address. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *cfg); + +#define linphone_proxy_config_get_addr linphone_proxy_config_get_server_addr + +/** + * @return the duration of registration. +**/ +LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg); + +/** + * @return TRUE if registration to the proxy is enabled. +**/ +LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *cfg); + +/** + * Refresh a proxy registration. + * This is useful if for example you resuming from suspend, thus IP address may have changed. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg); + +/** + * Prevent a proxy config from refreshing its registration. + * This is useful to let registrations to expire naturally (or) when the application wants to keep control on when + * refreshes are sent. + * However, linphone_core_set_network_reachable(lc,TRUE) will always request the proxy configs to refresh their registrations. + * The refreshing operations can be resumed with linphone_proxy_config_refresh_register(). + * @param[in] cfg #LinphoneProxyConfig object. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg); + +LINPHONE_PUBLIC const LinphoneAddress* linphone_proxy_config_get_contact(const LinphoneProxyConfig *cfg); + +/** + * @return previously set contact parameters. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg); + +/** + * Set optional contact parameters that will be added to the contact information sent in the registration. + * @param[in] cfg #LinphoneProxyConfig object. + * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. + * As an example, the contact address in the SIP register sent will look like ;apple-push-id=43143-DFE23F-2323-FA2232. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *cfg, const char *contact_params); + +/** + * Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI. + * @param[in] cfg #LinphoneProxyConfig object. + * @param contact_uri_params a string containing the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. + * As an example, the contact address in the SIP register sent will look like . +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *cfg, const char *contact_uri_params); + +/** + * @return previously set contact URI parameters. +**/ +LINPHONE_PUBLIC const char* linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *cfg); + +/** + * Get the #LinphoneCore object to which is associated the #LinphoneProxyConfig. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The #LinphoneCore object to which is associated the #LinphoneProxyConfig. +**/ +LINPHONE_PUBLIC LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *cfg); + +/** + * @return whether liblinphone should replace "+" by "00" in dialed numbers (passed to + * #linphone_core_invite ). + * +**/ +LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); + +/** + * @return dialing prefix. +**/ +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. + * @return The reason why registration failed for this proxy config. +**/ +LINPHONE_PUBLIC LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); + +/** + * Get detailed information why registration failed when the proxy config state is LinphoneRegistrationFailed. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The details why registration failed for this proxy config. +**/ +LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg); + +/** + * Get the transport from either service route, route or addr. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The transport as a string (I.E udp, tcp, tls, dtls) +**/ +LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg); + +/** + * Destroys a proxy config. + * @deprecated + * + * @note: LinphoneProxyConfig that have been removed from LinphoneCore with + * linphone_core_remove_proxy_config() must not be freed. +**/ +LINPHONE_PUBLIC void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); + +LINPHONE_PUBLIC void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type); +LINPHONE_PUBLIC SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); + +/** + * Detect if the given input is a phone number or not. + * @param proxy #LinphoneProxyConfig argument, unused yet but may contain useful data. Can be NULL. + * @param username string to parse. + * @return TRUE if input is a phone number, FALSE otherwise. +**/ +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig *proxy, const char *username); + +/** + * Normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 + * or +33888444222 depending on the #LinphoneProxyConfig object. However this argument is OPTIONNAL + * and if not provided, a default one will be used. + * This function will always generate a normalized username; if input is not a phone number, output will be a copy of input. + * @param proxy #LinphoneProxyConfig object containing country code and/or escape symbol. If NULL passed, will use default configuration. + * @param username the string to parse + * @param result the newly normalized number + * @param result_len the size of the normalized number \a result + * @return TRUE if a phone number was recognized, FALSE otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); + +/** + * Same objective as linphone_proxy_config_normalize_number but allocates a new string + * @param proxy #LinphoneProxyConfig object containing country code and/or escape symbol. If NULL passed, will use default configuration. + * @param username the string to parse + * @return NULL if invalid phone number, normalized phone number from username input otherwise. +*/ +LINPHONE_PUBLIC char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username); + +/** + * Normalize a human readable sip uri into a fully qualified LinphoneAddress. + * A sip address should look like DisplayName \ . + * Basically this function performs the following tasks + * - if a phone number is entered, prepend country prefix and eventually escape the '+' by 00 of the proxy config. + * - if no domain part is supplied, append the domain name of the proxy config. Returns NULL if no proxy is provided at this point. + * - if no sip: is present, prepend it. + * + * The result is a syntactically correct SIP address. + * @param proxy #LinphoneProxyConfig object containing country code, escape symbol and/or domain name. Can be NULL if domain is already provided. + * @param username the string to parse + * @return NULL if invalid input, normalized sip address otherwise. +*/ +LINPHONE_PUBLIC LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *proxy, const char *username); + +/** + * Set default privacy policy for all calls routed through this proxy. + * @param[in] cfg #LinphoneProxyConfig object. + * @param privacy LinphonePrivacy to configure privacy + * */ +LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *cfg, LinphonePrivacyMask privacy); + +/** + * Get default privacy policy for all calls routed through this proxy. + * @param[in] cfg #LinphoneProxyConfig object. + * @return Privacy mode + * */ +LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *cfg); + +/** + * Set the http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml + * @param[in] cfg #LinphoneProxyConfig object. + * @param server_url URL of the file server like https://file.linphone.org/upload.php + * */ +LINPHONE_PUBLIC void linphone_proxy_config_set_file_transfer_server(LinphoneProxyConfig *cfg, const char * server_url); + +/** + * Get the http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml + * @param[in] cfg #LinphoneProxyConfig object. + * @return URL of the file server like https://file.linphone.org/upload.php + * */ +LINPHONE_PUBLIC const char* linphone_proxy_config_get_file_transfer_server(const LinphoneProxyConfig *cfg); + +/** + * Indicates whether AVPF/SAVPF must be used for calls using this proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] enable True to enable AVPF/SAVF, false to disable it. + * @deprecated use linphone_proxy_config_set_avpf_mode() + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable); + +/** + * Indicates whether AVPF/SAVPF is being used for calls using this proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @return True if AVPF/SAVPF is enabled, false otherwise. + * @deprecated use linphone_proxy_config_set_avpf_mode() + */ +LINPHONE_PUBLIC bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg); + +/** + * Set the interval between regular RTCP reports when using AVPF/SAVPF. + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] interval The interval in seconds (between 0 and 5 seconds). + */ +LINPHONE_PUBLIC void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval); + +/** + * Get the interval between regular RTCP reports when using AVPF/SAVPF. + * @param[in] cfg #LinphoneProxyConfig object. + * @return The interval in seconds. + */ +LINPHONE_PUBLIC uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg); + +/** + * Get enablement status of RTCP feedback (also known as AVPF profile). + * @param[in] cfg #LinphoneProxyConfig object. + * @return the enablement mode, which can be LinphoneAVPFDefault (use LinphoneCore's mode), LinphoneAVPFEnabled (avpf is enabled), or LinphoneAVPFDisabled (disabled). +**/ +LINPHONE_PUBLIC LinphoneAVPFMode linphone_proxy_config_get_avpf_mode(const LinphoneProxyConfig *cfg); + +/** + * Enable the use of RTCP feedback (also known as AVPF profile). + * @param[in] cfg #LinphoneProxyConfig object. + * @param[in] mode the enablement mode, which can be LinphoneAVPFDefault (use LinphoneCore's mode), LinphoneAVPFEnabled (avpf is enabled), or LinphoneAVPFDisabled (disabled). +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_avpf_mode(LinphoneProxyConfig *cfg, LinphoneAVPFMode mode); + +/** + * Obtain the value of a header sent by the server in last answer to REGISTER. + * @param[in] cfg #LinphoneProxyConfig object. + * @param header_name the header name for which to fetch corresponding value + * @return the value of the queried header. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_custom_header(LinphoneProxyConfig *cfg, const char *header_name); + +/** + * Set the value of a custom header sent to the server in REGISTERs request. + * @param[in] cfg #LinphoneProxyConfig object. + * @param header_name the header name + * @param header_value the header's value +**/ +LINPHONE_PUBLIC void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const char *header_name, const char *header_value); + +/** + * @} + */ + +#endif diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index f0de56694..7dd27d890 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -29,7 +29,7 @@ #include "private.h" #include "lpconfig.h" -LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ +LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){ return lc->tunnel; } @@ -44,31 +44,37 @@ extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){ return tunnel; } -static inline belledonnecomm::TunnelManager *bcTunnel(LinphoneTunnel *tunnel){ +belledonnecomm::TunnelManager *bcTunnel(const LinphoneTunnel *tunnel){ return tunnel->manager; } -static inline _LpConfig *config(LinphoneTunnel *tunnel){ +static inline _LpConfig *config(const LinphoneTunnel *tunnel){ return tunnel->manager->getLinphoneCore()->config; } void linphone_tunnel_destroy(LinphoneTunnel *tunnel){ delete tunnel->manager; + + ms_list_free_with_data(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy); + ms_free(tunnel); } static char *linphone_tunnel_config_to_string(const LinphoneTunnelConfig *tunnel_config) { char *str = NULL; - if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) != -1) { - str = ms_strdup_printf("%s:%d:%d:%d", - linphone_tunnel_config_get_host(tunnel_config), - linphone_tunnel_config_get_port(tunnel_config), - linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), - linphone_tunnel_config_get_delay(tunnel_config)); - } else { - str = ms_strdup_printf("%s:%d", - linphone_tunnel_config_get_host(tunnel_config), - linphone_tunnel_config_get_port(tunnel_config)); + const char *host = linphone_tunnel_config_get_host(tunnel_config); + if(host != NULL) { + if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) != -1) { + str = ms_strdup_printf("%s:%d:%d:%d", + linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config), + linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), + linphone_tunnel_config_get_delay(tunnel_config)); + } else { + str = ms_strdup_printf("%s:%d", + linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config)); + } } return str; } @@ -96,12 +102,12 @@ static LinphoneTunnelConfig *linphone_tunnel_config_from_string(const char *str) break; case 3: delay = atoi(pch); - break; + break; default: // Abort pos = 0; break; - + } ++pos; pch = strtok(NULL, ":"); @@ -117,26 +123,27 @@ static LinphoneTunnelConfig *linphone_tunnel_config_from_string(const char *str) if(pos == 4) { linphone_tunnel_config_set_delay(tunnel_config, delay); } - ms_free(dstr); + ms_free(dstr); return tunnel_config; } -static void linphone_tunnel_save_config(LinphoneTunnel *tunnel) { - MSList *elem = tunnel->config_list; +static void linphone_tunnel_save_config(const LinphoneTunnel *tunnel) { + MSList *elem = NULL; char *tmp = NULL, *old_tmp = NULL, *tc_str = NULL; - while(elem != NULL) { + for(elem = tunnel->config_list; elem != NULL; elem = elem->next) { LinphoneTunnelConfig *tunnel_config = (LinphoneTunnelConfig *)elem->data; tc_str = linphone_tunnel_config_to_string(tunnel_config); - if(tmp != NULL) { - old_tmp = tmp; - tmp = ms_strdup_printf("%s %s", old_tmp, tc_str); - ms_free(old_tmp); - ms_free(tc_str); - } else { - tmp = tc_str; + if(tc_str != NULL) { + if(tmp != NULL) { + old_tmp = tmp; + tmp = ms_strdup_printf("%s %s", old_tmp, tc_str); + ms_free(old_tmp); + ms_free(tc_str); + } else { + tmp = tc_str; + } } - elem = elem->next; } lp_config_set_string(config(tunnel), "tunnel", "server_addresses", tmp); if(tmp != NULL) { @@ -147,12 +154,12 @@ static void linphone_tunnel_save_config(LinphoneTunnel *tunnel) { static void linphone_tunnel_add_server_intern(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) { if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) == -1) { - bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), + bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), linphone_tunnel_config_get_port(tunnel_config)); } else { - bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), - linphone_tunnel_config_get_port(tunnel_config), - linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), + bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), + linphone_tunnel_config_get_port(tunnel_config), + linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), linphone_tunnel_config_get_delay(tunnel_config)); } tunnel->config_list = ms_list_append(tunnel->config_list, tunnel_config); @@ -204,33 +211,41 @@ void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig MSList *elem = ms_list_find(tunnel->config_list, tunnel_config); if(elem != NULL) { tunnel->config_list = ms_list_remove(tunnel->config_list, tunnel_config); - linphone_tunnel_config_destroy(tunnel_config); + linphone_tunnel_config_destroy(tunnel_config); linphone_tunnel_refresh_config(tunnel); linphone_tunnel_save_config(tunnel); - } + } } -const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ +const MSList *linphone_tunnel_get_servers(const LinphoneTunnel *tunnel){ return tunnel->config_list; } void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ bcTunnel(tunnel)->cleanServers(); - + /* Free the list */ - ms_list_for_each(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy); - tunnel->config_list = ms_list_free(tunnel->config_list); - + ms_list_free_with_data(tunnel->config_list, (void (*)(void *))linphone_tunnel_config_destroy); + tunnel->config_list = NULL; + linphone_tunnel_save_config(tunnel); } -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ - lp_config_set_int(config(tunnel),"tunnel","enabled",(int)enabled); - bcTunnel(tunnel)->enable(enabled); +void linphone_tunnel_set_mode(LinphoneTunnel *tunnel, LinphoneTunnelMode mode){ + lp_config_set_string(config(tunnel),"tunnel","mode", linphone_tunnel_mode_to_string(mode)); + bcTunnel(tunnel)->setMode(mode); } -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ - return bcTunnel(tunnel)->isEnabled(); +LinphoneTunnelMode linphone_tunnel_get_mode(const LinphoneTunnel *tunnel){ + return bcTunnel(tunnel)->getMode(); +} + +bool_t linphone_tunnel_connected(const LinphoneTunnel *tunnel){ + return bcTunnel(tunnel)->isConnected(); +} + +bool_t linphone_tunnel_get_activated(const LinphoneTunnel *tunnel){ + return bcTunnel(tunnel)->isActivated(); } static OrtpLogFunc tunnelOrtpLogHandler=NULL; @@ -306,22 +321,47 @@ void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ bcTunnel(tunnel)->reconnect(); } -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ - bcTunnel(tunnel)->autoDetect(); +void linphone_tunnel_enable_sip(LinphoneTunnel *tunnel, bool_t enable) { + bcTunnel(tunnel)->tunnelizeSipPackets(enable); + lp_config_set_int(config(tunnel), "tunnel", "sip", (enable ? TRUE : FALSE)); +} + +bool_t linphone_tunnel_sip_enabled(const LinphoneTunnel *tunnel) { + return bcTunnel(tunnel)->tunnelizeSipPacketsEnabled() ? TRUE : FALSE; } static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){ ortp_logv(level,fmt,args); } + /** * Startup tunnel using configuration. * Called internally from linphonecore at startup. */ void linphone_tunnel_configure(LinphoneTunnel *tunnel){ - bool_t enabled=(bool_t)lp_config_get_int(config(tunnel),"tunnel","enabled",FALSE); + LinphoneTunnelMode mode = linphone_tunnel_mode_from_string(lp_config_get_string(config(tunnel), "tunnel", "mode", NULL)); + bool_t tunnelizeSIPPackets = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "sip", TRUE); linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv); linphone_tunnel_load_config(tunnel); - linphone_tunnel_enable(tunnel, enabled); + linphone_tunnel_enable_sip(tunnel, tunnelizeSIPPackets); + linphone_tunnel_set_mode(tunnel, mode); } +/* Deprecated functions */ +void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled) { + if(enabled) linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeEnable); + else linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeDisable); +} + +bool_t linphone_tunnel_enabled(const LinphoneTunnel *tunnel) { + return linphone_tunnel_get_mode(tunnel) == LinphoneTunnelModeEnable; +} + +void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel) { + linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeAuto); +} + +bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) { + return linphone_tunnel_get_mode(tunnel) == LinphoneTunnelModeAuto; +} diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index e42a054dc..ecaaf2227 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -22,26 +22,65 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #ifndef LINPHONETUNNEL_H #define LINPHONETUNNEL_H #include "linphonecore.h" + /** * @addtogroup tunnel * @{ **/ /** - * This set of methods enhance LinphoneCore functionalities in order to provide an easy to use API to - * - provision tunnel servers ip addresses and ports. This functionality is an option not implemented under GPL. - * - start/stop the tunneling service - * - perform auto-detection whether tunneling is required, based on a test of sending/receiving a flow of UDP packets. + * Linphone tunnel aims is to bypass IP traffic blocking due to aggressive firewalls which typically only authorize TCP traffic with destination port 443. + *
    Its principle is tunneling all SIP and/or RTP traffic through a single secure https connection up to a detunnelizer server. + *
    This set of methods enhance LinphoneCore functionalities in order to provide an easy to use API to + * \li provision tunnel servers IP addresses and ports. This functionality is an option not implemented under GPL. Availability can be check at runtime using function #linphone_core_tunnel_available + * \li start/stop the tunneling service + * \li perform auto-detection whether tunneling is required, based on a test of sending/receiving a flow of UDP packets. * * It takes in charge automatically the SIP registration procedure when connecting or disconnecting to a tunnel server. * No other action on LinphoneCore is required to enable full operation in tunnel mode. - **/ + * + *
    Provision is done using object #LinphoneTunnelConfig created by function #linphone_tunnel_config_new(). Functions #linphone_tunnel_config_set_host + * and #linphone_tunnel_config_set_port allow to point to tunnel server IP/port. Once set, use function #linphone_tunnel_add_server to provision a tunnel server. + *
    Finally tunnel mode configuration is achieved by function #linphone_tunnel_set_mode. + *
    Tunnel connection status can be checked using function #linphone_tunnel_connected. + * + * Bellow pseudo code that can be use to configure, enable, check state and disable tunnel functionality: + * + * \code + LinphoneTunnel *tunnel = linphone_core_get_tunnel(linphone_core); + LinphoneTunnelConfig *config=linphone_tunnel_config_new(); //instantiate tunnel configuration + linphone_tunnel_config_set_host(config, "tunnel.linphone.org"); //set tunnel server host address + linphone_tunnel_config_set_port(config, 443); //set tunnel server port + linphone_tunnel_add_server(tunnel, config); //provision tunnel config + linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeEnable); //activate the tunnel unconditional + + while (!linphone_tunnel_connected(tunnel)) { //wait for tunnel to be ready + linphone_core_iterate(linphone_core); //schedule core main loop + ms_sleep(100); //wait 100ms + } + + LinphoneCall *call = linphone_core_invite(linphone_core,"sip:foo@example.org"); //place an outgoing call + linphone_call_ref(call); //acquire a reference on the call to avoid deletion after completion + //... + linphone_core_terminate_call(linphone_core,call); + + while (linphone_call_get_state(call) != LinphoneCallReleased) { //wait for call to be in release state + linphone_core_iterate(linphone_core); //schedule core main loop + ms_sleep(100); //wait 100ms + } + + linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeDisable); //deactivate tunnel + linphone_call_unref(call); //release reference on the call + + \endcode +* +* **/ #ifdef __cplusplus extern "C" @@ -50,161 +89,245 @@ extern "C" typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig; +/** + * Enum describing the tunnel modes. +**/ +typedef enum _LinphoneTunnelMode { + LinphoneTunnelModeDisable, /**< The tunnel is disabled. */ + LinphoneTunnelModeEnable, /**< The tunnel is enabled. */ + LinphoneTunnelModeAuto /**< The tunnel is enabled automatically if it is required. */ +} LinphoneTunnelMode; + +/** + * Convert a string into LinphoneTunnelMode enum + * @param string String to convert + * @return An LinphoneTunnelMode enum. If the passed string is NULL or + * does not match with any mode, the LinphoneTunnelModeDisable is returned. + */ +LINPHONE_PUBLIC LinphoneTunnelMode linphone_tunnel_mode_from_string(const char *string); + +/** + * Convert a tunnel mode enum into string + * @param mode Enum to convert + * @return "disable", "enable" or "auto" + */ +LINPHONE_PUBLIC const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mode); + /** * Create a new tunnel configuration */ -LinphoneTunnelConfig *linphone_tunnel_config_new(); +LINPHONE_PUBLIC LinphoneTunnelConfig *linphone_tunnel_config_new(void); /** - * Set address of server. - * - * @param tunnel configuration object - * @param host tunnel server ip address + * Set the IP address or hostname of the tunnel server. + * @param tunnel LinphoneTunnelConfig object + * @param host The tunnel server IP address or hostname */ -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 + * Get the IP address or hostname of the tunnel server. + * @param tunnel LinphoneTunnelConfig object + * @return The tunnel server IP address or hostname */ -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. - * - * @param tunnel configuration object - * @param port tunnel server tls port, recommended value is 443 + * @param tunnel LinphoneTunnelConfig object + * @param port The 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 + * Get the TLS port of the tunnel server. + * @param tunnel LinphoneTunnelConfig object + * @return The TLS port of the tunnel server */ -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. - * - * @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 + * Set the remote port on the tunnel server side used to test UDP reachability. + * This is used when the mode is set auto, to detect whether the tunnel has to be enabled or not. + * @param tunnel LinphoneTunnelConfig object + * @param remote_udp_mirror_port The 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 + * Get the remote port on the tunnel server side used to test UDP reachability. + * This is used when the mode is set auto, to detect whether the tunnel has to be enabled or not. + * @param tunnel LinphoneTunnelConfig object + * @return The remote port on the tunnel server side used to test UDP reachability */ -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. - * - * @param tunnel configuration object - * @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms. + * Set the UDP packet round trip delay in ms for a tunnel configuration. + * @param tunnel LinphoneTunnelConfig object + * @param delay The 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 + * Get the UDP packet round trip delay in ms for a tunnel configuration. + * @param tunnel LinphoneTunnelConfig object + * @return The UDP packet round trip delay in ms. */ -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 + * @param tunnel LinphoneTunnelConfig object */ -void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); /** - * Add tunnel server configuration - * - * @param tunnel object - * @param tunnel_config object + * Add a tunnel server configuration. + * @param tunnel LinphoneTunnel object + * @param tunnel_config LinphoneTunnelConfig 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 - * - * @param tunnel object - * @param tunnel_config object + * Remove a tunnel server configuration. + * @param tunnel LinphoneTunnel object + * @param tunnel_config LinphoneTunnelConfig 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); + * Get added servers + * @param tunnel LinphoneTunnel object + * @return \mslist{LinphoneTunnelConfig} + */ +LINPHONE_PUBLIC const MSList *linphone_tunnel_get_servers(const LinphoneTunnel *tunnel); /** - * @param tunnel object - * Removes all tunnel server address previously entered with addServer() + * Remove all tunnel server addresses previously entered with linphone_tunnel_add_server() + * @param tunnel LinphoneTunnel object **/ -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. - * @param tunnel object - * @param enabled If true enter in tunneled mode, if false exits from tunneled mode. - * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode. - * + * Set the tunnel mode. + * The tunnel mode can be 'enable', 'disable' or 'auto' + * If the mode is set to 'auto', the tunnel manager will try to established an RTP session + * with the tunnel server on the UdpMirrorPort. If the connection fail, the tunnel is automatically + * activated whereas the tunnel is automatically disabled if the connection succeed. + * @param tunnel LinphoneTunnel object + * @param mode The desired LinphoneTunnelMode **/ -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); +LINPHONE_PUBLIC void linphone_tunnel_set_mode(LinphoneTunnel *tunnel, LinphoneTunnelMode mode); /** - * @param tunnel object - * Returns a boolean indicating whether tunneled operation is enabled. + * Get the tunnel mode + * @param tunnel LinphoneTunnel object + * @return The current LinphoneTunnelMode **/ -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC LinphoneTunnelMode linphone_tunnel_get_mode(const LinphoneTunnel *tunnel); /** - * @param tunnel object - * Forces reconnection to the tunnel server. + * Returns whether the tunnel is activated. If mode is set to auto, this gives indication whether the automatic detection determined + * that tunnel was necessary or not. + * @param tunnel the tunnel + * @return TRUE if tunnel is in use, FALSE otherwise. +**/ +LINPHONE_PUBLIC bool_t linphone_tunnel_get_activated(const LinphoneTunnel *tunnel); + + +/** + * Check whether the tunnel is connected + * @param tunnel LinphoneTunnel object + * @return A boolean value telling if the tunnel is connected +**/ +LINPHONE_PUBLIC bool_t linphone_tunnel_connected(const LinphoneTunnel *tunnel); + +/** + * Force reconnection to the tunnel server. * This method is useful when the device switches from wifi to Edge/3G or vice versa. In most cases the tunnel client socket * 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. + * @param tunnel LinphoneTunnel object **/ -void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); /** - * Start tunnel need detection. - * @param tunnel object - * In auto detect mode, the tunnel manager try to establish a real time rtp cummunication with the tunnel server on specified port. - *
    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 + * Set whether SIP packets must be directly sent to a UA or pass through the tunnel + * @param tunnel LinphoneTunnel object + * @param enable If true, SIP packets shall pass through the tunnel */ -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_enable_sip(LinphoneTunnel *tunnel, bool_t enable); + +/** + * Check whether tunnel is set to transport SIP packets + * @param tunnel LinphoneTunnel object + * @return A boolean value telling whether SIP packets shall pass through the tunnel + */ +LINPHONE_PUBLIC bool_t linphone_tunnel_sip_enabled(const LinphoneTunnel *tunnel); /** * Set an optional http proxy to go through when connecting to tunnel server. * @param tunnel LinphoneTunnel object - * @param host Http proxy host. - * @param port http proxy port. - * @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. + * @param host http proxy host + * @param port http proxy port + * @param username Optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. + * @param passwd 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(). * @param tunnel LinphoneTunnel object - * @param host Http proxy host. - * @param port http proxy port. - * @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. + * @param host http proxy host + * @param port http proxy port + * @param username Optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. + * @param passwd 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); +/** + * Set authentication info for the http proxy + * @param tunnel LinphoneTunnel object + * @param username User name + * @param passwd Password + */ +LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); +/** + * Sets whether tunneling of SIP and RTP is required. + * @param tunnel object + * @param enabled If true enter in tunneled mode, if false exits from tunneled mode. + * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode. + * @deprecated Replaced by linphone_tunnel_set_mode() +**/ +LINPHONE_PUBLIC void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); + +/** + * Check whether tunnel is enabled + * @param tunnel Tunnel object + * @return Returns a boolean indicating whether tunneled operation is enabled. + * @deprecated Replaced by linphone_tunnel_get_mode() +**/ +LINPHONE_PUBLIC bool_t linphone_tunnel_enabled(const LinphoneTunnel *tunnel); + +/** + * Start tunnel need detection. + * @param tunnel object + * In auto detect mode, the tunnel manager try to establish a real time rtp communication with the tunnel server on specified port. + *
    In case of success, the tunnel is automatically turned off. Otherwise, if no udp communication is feasible, tunnel mode is turned on. + *
    Call this method each time to run the auto detection algorithm + * @deprecated Replaced by linphone_tunnel_set_mode(LinphoneTunnelModeAuto) + */ +LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); + +/** + * Tell whether tunnel auto detection is enabled. + * @param[in] tunnel LinphoneTunnel object. + * @return TRUE if auto detection is enabled, FALSE otherwise. + * @deprecated Replaced by linphone_tunnel_get_mode() + */ +LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel); /** * @} diff --git a/coreapi/linphone_tunnel_stubs.c b/coreapi/linphone_tunnel_stubs.c index 0560b3956..bfe793be6 100644 --- a/coreapi/linphone_tunnel_stubs.c +++ b/coreapi/linphone_tunnel_stubs.c @@ -29,7 +29,7 @@ #include "lpconfig.h" -LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ +LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){ return lc->tunnel; } @@ -45,20 +45,27 @@ void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tu void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){ } -const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){ - return NULL; +const MSList *linphone_tunnel_get_servers(const LinphoneTunnel *tunnel){ + return NULL; } void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ } -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ +void linphone_tunnel_set_mode(LinphoneTunnel *tunnel, LinphoneTunnelMode mode) { } -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ - return FALSE; +LinphoneTunnelMode linphone_tunnel_get_mode(const LinphoneTunnel *tunnel){ + return LinphoneTunnelModeDisable; } +bool_t linphone_tunnel_connected(const LinphoneTunnel *tunnel){ + return FALSE; +} + +bool_t linphone_tunnel_get_activated(const LinphoneTunnel *tunnel){ + return FALSE; +} void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ } @@ -75,9 +82,14 @@ void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ } -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ -} - void linphone_tunnel_configure(LinphoneTunnel *tunnel){ } +void linphone_tunnel_enable_sip(LinphoneTunnel *tunnel, bool_t enable) {} +bool_t linphone_tunnel_sip_enabled(const LinphoneTunnel *tunnel) { return FALSE; } + +/* Deprecated functions */ +void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled) {} +bool_t linphone_tunnel_enabled(const LinphoneTunnel *tunnel) { return FALSE; } +void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel) {} +bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) { return FALSE; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 9872c0f5d..45a78f47f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -18,7 +18,7 @@ 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 WIN32 +#ifdef _WIN32 #include #endif #include "linphonecore.h" @@ -37,30 +37,50 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/mssndcard.h" -#ifdef VIDEO_ENABLED -static MSWebCam *get_nowebcam_device(){ - return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture"); -} -#endif +static const char *EC_STATE_STORE = ".linphone.ecstate"; +#define EC_STATE_MAX_LEN 1048576 // 1Mo -static bool_t generate_b64_crypto_key(int key_length, char* key_out) { +static void linphone_call_stats_uninit(LinphoneCallStats *stats); +static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr); + + +MSWebCam *get_nowebcam_device(){ +#ifdef VIDEO_ENABLED + return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture"); +#else + return NULL; +#endif +} + + +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; } @@ -72,63 +92,99 @@ const char* linphone_call_get_authentication_token(LinphoneCall *call){ return call->auth_token; } +/** + * Returns whether ZRTP authentication token is verified. + * If not, it must be verified by users as described in ZRTP procedure. + * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified(). + * @param call the LinphoneCall + * @return TRUE if authentication token is verifed, false otherwise. + * @ingroup call_control +**/ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){ return call->auth_token_verified; } -static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) { - // Check ZRTP encryption in audiostream - if (!call->audiostream_encrypted) { - return FALSE; +static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) { + int number_of_encrypted_stream = 0; + int number_of_active_stream = 0; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + number_of_active_stream++; + if(media_stream_secured((MediaStream *)call->audiostream)) + number_of_encrypted_stream++; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + number_of_active_stream++; + if (media_stream_secured((MediaStream *)call->videostream)) + number_of_encrypted_stream++; + } } - -#ifdef VIDEO_ENABLED - // If video enabled, check ZRTP encryption in videostream - const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (params->has_video && !call->videostream_encrypted) { - return FALSE; - } -#endif - - return TRUE; + return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream; } -void propagate_encryption_changed(LinphoneCall *call){ - LinphoneCore *lc=call->core; - if (!linphone_call_are_all_streams_encrypted(call)) { - ms_message("Some streams are not encrypted"); - call->current_params.media_encryption=LinphoneMediaEncryptionNone; - if (lc->vtable.call_encryption_changed) - lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token); +static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) { + int nb_active_streams = 0; + int nb_avpf_enabled_streams = 0; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + nb_active_streams++; + if (media_stream_avpf_enabled((MediaStream *)call->audiostream)) + nb_avpf_enabled_streams++; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + nb_active_streams++; + if (media_stream_avpf_enabled((MediaStream *)call->videostream)) + nb_avpf_enabled_streams++; + } + } + return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams)); +} + +static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { + uint16_t rr_interval = 0; + uint16_t stream_rr_interval; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream); + if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream); + if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; + } } else { - ms_message("All streams are encrypted"); - call->current_params.media_encryption=LinphoneMediaEncryptionZRTP; - if (lc->vtable.call_encryption_changed) - lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token); + rr_interval = 5000; + } + return rr_interval; +} + +static void propagate_encryption_changed(LinphoneCall *call){ + if (!linphone_call_all_streams_encrypted(call)) { + ms_message("Some streams are not encrypted"); + call->current_params->media_encryption=LinphoneMediaEncryptionNone; + linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token); + } else { + if (call->auth_token) {/* ZRTP only is using auth_token */ + call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + } else { /* otherwise it must be DTLS as SDES doesn't go through this function */ + call->current_params->media_encryption=LinphoneMediaEncryptionDTLS; + } + ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); + linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token); } } -#ifdef VIDEO_ENABLED -static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){ - ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted"); - - LinphoneCall *call = (LinphoneCall *)data; - call->videostream_encrypted=encrypted; - propagate_encryption_changed(call); -} -#endif - 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"); call = (LinphoneCall *)data; - call->audiostream_encrypted=encrypted; - - if (encrypted && call->core->vtable.display_status != NULL) { - snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); - call->core->vtable.display_status(call->core, status); + + if (encrypted) { + if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */ + snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); + linphone_core_notify_display_status(call->core, status); + } } propagate_encryption_changed(call); @@ -136,12 +192,14 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr #ifdef VIDEO_ENABLED // Enable video encryption - const LinphoneCallParams *params=linphone_call_get_current_params(call); - if (params->has_video) { - ms_message("Trying to enable encryption on video stream"); - OrtpZrtpParams params; - params.zid_file=NULL; //unused - video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); + { + const LinphoneCallParams *params=linphone_call_get_current_params(call); + if (params->has_video) { + MSZrtpParams params; + ms_message("Trying to enable encryption on video stream"); + params.zid_file=NULL; //unused + video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); + } } #endif } @@ -158,52 +216,199 @@ static void linphone_call_audiostream_auth_token_ready(void *data, const char* a ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified"); } +/** + * Set the result of ZRTP short code verification by user. + * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users. + * @param call the LinphoneCall + * @param verified whether the ZRTP SAS is verified. + * @ingroup call_control +**/ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){ if (call->audiostream==NULL){ ms_error("linphone_call_set_authentication_token_verified(): No audio stream"); } - if (call->audiostream->ms.zrtp_context==NULL){ + if (call->audiostream->ms.sessions.zrtp_context==NULL){ ms_error("linphone_call_set_authentication_token_verified(): No zrtp context."); } if (!call->auth_token_verified && verified){ - ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context); + ms_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context); }else if (call->auth_token_verified && !verified){ - ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context); + ms_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context); } call->auth_token_verified=verified; propagate_encryption_changed(call); } -static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){ +static int get_max_codec_sample_rate(const MSList *codecs){ + int max_sample_rate=0; + const MSList *it; + for(it=codecs;it!=NULL;it=it->next){ + PayloadType *pt=(PayloadType*)it->data; + int sample_rate; + + if( strcasecmp("G722",pt->mime_type) == 0 ){ + /* G722 spec says 8000 but the codec actually requires 16000 */ + sample_rate = 16000; + }else sample_rate=pt->clock_rate; + if (sample_rate>max_sample_rate) max_sample_rate=sample_rate; + } + return max_sample_rate; +} + +static int find_payload_type_number(const MSList *assigned, const PayloadType *pt){ + const MSList *elem; + const PayloadType *candidate=NULL; + for(elem=assigned;elem!=NULL;elem=elem->next){ + const PayloadType *it=(const PayloadType*)elem->data; + if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0) + && (it->clock_rate==pt->clock_rate) + && (it->channels==pt->channels || pt->channels<=0)) { + candidate=it; + if ((it->recv_fmtp!=NULL && pt->recv_fmtp!=NULL && strcasecmp(it->recv_fmtp, pt->recv_fmtp)==0) + || (it->recv_fmtp==NULL && pt->recv_fmtp==NULL)){ + break;/*exact match*/ + } + } + } + return candidate ? payload_type_get_number(candidate) : -1; +} + +bool_t is_payload_type_number_available(const MSList *l, int number, const PayloadType *ignore){ + const MSList *elem; + for (elem=l; elem!=NULL; elem=elem->next){ + const PayloadType *pt=(PayloadType*)elem->data; + if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE; + } + return TRUE; +} + +static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, MSList *codecs){ + MSList *elem; + int dyn_number=lc->codecs_conf.dyn_pt; + for (elem=codecs; elem!=NULL; elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + int number=payload_type_get_number(pt); + + /*check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer*/ + if (number!=-1 && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)){ + if (!is_payload_type_number_available(codecs, number, pt)){ + ms_message("Reassigning payload type %i %s/%i because already offered.", number, pt->mime_type, pt->clock_rate); + number=-1; /*need to be re-assigned*/ + } + } + + if (number==-1){ + while(dyn_number<127){ + if (is_payload_type_number_available(codecs, dyn_number, NULL)){ + payload_type_set_number(pt, dyn_number); + dyn_number++; + break; + } + dyn_number++; + } + if (dyn_number==127){ + ms_error("Too many payload types configured ! codec %s/%i is disabled.", pt->mime_type, pt->clock_rate); + payload_type_set_enable(pt, FALSE); + } + } + } +} + +static bool_t has_telephone_event_at_rate(const MSList *tev, int rate){ + const MSList *it; + for(it=tev;it!=NULL;it=it->next){ + const PayloadType *pt=(PayloadType*)it->data; + if (pt->clock_rate==rate) return TRUE; + } + return FALSE; +} + +static MSList * create_telephone_events(LinphoneCore *lc, const MSList *codecs){ + const MSList *it; + MSList *ret=NULL; + for(it=codecs;it!=NULL;it=it->next){ + const PayloadType *pt=(PayloadType*)it->data; + if (!has_telephone_event_at_rate(ret,pt->clock_rate)){ + PayloadType *tev=payload_type_clone(&payload_type_telephone_event); + tev->clock_rate=pt->clock_rate; + /*let it choose the number dynamically as for normal codecs*/ + payload_type_set_number(tev, -1); + if (ret==NULL){ + /*But for first telephone-event, prefer the number that was configured in the core*/ + if (is_payload_type_number_available(codecs, lc->codecs_conf.telephone_event_pt, NULL)){ + payload_type_set_number(tev, lc->codecs_conf.telephone_event_pt); + } + } + ret=ms_list_append(ret,tev); + } + } + return ret; +} + +static MSList *create_special_payload_types(LinphoneCore *lc, const MSList *codecs){ + MSList *ret=create_telephone_events(lc, codecs); + if (linphone_core_generic_confort_noise_enabled(lc)){ + PayloadType *cn=payload_type_clone(&payload_type_cn); + payload_type_set_number(cn, 13); + ret=ms_list_append(ret, cn); + } + return ret; +} + +typedef struct _CodecConstraints{ + int bandwidth_limit; + int max_codecs; + MSList *previously_used; +}CodecConstraints; + +static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalStreamType stype, const MSList *codecs){ MSList *l=NULL; const MSList *it; int nb = 0; - if (max_sample_rate) *max_sample_rate=0; + for(it=codecs;it!=NULL;it=it->next){ 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); - continue; - } - if (linphone_core_check_payload_type_usability(lc,pt)){ - l=ms_list_append(l,payload_type_clone(pt)); - nb++; - if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt); - } + int num; + + if (!(pt->flags & PAYLOAD_TYPE_ENABLED)) + continue; + if (hints->bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,hints->bandwidth_limit)){ + ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", + pt->mime_type,pt->clock_rate,hints->bandwidth_limit); + continue; } - if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break; + if (!linphone_core_check_payload_type_usability(lc,pt)){ + continue; + } + pt=payload_type_clone(pt); + + /*look for a previously assigned number for this codec*/ + num=find_payload_type_number(hints->previously_used, pt); + if (num!=-1){ + payload_type_set_number(pt,num); + payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER); + } + + l=ms_list_append(l, pt); + nb++; + if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break; } + if (stype==SalAudio){ + MSList *specials=create_special_payload_types(lc,l); + l=ms_list_concat(l,specials); + } + linphone_core_assign_payload_type_numbers(lc, l); return l; } static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ int i; - for (i = 0; i < md->n_active_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { strcpy(md->streams[0].rtp_addr,ac->addr); md->streams[0].rtp_port=ac->port; - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){ + if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){ strcpy(md->addr,ac->addr); } } @@ -214,134 +419,343 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St } } -void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ - MSList *l; - PayloadType *pt; - SalMediaDescription *old_md=call->localdesc; +static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){ + int keylen=0; + crypto->tag=tag; + crypto->algo=suite; + switch(suite){ + case MS_AES_128_SHA1_80: + case MS_AES_128_SHA1_32: + case MS_AES_128_NO_AUTH: + case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/ + keylen=30; + break; + case MS_AES_256_SHA1_80: + case MS_AES_256_SHA1_32: + keylen=46; + break; + case MS_CRYPTO_SUITE_INVALID: + break; + } + if (keylen==0 || !generate_b64_crypto_key(30, crypto->master_key, SAL_SRTP_KEY_SIZE)){ + ms_error("Could not generate SRTP key."); + crypto->algo = 0; + return -1; + } + return 0; +} +static void setup_dtls_keys(LinphoneCall *call, SalMediaDescription *md){ int i; - const char *me=linphone_core_get_identity(lc); - LinphoneAddress *addr=linphone_address_new(me); - const char *username=linphone_address_get_username (addr); - SalMediaDescription *md=sal_media_description_new(); - bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + for(i=0; inb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + /* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */ + if (sal_stream_description_has_dtls(&md->streams[i]) == TRUE) { + strncpy(md->streams[i].dtls_fingerprint, call->dtls_certificate_fingerprint, sizeof(md->streams[i].dtls_fingerprint)); /* get the self fingerprint from call(it's computed at stream init) */ + md->streams[i].dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */ + } else { + md->streams[i].dtls_fingerprint[0] = '\0'; + md->streams[i].dtls_role = SalDtlsRoleInvalid; - linphone_core_adapt_to_network(lc,call->ping_time,&call->params); - - 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)); - - 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)); - 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) ? - SalProtoRtpSavp : SalProtoRtpAvp; - md->streams[0].type=SalAudio; - if (call->params.down_ptime) - md->streams[0].ptime=call->params.down_ptime; - else - md->streams[0].ptime=linphone_core_get_download_ptime(lc); - l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1); - pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); - l=ms_list_append(l,pt); - md->streams[0].payloads=l; - - if (call->params.has_video){ - md->n_active_streams++; - md->streams[1].rtp_port=call->video_port; - md->streams[1].rtcp_port=call->video_port+1; - md->streams[1].proto=md->streams[0].proto; - md->streams[1].type=SalVideo; - l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); - md->streams[1].payloads=l; - } - if (md->n_total_streams < md->n_active_streams) - md->n_total_streams = md->n_active_streams; - - /* Deactivate inactive streams. */ - for (i = md->n_active_streams; i < md->n_total_streams; i++) { - md->streams[i].rtp_port = 0; - md->streams[i].rtcp_port = 0; - md->streams[i].proto = SalProtoRtpAvp; - md->streams[i].type = old_md->streams[i].type; - md->streams[i].dir = SalStreamInactive; - l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1); - md->streams[i].payloads = l; + } } - for(i=0; in_active_streams; i++) { - if (md->streams[i].proto == SalProtoRtpSavp) { - if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ +} +static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ + LinphoneCore *lc=call->core; + int i,j; + SalMediaDescription *old_md=call->localdesc; + bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); + + for(i=0; inb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) { + if (keep_srtp_keys && old_md && (sal_stream_description_active(&old_md->streams[i]) == TRUE) && (sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE)) { 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)) - 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)) - md->streams[i].crypto[1].algo = 0; - md->streams[i].crypto[2].algo = 0; + const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc); + for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && jstreams[i].crypto[j],suites[j],j+1); + } } } } - update_media_description_from_stun(md,&call->ac,&call->vc); +} + +static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { + MSList *pt_it; + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + LinphoneCore *lc = call->core; + int i; + + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0); + md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 0); + for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + if (call->params->avpf_enabled == TRUE) { + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + avpf_params.trr_interval = call->params->avpf_rr_interval; + } else { + payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + memset(&avpf_params, 0, sizeof(avpf_params)); + } + payload_type_set_avpf_params(pt, avpf_params); + } + } +} + +static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) { + LinphoneCore *lc = call->core; + int i; + + md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 1); + if (md->rtcp_xr.enabled == TRUE) { + const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "all"); + if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll; + else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender; + else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; + if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { + md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000); + } + md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 1); + if (md->rtcp_xr.stat_summary_enabled == TRUE) { + md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL; + } + md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 1); + } + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr)); + } +} + +void linphone_call_increment_local_media_description(LinphoneCall *call){ + SalMediaDescription *md=call->localdesc; + md->session_ver++; +} + +void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){ if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(md, call->ice_session); + _update_local_media_description_from_ice(call->localdesc, call->ice_session); linphone_core_update_ice_state_in_call_stats(call); } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { - linphone_core_update_local_media_description_from_upnp(md, call->upnp_session); + linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); linphone_core_update_upnp_state_in_call_stats(call); } #endif //BUILD_UPNP - linphone_address_destroy(addr); - call->localdesc=md; - if (old_md) sal_media_description_unref(old_md); } -static int find_port_offset(LinphoneCore *lc, SalStreamType type){ +static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){ + int i; + for(i=0;inb_streams;++i){ + md->streams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads; + old->streams[i].already_assigned_payloads=NULL; + } +} + +static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){ + const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address",call->af==AF_INET6 ? "::0" : "0.0.0.0"); + + if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0'){ + if (call->dir==LinphoneCallOutgoing){ + /*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/ + bind_ip=call->media_localip; + } + } + return bind_ip; +} + +static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){ + const char *public_ip=call->media_localip; + + if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0') + public_ip=call->media_ports[stream_index].multicast_ip; + return public_ip; +} + +static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){ + int i; + + switch (call->state){ + case LinphoneCallPausing: + case LinphoneCallPaused: + break; + default: + return; + break; + } + + for (i=0; i<2; ++i){ + SalStreamDescription *sd = &md->streams[i]; + sd->dir = SalStreamSendOnly; + if (sd->type == SalVideo){ + if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) { + sd->dir = SalStreamInactive; + } + } + } +} + +void linphone_call_make_local_media_description(LinphoneCall *call) { + MSList *l; + SalMediaDescription *old_md=call->localdesc; + int i; + int nb_active_streams = 0; + SalMediaDescription *md=sal_media_description_new(); + LinphoneAddress *addr; + const char *subject; + CodecConstraints codec_hints={0}; + LinphoneCallParams *params = call->params; + LinphoneCore *lc = call->core; + + + /*multicast is only set in case of outgoing call*/ + if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) { + md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc); + md->streams[0].multicast_role = SalMulticastSender; + } + + if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) { + md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc); + md->streams[1].multicast_role = SalMulticastSender; + } + + subject=linphone_call_params_get_session_name(params); + + linphone_core_adapt_to_network(lc,call->ping_time,params); + + if (call->dest_proxy) { + addr=linphone_address_clone(linphone_proxy_config_get_identity_address(call->dest_proxy)); + } else { + addr=linphone_address_new(linphone_core_get_identity(lc)); + } + + md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); + md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); + md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1); + + /*re-check local ip address each time we make a new offer, because it may change in case of network reconnection*/ + linphone_call_get_local_ip(call, call->dir == LinphoneCallOutgoing ? call->log->to : call->log->from); + strncpy(md->addr,call->media_localip,sizeof(md->addr)); + if (linphone_address_get_username(addr)) /*might be null in case of identity without userinfo*/ + strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); + if (subject) strncpy(md->name,subject,sizeof(md->name)); + + if (params->down_bw) + md->bandwidth=params->down_bw; + else md->bandwidth=linphone_core_get_download_bandwidth(lc); + + /*set audio capabilities */ + strncpy(md->streams[0].rtp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtp_addr)); + strncpy(md->streams[0].rtcp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtcp_addr)); + strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); + md->streams[0].rtp_port=call->media_ports[0].rtp_port; + md->streams[0].rtcp_port=call->media_ports[0].rtcp_port; + md->streams[0].proto=get_proto_from_call_params(params); + md->streams[0].dir=get_audio_dir_from_call_params(params); + md->streams[0].type=SalAudio; + if (params->down_ptime) + md->streams[0].ptime=params->down_ptime; + else + md->streams[0].ptime=linphone_core_get_download_ptime(lc); + codec_hints.bandwidth_limit=params->audio_bw; + codec_hints.max_codecs=-1; + codec_hints.previously_used=old_md ? old_md->streams[0].already_assigned_payloads : NULL; + l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs); + md->streams[0].max_rate=get_max_codec_sample_rate(l); + md->streams[0].payloads=l; + if (call->audiostream && call->audiostream->ms.sessions.rtp_session) { + char* me = linphone_address_as_string_uri_only(call->me); + md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session); + strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname)); + ms_free(me); + } + else + ms_warning("Cannot get audio local ssrc for call [%p]",call); + nb_active_streams++; + + if (params->has_video && (!params->internal_call_update || !call->current_params->video_declined)){ + strncpy(md->streams[1].rtp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtp_addr)); + strncpy(md->streams[1].rtcp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtcp_addr)); + strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1); + md->streams[1].rtp_port=call->media_ports[1].rtp_port; + md->streams[1].rtcp_port=call->media_ports[1].rtcp_port; + md->streams[1].proto=md->streams[0].proto; + md->streams[1].dir=get_video_dir_from_call_params(params); + md->streams[1].type=SalVideo; + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=-1; + codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL; + l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); + md->streams[1].payloads=l; + if (call->videostream && call->videostream->ms.sessions.rtp_session) { + char* me = linphone_address_as_string_uri_only(call->me); + md->streams[1].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session); + strncpy(md->streams[1].rtcp_cname,me,sizeof(md->streams[1].rtcp_cname)); + ms_free(me); + } + else + ms_warning("Cannot get video local ssrc for call [%p]",call); + nb_active_streams++; + } else { + ms_message("Don't put video stream on local offer for call [%p]",call); + } + + if (md->nb_streams < nb_active_streams) + md->nb_streams = nb_active_streams; + + /* Deactivate inactive streams. */ + for (i = nb_active_streams; i < md->nb_streams; i++) { + md->streams[i].rtp_port = 0; + md->streams[i].rtcp_port = 0; + md->streams[i].proto = call->biggestdesc->streams[i].proto; + md->streams[i].type = call->biggestdesc->streams[i].type; + md->streams[i].dir = SalStreamInactive; + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=1; + codec_hints.previously_used=NULL; + l = make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); + md->streams[i].payloads = l; + } + setup_encryption_keys(call,md); + setup_dtls_keys(call,md); + setup_rtcp_fb(call, md); + setup_rtcp_xr(call, md); + + update_media_description_from_stun(md,&call->ac,&call->vc); + call->localdesc=md; + linphone_call_update_local_media_description_from_ice_or_upnp(call); + linphone_address_destroy(addr); + if (old_md){ + transfer_already_assigned_payload_types(old_md,md); + call->localdesc_changed=sal_media_description_equals(md,old_md); + sal_media_description_unref(old_md); + } + force_streams_dir_according_to_state(call, md); +} + +static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){ int offset; MSList *elem; int tried_port; int existing_port; bool_t already_used=FALSE; + for(offset=0;offset<100;offset+=2){ - switch (type) { - default: - case SalAudio: - tried_port=linphone_core_get_audio_port (lc)+offset; - break; - case SalVideo: - tried_port=linphone_core_get_video_port (lc)+offset; - break; - } + tried_port=base_port+offset; already_used=FALSE; for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; - switch (type) { - default: - case SalAudio: - existing_port = call->audio_port; - break; - case SalVideo: - existing_port = call->video_port; - break; - } + existing_port=call->media_ports[stream_index].rtp_port; if (existing_port==tried_port) { already_used=TRUE; break; @@ -356,37 +770,19 @@ static int find_port_offset(LinphoneCore *lc, SalStreamType type){ return offset; } -static int select_random_port(LinphoneCore *lc, SalStreamType type) { +static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) { MSList *elem; int nb_tries; int tried_port = 0; int existing_port = 0; - int min_port = 0, max_port = 0; bool_t already_used = FALSE; - switch (type) { - default: - case SalAudio: - linphone_core_get_audio_port_range(lc, &min_port, &max_port); - break; - case SalVideo: - linphone_core_get_video_port_range(lc, &min_port, &max_port); - break; - } - tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1; + tried_port = (ortp_random() % (max_port - min_port) + min_port) & ~0x1; if (tried_port < min_port) tried_port = min_port + 2; for (nb_tries = 0; nb_tries < 100; nb_tries++) { for (elem = lc->calls; elem != NULL; elem = elem->next) { LinphoneCall *call = (LinphoneCall *)elem->data; - switch (type) { - default: - case SalAudio: - existing_port = call->audio_port; - break; - case SalVideo: - existing_port = call->video_port; - break; - } + existing_port=call->media_ports[stream_index].rtp_port; if (existing_port == tried_port) { already_used = TRUE; break; @@ -401,38 +797,52 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) { return tried_port; } -static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ +static void port_config_set_random(LinphoneCall *call, int stream_index){ + call->media_ports[stream_index].rtp_port=-1; + call->media_ports[stream_index].rtcp_port=-1; +} + +static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){ int port_offset; + if (min_port>0 && max_port>0){ + if (min_port == max_port) { + /* Used fixed RTP audio port. */ + port_offset=find_port_offset(call->core, stream_index, min_port); + if (port_offset==-1) { + port_config_set_random(call, stream_index); + return; + } + call->media_ports[stream_index].rtp_port=min_port+port_offset; + } else { + /* Select random RTP audio port in the specified range. */ + call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port); + } + call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1; + }else port_config_set_random(call,stream_index); +} + +static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ int min_port, max_port; - call->magic=linphone_call_magic; - call->refcnt=1; + ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version()); call->state=LinphoneCallIdle; call->transfer_state = LinphoneCallIdle; - call->start_time=time(NULL); - 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); + call->log=linphone_call_log_new(call->dir, from, to); + call->camera_enabled=TRUE; + call->current_params = linphone_call_params_new(); + call->current_params->media_encryption=LinphoneMediaEncryptionNone; + call->dtls_certificate_fingerprint = NULL; + if (call->dir == LinphoneCallIncoming) + call->me=to; + else + call->me=from; + linphone_address_ref(call->me); + linphone_core_get_audio_port_range(call->core, &min_port, &max_port); - if (min_port == max_port) { - /* Used fixed RTP audio port. */ - port_offset=find_port_offset (call->core, SalAudio); - if (port_offset==-1) return; - call->audio_port=linphone_core_get_audio_port(call->core)+port_offset; - } else { - /* Select random RTP audio port in the specified range. */ - call->audio_port = select_random_port(call->core, SalAudio); - } + port_config_set(call,0,min_port,max_port); + linphone_core_get_video_port_range(call->core, &min_port, &max_port); - if (min_port == max_port) { - /* Used fixed RTP video port. */ - port_offset=find_port_offset (call->core, SalVideo); - if (port_offset==-1) return; - call->video_port=linphone_core_get_video_port(call->core)+port_offset; - } else { - /* Select random RTP video port in the specified range. */ - call->video_port = select_random_port(call->core, SalVideo); - } + port_config_set(call,1,min_port,max_port); + linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); } @@ -463,21 +873,122 @@ 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 */ +} + +/* + * Choose IP version we are going to use for RTP socket. + * The algorithm is as follows: + * - if ipv6 is disabled at the core level, it is always AF_INET + * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. + * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER + * to know if IPv6 is supported by the server. +**/ +static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){ + if (linphone_core_ipv6_enabled(call->core)){ + call->af=AF_INET; + if (sal_address_is_ipv6((SalAddress*)to)){ + call->af=AF_INET6; + }else if (cfg && cfg->op){ + call->af=sal_op_is_ipv6(cfg->op) ? AF_INET6 : AF_INET; + } + }else call->af=AF_INET; +} + +/** + * Fill the local ip that routes to the internet according to the destination, or guess it by other special means (upnp). + */ +static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr){ + const char *ip; + int af = call->af; + const char *dest = NULL; + if (call->dest_proxy == NULL) { + struct addrinfo hints; + struct addrinfo *res = NULL; + int err; + const char *domain = linphone_address_get_domain(remote_addr); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + err = getaddrinfo(domain, NULL, &hints, &res); + if (err == 0) { + dest = domain; + } + if (res != NULL) freeaddrinfo(res); + } + if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress + && (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){ + strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); + return; + } +#ifdef BUILD_UPNP + else if (call->core->upnp != NULL && linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseUpnp && + linphone_upnp_context_get_state(call->core->upnp) == LinphoneUpnpStateOk) { + ip = linphone_upnp_context_get_external_ipaddress(call->core->upnp); + strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); + return; + } +#endif //BUILD_UPNP + /*first nominal use case*/ + linphone_core_get_local_ip(call->core, af, dest, call->media_localip); + + /*next, sometime, override from config*/ + if ((ip=lp_config_get_string(call->core->config,"rtp","bind_address",NULL))) + strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE); + + return; +} + +static void linphone_call_destroy(LinphoneCall *obj); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_call_destroy, + NULL, // clone + NULL, // marshal + FALSE +); +void linphone_call_fill_media_multicast_addr(LinphoneCall *call) { + if (linphone_call_params_audio_multicast_enabled(call->params)){ + strncpy(call->media_ports[0].multicast_ip, + linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip)); + } else + call->media_ports[0].multicast_ip[0]='\0'; + + if (linphone_call_params_video_multicast_enabled(call->params)){ + strncpy(call->media_ports[1].multicast_ip, + linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip)); + } else + call->media_ports[1].multicast_ip[0]='\0'; +} + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ + LinphoneCall *call = belle_sip_object_new(LinphoneCall); + + call->dir=LinphoneCallOutgoing; call->core=lc; - linphone_core_get_local_ip(lc,linphone_address_get_domain(to),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; - + linphone_call_outgoing_select_ip_version(call,to,cfg); + linphone_call_get_local_ip(call, to); + linphone_call_init_common(call, from, to); + call->params = linphone_call_params_copy(params); + + linphone_call_fill_media_multicast_addr(call); + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); + /*for backward compatibility purposes, shall be enabled by default in futur*/ + ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0)); ice_session_set_role(call->ice_session, IR_Controlling); } if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { @@ -485,29 +996,65 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr } #ifdef BUILD_UPNP if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { - call->upnp_session = linphone_upnp_session_new(call); + if(!lc->rtp_conf.disable_upnp) { + call->upnp_session = linphone_upnp_session_new(call); + } } #endif //BUILD_UPNP - call->camera_active=params->has_video; - + 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; } +static void linphone_call_incoming_select_ip_version(LinphoneCall *call){ + if (linphone_core_ipv6_enabled(call->core)){ + call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET; + }else call->af=AF_INET; +} + +/** + * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally. + */ +void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) { + /* Handle AVPF, SRTP and DTLS. */ + call->params->avpf_enabled = sal_media_description_has_avpf(md); + if (call->params->avpf_enabled == TRUE) { + if (call->dest_proxy != NULL) { + call->params->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000; + } else { + call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000; + } + } + if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) { + call->params->media_encryption = LinphoneMediaEncryptionDTLS; + }else if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) { + call->params->media_encryption = LinphoneMediaEncryptionSRTP; + }else if (call->params->media_encryption != LinphoneMediaEncryptionZRTP){ + call->params->media_encryption = LinphoneMediaEncryptionNone; + } + +} + LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ - LinphoneCall *call=ms_new0(LinphoneCall,1); - char *from_str; - const SalMediaDescription *md; + LinphoneCall *call = belle_sip_object_new(LinphoneCall); + SalMediaDescription *md; + LinphoneFirewallPolicy fpol; + int i; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); call->op=op; call->core=lc; + linphone_call_incoming_select_ip_version(call); + + sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); + if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && @@ -518,40 +1065,67 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /*the following sends an option request back to the caller so that we get a chance to discover our nat'd address before answering.*/ call->ping_op=sal_op_new(lc->sal); - from_str=linphone_address_as_string_uri_only(from); + + linphone_configure_op(lc, call->ping_op, from, NULL, FALSE); + 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); - ms_free(from_str); + + sal_ping(call->ping_op,sal_op_get_from(call->ping_op), sal_op_get_to(call->ping_op)); } } linphone_address_clean(from); - linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); + linphone_call_get_local_ip(call, from); linphone_call_init_common(call, from, to); + call->params = linphone_call_params_new(); 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); + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to); + linphone_core_init_default_params(lc, call->params); + + /* + * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote + * end apparently does not support. This features are: privacy, video + */ + /*set privacy*/ + call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + /*set video support */ md=sal_call_get_remote_media_description(op); - call->params.has_video &= !!lc->video_policy.automatically_accept; + call->params->has_video = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept; if (md) { // It is licit to receive an INVITE without SDP // In this case WE chose the media parameters according to policy. - call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - } - switch (linphone_core_get_firewall_policy(call->core)) { - case LinphonePolicyUseIce: - call->ice_session = ice_session_new(); - ice_session_set_role(call->ice_session, IR_Controlled); - linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - if (call->ice_session != NULL) { - linphone_call_init_media_streams(call); - linphone_call_start_media_streams_for_ice_gathering(call); - if (linphone_core_gather_ice_candidates(call->core,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); + linphone_call_set_compatible_incoming_call_parameters(call, md); + /* set multicast role & address if any*/ + if (!sal_call_is_offerer(op)){ + for (i=0;inb_streams;i++){ + if (md->streams[i].rtp_addr[0]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)){ + md->streams[i].multicast_role = SalMulticastReceiver; + strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip)); } } + } + } + + fpol=linphone_core_get_firewall_policy(call->core); + /*create the ice session now if ICE is required*/ + if (fpol==LinphonePolicyUseIce){ + if (md){ + call->ice_session = ice_session_new(); + /*for backward compatibility purposes, shall be enabled by default in futur*/ + ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0)); + ice_session_set_role(call->ice_session, IR_Controlled); + }else{ + fpol=LinphonePolicyNoFirewall; + ms_warning("ICE not supported for incoming INVITE without SDP."); + } + } + + /*reserve the sockets immediately*/ + linphone_call_init_media_streams(call); + switch (fpol) { + case LinphonePolicyUseIce: + linphone_call_prepare_ice(call,TRUE); break; case LinphonePolicyUseStun: call->ping_time=linphone_core_run_stun_tests(call->core,call); @@ -559,12 +1133,13 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro break; case LinphonePolicyUseUpnp: #ifdef BUILD_UPNP - call->upnp_session = linphone_upnp_session_new(call); - if (call->upnp_session != NULL) { - linphone_call_init_media_streams(call); - if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) { - /* uPnP port mappings failed, proceed with the call anyway. */ - linphone_call_delete_upnp_session(call); + if(!lc->rtp_conf.disable_upnp) { + call->upnp_session = linphone_upnp_session_new(call); + if (call->upnp_session != NULL) { + if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } } } #endif //BUILD_UPNP @@ -572,13 +1147,55 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro default: break; } - call->camera_active=call->params.has_video; - + discover_mtu(lc,linphone_address_get_domain(from)); return call; } -/* this function is called internally to get rid of a call. +/* + * Frees the media resources of the call. + * This has to be done at the earliest, unlike signaling resources that sometimes need to be kept a bit more longer. + * It is called by linphone_call_set_terminated() (for termination of calls signaled to the application), or directly by the destructor of LinphoneCall + * (_linphone_call_destroy) if the call was never notified to the application. + */ +void linphone_call_free_media_resources(LinphoneCall *call){ + linphone_call_stop_media_streams(call); + ms_media_stream_sessions_uninit(&call->sessions[0]); + ms_media_stream_sessions_uninit(&call->sessions[1]); + linphone_call_delete_upnp_session(call); + linphone_call_delete_ice_session(call); + linphone_call_stats_uninit(&call->stats[0]); + linphone_call_stats_uninit(&call->stats[1]); +} + +/* + * Called internally when reaching the Released state, to perform cleanups to break circular references. +**/ +static void linphone_call_set_released(LinphoneCall *call){ + if (call->op!=NULL) { + /*transfer the last error so that it can be obtained even in Released state*/ + if (call->non_op_error.reason==SalReasonNone){ + const SalErrorInfo *ei=sal_op_get_error_info(call->op); + sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings); + } + /* so that we cannot have anymore upcalls for SAL + concerning this call*/ + 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); +} + +/* this function is called internally to get rid of a call that was notified to the application, because it reached the end or error state. It performs the following tasks: - remove the call from the internal list of calls - update the call logs accordingly @@ -587,12 +1204,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro static void linphone_call_set_terminated(LinphoneCall *call){ LinphoneCore *lc=call->core; - linphone_core_update_allocated_audio_bandwidth(lc); - - call->owns_call_log=FALSE; + linphone_call_free_media_resources(call); linphone_call_log_completed(call); - if (call == lc->current_call){ ms_message("Resetting the current call"); lc->current_call=NULL; @@ -601,24 +1215,19 @@ static void linphone_call_set_terminated(LinphoneCall *call){ if (linphone_core_del_call(lc,call) != 0){ ms_error("Could not remove the call from the list !!!"); } - - if (ms_list_size(lc->calls)==0) - linphone_core_notify_all_friends(lc,lc->presence_mode); - 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){ - call->params.has_video=call->current_params.has_video; - call->params.media_encryption=call->current_params.media_encryption; + if (sal_call_is_offerer(call->op)) { + /*get remote params*/ + const LinphoneCallParams* rcp = linphone_call_get_remote_params(call); + call->current_params->video_declined = call->params->has_video && !rcp->has_video; + } } const char *linphone_call_state_to_string(LinphoneCallState cs){ @@ -661,6 +1270,10 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){ return "LinphoneCallUpdating"; case LinphoneCallReleased: return "LinphoneCallReleased"; + case LinphoneCallEarlyUpdatedByRemote: + return "LinphoneCallEarlyUpdatedByRemote"; + case LinphoneCallEarlyUpdating: + return "LinphoneCallEarlyUpdating"; } return "undefined state"; } @@ -669,62 +1282,95 @@ 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), - linphone_call_state_to_string(cstate)); + ms_fatal("Spurious call state change from %s to %s, ignored." ,linphone_call_state_to_string(call->state) + ,linphone_call_state_to_string(cstate)); 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)); + ms_message("Call %p: moving from state %s to %s",call + ,linphone_call_state_to_string(call->state) + ,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)*/ call->state=cstate; } - if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ - switch(call->reason){ - case LinphoneReasonDeclined: - call->log->status=LinphoneCallDeclined; - break; - case LinphoneReasonNotAnswered: - call->log->status=LinphoneCallMissed; + + switch (cstate) { + case LinphoneCallOutgoingInit: + case LinphoneCallIncomingReceived: +#ifdef ANDROID + ms_message("Call [%p] acquires both wifi and multicast lock",call); + linphone_core_wifi_lock_acquire(call->core); + linphone_core_multicast_lock_acquire(call->core); /*does no affect battery more than regular rtp traffic*/ +#endif + break; + case LinphoneCallEnd: + case LinphoneCallError: + switch(call->non_op_error.reason){ + case SalReasonDeclined: + call->log->status=LinphoneCallDeclined; break; - default: + case SalReasonRequestTimeout: + call->log->status=LinphoneCallMissed; + break; + default: break; } - linphone_call_set_terminated (call); - } - if (cstate == LinphoneCallConnected) { + linphone_call_set_terminated(call); + break; + case LinphoneCallConnected: call->log->status=LinphoneCallSuccess; - call->media_start_time=time(NULL); + call->log->connected_date_time=time(NULL); + break; + case LinphoneCallReleased: +#ifdef ANDROID + ms_message("Call [%p] releases wifi/multicast lock",call); + linphone_core_wifi_lock_release(call->core); + linphone_core_multicast_lock_release(call->core); +#endif + break; + case LinphoneCallStreamsRunning: + if (call->prevstate == LinphoneCallUpdating || call->prevstate == LinphoneCallUpdatedByRemote) { + linphone_core_notify_display_status(lc,_("Call parameters were successfully modified.")); + } + break; + default: + break; } - if (lc->vtable.call_state_changed) - lc->vtable.call_state_changed(lc,call,cstate,message); - if (cstate==LinphoneCallReleased){ - if (call->op!=NULL) { - /* so that we cannot have anymore upcalls for SAL - concerning this call*/ - sal_op_release(call->op); - call->op=NULL; + if(cstate!=LinphoneCallStreamsRunning) { + if (call->dtmfs_timer!=NULL){ + /*cancelling DTMF sequence, if any*/ + linphone_call_cancel_dtmfs(call); } - linphone_call_unref(call); } + linphone_core_notify_call_state_changed(lc,call,cstate,message); + linphone_reporting_call_state_updated(call); + if (cstate==LinphoneCallReleased) {/*shall be performed after app notification*/ + linphone_call_set_released(call); + } + linphone_core_soundcard_hint_check(lc); } } -static void linphone_call_destroy(LinphoneCall *obj) -{ -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(obj); -#endif //BUILD_UPNP - linphone_call_delete_ice_session(obj); +static void linphone_call_destroy(LinphoneCall *obj){ + ms_message("Call [%p] freed.",obj); + if (obj->audiostream || obj->videostream){ + linphone_call_free_media_resources(obj); + } if (obj->op!=NULL) { sal_op_release(obj->op); obj->op=NULL; } + if (obj->biggestdesc!=NULL){ + sal_media_description_unref(obj->biggestdesc); + obj->biggestdesc=NULL; + } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; @@ -735,17 +1381,53 @@ static void linphone_call_destroy(LinphoneCall *obj) } if (obj->ping_op) { sal_op_release(obj->ping_op); + obj->ping_op=NULL; } if (obj->refer_to){ ms_free(obj->refer_to); + obj->refer_to=NULL; + } + if (obj->referer){ + linphone_call_unref(obj->referer); + obj->referer=NULL; + } + if (obj->transfer_target){ + linphone_call_unref(obj->transfer_target); + obj->transfer_target=NULL; + } + if (obj->log) { + linphone_call_log_unref(obj->log); + obj->log=NULL; } - if (obj->owns_call_log) - linphone_call_log_destroy(obj->log); if (obj->auth_token) { ms_free(obj->auth_token); + obj->auth_token=NULL; } - linphone_call_params_uninit(&obj->params); - ms_free(obj); + if (obj->dtls_certificate_fingerprint) { + ms_free(obj->dtls_certificate_fingerprint); + obj->dtls_certificate_fingerprint=NULL; + } + if (obj->dtmfs_timer) { + linphone_call_cancel_dtmfs(obj); + } + if (obj->params){ + linphone_call_params_unref(obj->params); + obj->params=NULL; + } + if (obj->current_params){ + linphone_call_params_unref(obj->current_params); + obj->current_params=NULL; + } + if (obj->remote_params != NULL) { + linphone_call_params_unref(obj->remote_params); + obj->remote_params=NULL; + } + if (obj->me) { + linphone_address_unref(obj->me); + obj->me = NULL; + } + + sal_error_info_reset(&obj->non_op_error); } /** @@ -753,75 +1435,139 @@ static void linphone_call_destroy(LinphoneCall *obj) * @{ **/ -/** - * Increments the call 's reference count. - * An application that wishes to retain a pointer to call object - * must use this function to unsure the pointer remains - * valid. Once the application no more needs this pointer, - * it must call linphone_call_unref(). -**/ LinphoneCall * linphone_call_ref(LinphoneCall *obj){ - obj->refcnt++; + belle_sip_object_ref(obj); return obj; } -/** - * Decrements the call object reference count. - * See linphone_call_ref(). -**/ void linphone_call_unref(LinphoneCall *obj){ - obj->refcnt--; - if (obj->refcnt==0){ - linphone_call_destroy(obj); - } + belle_sip_object_unref(obj); +} +static unsigned int linphone_call_get_n_active_streams(const LinphoneCall *call) { + SalMediaDescription *md=NULL; + if (call->op) + md = sal_call_get_remote_media_description(call->op); + if (!md) + return 0; + return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo); } /** * 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; - return &call->current_params; -} + SalMediaDescription *md=call->resultdesc; +#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); + call->current_params->sent_fps = video_stream_get_sent_framerate(vstream); + call->current_params->received_fps = video_stream_get_received_framerate(vstream); + } +#endif -static bool_t is_video_active(const SalStreamDescription *sd){ - return sd->rtp_port!=0 && sd->dir!=SalStreamInactive; + /* REVISITED + * Previous code was buggy. + * Relying on the mediastream's state (added by jehan: only) to know the current encryption is unreliable. + * For (added by jehan: both DTLS and) ZRTP it is though necessary. + * But for all others the current_params->media_encryption state should reflect (added by jehan: both) what is agreed by the offer/answer + * mechanism (added by jehan: and encryption status from media which is much stronger than only result of offer/answer ) + * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not. + */ + + switch (call->params->media_encryption) { + case LinphoneMediaEncryptionZRTP: + if (linphone_call_all_streams_encrypted(call) && linphone_call_get_authentication_token(call)) { + call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + } else { + call->current_params->media_encryption=LinphoneMediaEncryptionNone; + } + break; + case LinphoneMediaEncryptionDTLS: + case LinphoneMediaEncryptionSRTP: + if (linphone_call_get_n_active_streams(call)==0 || linphone_call_all_streams_encrypted(call)) { + call->current_params->media_encryption = call->params->media_encryption; + } else { + call->current_params->media_encryption=LinphoneMediaEncryptionNone; + } + break; + case LinphoneMediaEncryptionNone: + call->current_params->media_encryption=LinphoneMediaEncryptionNone; + break; + } + + call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call); + if (call->current_params->avpf_enabled == TRUE) { + call->current_params->avpf_rr_interval = linphone_call_get_avpf_rr_interval(call); + } else { + call->current_params->avpf_rr_interval = 0; + } + if (md){ + const char *rtp_addr; + + SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio); + call->current_params->audio_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive; + if (call->current_params->audio_dir != LinphoneMediaDirectionInactive) { + rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; + call->current_params->audio_multicast_enabled = ms_is_multicast(rtp_addr); + } else + call->current_params->audio_multicast_enabled = FALSE; + + sd=sal_media_description_find_best_stream(md,SalVideo); + call->current_params->video_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive; + if (call->current_params->video_dir != LinphoneMediaDirectionInactive) { + rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr; + call->current_params->video_multicast_enabled = ms_is_multicast(rtp_addr); + } else + call->current_params->video_multicast_enabled = FALSE; + } + + return call->current_params; } /** * Returns call parameters proposed by remote. - * + * * This is useful when receiving an incoming call, to know whether the remote party * supports video, encryption or whatever. **/ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ - LinphoneCallParams *cp=&call->remote_params; - memset(cp,0,sizeof(*cp)); if (call->op){ - SalMediaDescription *md=sal_call_get_remote_media_description(call->op); - if (md){ - SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd; + LinphoneCallParams *cp; + SalMediaDescription *md; + if (call->remote_params != NULL) linphone_call_params_unref(call->remote_params); + cp = call->remote_params = linphone_call_params_new(); + md=sal_call_get_remote_media_description(call->op); + if (md) { + SalStreamDescription *sd; + unsigned int i; + unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio); + unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo); - asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio); - vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo); - secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio); - secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo); - if (secure_vsd){ - cp->has_video=is_video_active(secure_vsd); - if (secure_asd || asd==NULL) - cp->media_encryption=LinphoneMediaEncryptionSRTP; - }else if (vsd){ - cp->has_video=is_video_active(vsd); + for (i = 0; i < nb_video_streams; i++) { + sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); + if (sal_stream_description_active(sd) == TRUE) cp->has_video = TRUE; + if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + } + for (i = 0; i < nb_audio_streams; i++) { + sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); + if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } if (!cp->has_video){ if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ cp->low_bandwidth=TRUE; } } - cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op); - return cp; + if (md->name[0]!='\0') linphone_call_params_set_session_name(cp,md->name); } + cp->custom_headers=sal_custom_header_clone((SalCustomHeader*)sal_op_get_recv_custom_header(call->op)); + return cp; } return NULL; } @@ -854,31 +1600,39 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ * Returns the reason for a call termination (either error or normal termination) **/ LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ - return call->reason; + return linphone_error_info_get_reason(linphone_call_get_error_info(call)); } /** - * Get the user_pointer in the LinphoneCall - * - * @ingroup call_control - * - * return user_pointer an opaque user pointer that can be retrieved at any time + * Returns full details about call errors or termination reasons. **/ -void *linphone_call_get_user_pointer(LinphoneCall *call) -{ - return call->user_pointer; +const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){ + if (call->non_op_error.reason!=SalReasonNone){ + return (const LinphoneErrorInfo*)&call->non_op_error; + }else return linphone_error_info_from_sal_op(call->op); } /** - * Set the user_pointer in the LinphoneCall + * Get the user pointer associated with the LinphoneCall + * + * @ingroup call_control + * @return an opaque user pointer that can be retrieved at any time +**/ +void *linphone_call_get_user_data(const LinphoneCall *call) +{ + return call->user_data; +} + +/** + * Set the user pointer associated with the LinphoneCall * * @ingroup call_control * - * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall + * the user pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall **/ -void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer) +void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer) { - call->user_pointer = user_pointer; + call->user_data = user_pointer; } /** @@ -895,6 +1649,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). **/ @@ -916,12 +1685,17 @@ const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ * Returns the far end's sip contact as a string, if available. **/ const char *linphone_call_get_remote_contact(LinphoneCall *call){ - if (call->op){ - return sal_op_get_remote_contact(call->op); + const LinphoneCallParams* lcp = linphone_call_get_remote_params(call); + if( lcp ){ + // we're not using sal_op_get_remote_contact() here because the returned value is stripped from + // params that we need, like the instanceid. Getting it from the headers will make sure we + // get everything + return linphone_call_params_get_custom_header(lcp, "Contact"); } return NULL; } + /** * Returns true if this calls has received a transfer that has not been * executed yet. @@ -938,8 +1712,8 @@ bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){ * Returns call's duration in seconds. **/ int linphone_call_get_duration(const LinphoneCall *call){ - if (call->media_start_time==0) return 0; - return time(NULL)-call->media_start_time; + if (call->log->connected_date_time==0) return 0; + return time(NULL)-call->log->connected_date_time; } /** @@ -961,32 +1735,45 @@ LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){ **/ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ #ifdef VIDEO_ENABLED - if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){ - LinphoneCore *lc=call->core; - MSWebCam *nowebcam=get_nowebcam_device(); - if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){ - video_stream_change_camera(call->videostream, - enable ? lc->video_conf.device : nowebcam); + call->camera_enabled=enable; + if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) + && call->videostream!=NULL && video_stream_started(call->videostream) ){ + if (video_stream_get_camera(call->videostream) != linphone_call_get_video_device(call)) { + const char *cur_cam, *new_cam; + cur_cam = video_stream_get_camera(call->videostream) ? ms_web_cam_get_name(video_stream_get_camera(call->videostream)) : "NULL"; + new_cam = linphone_call_get_video_device(call) ? ms_web_cam_get_name(linphone_call_get_video_device(call)) : "NULL"; + ms_message("Switching video cam from [%s] to [%s] on call [%p]" , cur_cam, new_cam, call); + video_stream_change_camera(call->videostream, linphone_call_get_video_device(call)); } } - call->camera_active=enable; #endif } -#ifdef VIDEO_ENABLED /** * Request remote side to send us a Video Fast Update. **/ -void linphone_call_send_vfu_request(LinphoneCall *call) -{ - if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) - sal_call_send_vfu_request(call->op); -} +void linphone_call_send_vfu_request(LinphoneCall *call) { +#ifdef VIDEO_ENABLED + const LinphoneCallParams *current_params = linphone_call_get_current_params(call); + if (current_params->avpf_enabled && call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { + ms_message("Request Full Intra Request on call [%p]", call); + video_stream_send_fir(call->videostream); + } else if (call->core->sip_conf.vfu_with_info) { + if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) + sal_call_send_vfu_request(call->op); + } else { + ms_message("vfu request using sip disabled from config [sip,vfu_with_info]"); + } #endif +} /** * Take a photo of currently received video and write it into a jpeg file. + * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. + * @param call a LinphoneCall + * @param file a path where to write the jpeg content. + * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). **/ int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){ #ifdef VIDEO_ENABLED @@ -994,153 +1781,51 @@ int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){ return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file); } ms_warning("Cannot take snapshot: no currently running video stream on this call."); +#endif + return -1; +} + +/** + * Take a photo of currently captured video and write it into a jpeg file. + * Note that the snapshot is asynchronous, an application shall not assume that the file is created when the function returns. + * @param call a LinphoneCall + * @param file a path where to write the jpeg content. + * @return 0 if successfull, -1 otherwise (typically if jpeg format is not supported). +**/ +int linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file){ +#ifdef VIDEO_ENABLED + if (call->videostream!=NULL && call->videostream->local_jpegwriter!=NULL){ + return ms_filter_call_method(call->videostream->local_jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file); + } + ms_warning("Cannot take local snapshot: no currently running video stream on this call."); return -1; #endif return -1; } /** - * Returns TRUE if camera pictures are sent to the remote party. + * Returns TRUE if camera pictures are allowed to be sent to the remote party. **/ bool_t linphone_call_camera_enabled (const LinphoneCall *call){ - return call->camera_active; + return call->camera_enabled; } -/** - * Enable video stream. -**/ -void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){ - cp->has_video=enabled; -} - -/** - * Returns the audio codec used in the call, described as a PayloadType structure. -**/ -const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) { - return cp->audio_codec; -} - - -/** - * Returns the video codec used in the call, described as a PayloadType structure. -**/ -const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) { - return cp->video_codec; -} /** * @ingroup call_control - * Use to know if this call has been configured in low bandwidth mode. - * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file. - * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure - * low bandwidth mode with linphone_call_params_enable_low_bandwidth(). - *
    When enabled, this param may transform a call request with video in audio only mode. - * @return TRUE if low bandwidth has been configured/detected - */ -bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) { - return cp->low_bandwidth; -} - -/** - * @ingroup call_control - * Indicate low bandwith mode. - * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage - * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided - * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled. - * -**/ -void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){ - cp->low_bandwidth=enabled; -} - -/** - * Returns whether video is enabled. -**/ -bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ - return cp->has_video; -} - -/** - * Returns kind of media encryption selected for the call. -**/ -enum 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) { - cp->media_encryption = e; -} - - -/** - * Enable sending of real early media (during outgoing calls). -**/ -void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){ - cp->real_early_media=enabled; -} - -/** - * Indicates whether sending of early media was enabled. -**/ -bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){ - return cp->real_early_media; -} - -/** - * Returns true if the call is part of the locally managed conference. -**/ -bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){ - return cp->in_conference; -} - -/** - * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams. - * As a consequence, codecs whose bitrates are not compatible with this limit won't be used. -**/ -void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){ - cp->audio_bw=bandwidth; -} - -void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){ - params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value); -} - -const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){ - return sal_custom_header_find(params->custom_headers,header_name); -} - -void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){ - memcpy(ncp,cp,sizeof(LinphoneCallParams)); - if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file); - /* - * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. - */ - if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); -} - -/** - * Copy existing LinphoneCallParams to a new LinphoneCallParams object. -**/ -LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){ - LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1); - _linphone_call_params_copy(ncp,cp); - return ncp; -} - -void linphone_call_params_uninit(LinphoneCallParams *p){ - if (p->record_file) ms_free(p->record_file); - if (p->custom_headers) sal_custom_header_free(p->custom_headers); -} - -/** - * Destroy LinphoneCallParams. -**/ -void linphone_call_params_destroy(LinphoneCallParams *p){ - linphone_call_params_uninit(p); - ms_free(p); + * @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"; + } } @@ -1152,23 +1837,36 @@ void linphone_call_params_destroy(LinphoneCallParams *p){ #ifdef TEST_EXT_RENDERER static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){ ms_message("rendercb, local buffer=%p, remote buffer=%p", - local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); + local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); } #endif #ifdef VIDEO_ENABLED static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){ - LinphoneCall* call = (LinphoneCall*) user_pointer; - ms_warning("In linphonecall.c: video_stream_event_cb"); + LinphoneCall* call = (LinphoneCall*) user_pointer; switch (event_id) { case MS_VIDEO_DECODER_DECODING_ERRORS: - ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS"); - linphone_call_send_vfu_request(call); + ms_warning("MS_VIDEO_DECODER_DECODING_ERRORS"); + if (call->videostream && (video_stream_is_decoding_error_to_be_reported(call->videostream, 5000) == TRUE)) { + video_stream_decoding_error_reported(call->videostream); + linphone_call_send_vfu_request(call); + } + break; + case MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS: + ms_message("MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS"); + if (call->videostream) { + video_stream_decoding_error_recovered(call->videostream); + } break; case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED: ms_message("First video frame decoded successfully"); if (call->nextVideoFrameDecoded._func != NULL) - call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); + call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); + break; + case MS_VIDEO_DECODER_SEND_PLI: + case MS_VIDEO_DECODER_SEND_SLI: + case MS_VIDEO_DECODER_SEND_RPSI: + /* Handled internally by mediastreamer2. */ break; default: ms_warning("Unhandled event %i", event_id); @@ -1181,17 +1879,169 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin call->nextVideoFrameDecoded._func = cb; call->nextVideoFrameDecoded._user_data = user_data; #ifdef VIDEO_ENABLED - ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); + if (call->videostream && call->videostream->ms.decoder) + ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); #endif } +static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){ + call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session); + call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session); +} + +static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){ + MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + IceCheckList *cl; + rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE); + cl=ice_session_check_list(call->ice_session, stream_index); + if (cl == NULL && create_checklist) { + cl=ice_check_list_new(); + ice_session_add_check_list(call->ice_session, cl, stream_index); + ms_message("Created new ICE check list for stream [%i]",stream_index); + } + if (cl){ + ms->ice_check_list = cl; + ice_check_list_set_rtp_session(ms->ice_check_list, ms->sessions.rtp_session); + } + } +} + +int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ + SalMediaDescription *remote = NULL; + bool_t has_video=FALSE; + + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + if (incoming_offer){ + remote=sal_call_get_remote_media_description(call->op); + has_video=linphone_core_video_enabled(call->core) && linphone_core_media_description_contains_video_stream(remote); + }else has_video=call->params->has_video; + + _linphone_call_prepare_ice_for_stream(call,0,TRUE); + if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE); + /*start ICE gathering*/ + if (incoming_offer) + linphone_call_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/ + if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){ + if (call->audiostream->ms.state==MSStreamInitialized) + audio_stream_prepare_sound(call->audiostream, NULL, NULL); +#ifdef VIDEO_ENABLED + if (has_video && call->videostream && call->videostream->ms.state==MSStreamInitialized) { + video_stream_prepare_video(call->videostream); + } +#endif + if (linphone_core_gather_ice_candidates(call->core,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + linphone_call_stop_media_streams_for_ice_gathering(call); + return -1; + } + return 1;/*gathering in progress, wait*/ + } + } + return 0; +} + +/*eventually join to a multicast group if told to do so*/ +static void linphone_call_join_multicast_group(LinphoneCall *call, int stream_index, MediaStream *ms){ + if (call->media_ports[stream_index].multicast_ip[stream_index]!='\0'){ + media_stream_join_multicast_group(ms, call->media_ports[stream_index].multicast_ip); + } else + ms_error("Cannot join multicast group if multicast ip is not set for call [%p]",call); +} + +static SalMulticastRole linphone_call_get_multicast_role(const LinphoneCall *call,SalStreamType type) { + SalMulticastRole multicast_role=SalMulticastInactive; + SalMediaDescription *remotedesc, *localdesc; + SalStreamDescription *stream_desc = NULL; + if (!call->op) goto end; + remotedesc = sal_call_get_remote_media_description(call->op); + localdesc = call->localdesc; + if (!localdesc && !remotedesc && call->dir == LinphoneCallOutgoing) { + /*well using call dir*/ + if ((type == SalAudio && linphone_call_params_audio_multicast_enabled(call->params)) + || (type == SalVideo && linphone_call_params_video_multicast_enabled(call->params))) + multicast_role=SalMulticastSender; + } else if (localdesc && (!remotedesc || sal_call_is_offerer(call->op))) { + stream_desc = sal_media_description_find_best_stream(localdesc, type); + } else if (!sal_call_is_offerer(call->op) && remotedesc) + stream_desc = sal_media_description_find_best_stream(remotedesc, type); + + if (stream_desc) + multicast_role=stream_desc->multicast_role; + else + ms_message("Cannot determine multicast role for stream type [%s] on call [%p]",sal_stream_type_to_string(type),call); + + + end: + return multicast_role; + +} + +static void setup_dtls_params(LinphoneCall *call, MediaStream* stream) { + LinphoneCore *lc=call->core; + if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + MSDtlsSrtpParams params; + char *certificate, *key; + memset(¶ms,0,sizeof(MSDtlsSrtpParams)); + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ + /* This will parse the directory to find a matching fingerprint or generate it if not found */ + /* returned string must be freed */ + sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); + + if (key!= NULL && certificate!=NULL) { + params.pem_certificate = (char *)certificate; + params.pem_pkey = (char *)key; + params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ + media_stream_enable_dtls(stream,¶ms); + ms_free(certificate); + ms_free(key); + } else { + ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); + /* TODO : check if encryption forced, if yes, stop call */ + } + } +} + void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; AudioStream *audiostream; + const char *location; int dscp; + char rtcp_tool[128]={0}; + char* cname; + + + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->audiostream != NULL) return; - call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc)); + if (call->sessions[0].rtp_session==NULL){ + SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio); + SalMediaDescription *remotedesc=NULL; + SalStreamDescription *stream_desc = NULL; + if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); + if (remotedesc) + stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio); + + call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,0), + multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[0].rtp_port, + multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[0].rtcp_port); + if (multicast_role == SalMulticastReceiver) + linphone_call_join_multicast_group(call, 0, &audiostream->ms); + rtp_session_enable_network_simulation(call->audiostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); + cname = linphone_address_as_string_uri_only(call->me); + audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); + ms_free(cname); + rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); + setup_dtls_params(call, &audiostream->ms); + media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[0]); + }else{ + call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); + } + audiostream=call->audiostream; + if (call->media_ports[0].rtp_port==-1){ + port_config_set_random_choosed(call,0,audiostream->ms.sessions.rtp_session); + } dscp=linphone_core_get_audio_dscp(lc); if (dscp!=-1) audio_stream_set_dscp(audiostream,dscp); @@ -1202,16 +2052,27 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ else if (strcasecmp(type,"full")==0) audio_stream_enable_echo_limiter(audiostream,ELControlFull); } + + /* equalizer location in the graph: 'mic' = in input graph, otherwise in output graph. + Any other value than mic will default to output graph for compatibility */ + location = lp_config_get_string(lc->config,"sound","eq_location","hp"); + audiostream->eq_loc = (strcasecmp(location,"mic") == 0) ? MSEqualizerMic : MSEqualizerHP; + ms_message("Equalizer location: %s", location); + audio_stream_enable_gain_control(audiostream,TRUE); if (linphone_core_echo_cancellation_enabled(lc)){ int len,delay,framesize; - const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL); len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); delay=lp_config_get_int(lc->config,"sound","ec_delay",0); framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0); audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize); - if (statestr && audiostream->ec){ - ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr); + if (audiostream->ec) { + char *statestr=ms_malloc0(EC_STATE_MAX_LEN); + if (lp_config_relative_file_exists(lc->config, EC_STATE_STORE) + && lp_config_read_relative_file(lc->config, EC_STATE_STORE, statestr, EC_STATE_MAX_LEN) == 0) { + ms_filter_call_method(audiostream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr); + } + ms_free(statestr); } } audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc)); @@ -1223,62 +2084,89 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc)); if (lc->rtptf){ - RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port); - RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1); - rtp_session_set_transports(audiostream->ms.session,artp,artcp); - } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(audiostream->ms.session, TRUE); - rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE); - if (ice_session_check_list(call->ice_session, 0) == NULL) { - ice_session_add_check_list(call->ice_session, ice_check_list_new()); + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); + if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port)); + } + if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port)); } - audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0); - ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session); } call->audiostream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq); + rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); + + _linphone_call_prepare_ice_for_stream(call,0,FALSE); } void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; + char* cname; + char rtcp_tool[128]; - if (!call->params.has_video) { - linphone_call_stop_video_stream(call); - return; - } - if (call->videostream != NULL) return; - if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){ + + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); + + if (call->videostream == NULL){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); int dscp=linphone_core_get_video_dscp(lc); - - call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc)); + const char *display_filter=linphone_core_get_video_display_filter(lc); + + if (call->sessions[1].rtp_session==NULL){ + SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalVideo); + SalMediaDescription *remotedesc=NULL; + SalStreamDescription *stream_desc = NULL; + if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); + if (remotedesc) + stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo); + + call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,1), + multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[1].rtp_port, + multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[1].rtcp_port); + if (multicast_role == SalMulticastReceiver) + linphone_call_join_multicast_group(call, 1, &call->videostream->ms); + rtp_session_enable_network_simulation(call->videostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); + cname = linphone_address_as_string_uri_only(call->me); + video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); + ms_free(cname); + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); + setup_dtls_params(call, &call->videostream->ms); + media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[1]); + }else{ + call->videostream=video_stream_new_with_sessions(&call->sessions[1]); + } + + if (call->media_ports[1].rtp_port==-1){ + port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session); + } if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); 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 (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_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); - RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); - rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp); - } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(call->videostream->ms.session, TRUE); - rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE); - if (ice_session_check_list(call->ice_session, 1) == NULL) { - ice_session_add_check_list(call->ice_session, ice_check_list_new()); + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); + if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port)); + } + if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port)); } - 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); } call->videostream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq); + rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); + _linphone_call_prepare_ice_for_stream(call,1,FALSE); #ifdef TEST_EXT_RENDERER video_stream_set_render_callback(call->videostream,rendercb,NULL); #endif @@ -1296,13 +2184,12 @@ void linphone_call_init_media_streams(LinphoneCall *call){ static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; -static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){ +static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){ if (dtmf<0 || dtmf>15){ ms_warning("Bad dtmf value %i",dtmf); return; } - if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]); + linphone_core_notify_dtmf_received(call->core, call, dtmf_tab[dtmf]); } static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ @@ -1327,6 +2214,17 @@ static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ } } +void set_mic_gain_db(AudioStream *st, float gain){ + audio_stream_set_mic_gain_db(st, gain); +} + +void set_playback_gain_db(AudioStream *st, float gain){ + if (st->volrecv){ + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply playback gain: gain control wasn't activated."); +} + +/*This function is not static because used internally in linphone-daemon project*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ float mic_gain=lc->sound_conf.soft_mic_lev; float thres = 0; @@ -1343,15 +2241,15 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute int spk_agc; if (!muted) - linphone_core_set_mic_gain_db (lc, mic_gain); + set_mic_gain_db(st,mic_gain); else audio_stream_set_mic_gain(st,0); recv_gain = lc->sound_conf.soft_play_lev; if (recv_gain != 0) { - linphone_core_set_playback_gain_db (lc,recv_gain); + set_playback_gain_db(st,recv_gain); } - + if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); speed=lp_config_get_float(lc->config,"sound","el_speed",-1); @@ -1385,35 +2283,92 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute parametrize_equalizer(lc,st); } -static void post_configure_audio_streams(LinphoneCall*call){ +static void post_configure_audio_streams(LinphoneCall *call, bool_t muted){ AudioStream *st=call->audiostream; LinphoneCore *lc=call->core; - _post_configure_audio_stream(st,lc,call->audio_muted); - if (lc->vtable.dtmf_received!=NULL){ + _post_configure_audio_stream(st,lc,muted); + if (linphone_core_dtmf_received_has_listener(lc)){ audio_stream_play_received_dtmfs(call->audiostream,FALSE); } - if (call->record_active) + if (call->record_active) linphone_call_start_recording(call); } -static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ +static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ + int remote_bw=0; + int upload_bw; + int total_upload_bw=linphone_core_get_upload_bandwidth(call->core); + const LinphoneCallParams *params=call->params; + bool_t will_use_video=linphone_core_media_description_contains_video_stream(md); + bool_t forced=FALSE; + + if (desc->bandwidth>0) remote_bw=desc->bandwidth; + else if (md->bandwidth>0) { + /*case where b=AS is given globally, not per stream*/ + remote_bw=md->bandwidth; + } + if (params->up_bw>0){ + forced=TRUE; + upload_bw=params->up_bw; + }else upload_bw=total_upload_bw; + upload_bw=get_min_bandwidth(upload_bw,remote_bw); + if (!will_use_video || forced) return upload_bw; + + if (bandwidth_is_greater(upload_bw,512)){ + upload_bw=100; + }else if (bandwidth_is_greater(upload_bw,256)){ + upload_bw=64; + }else if (bandwidth_is_greater(upload_bw,128)){ + upload_bw=40; + }else if (bandwidth_is_greater(upload_bw,0)){ + upload_bw=24; + } + return upload_bw; +} + +static int get_video_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ + int remote_bw=0; int bw; + if (desc->bandwidth>0) remote_bw=desc->bandwidth; + else if (md->bandwidth>0) { + /*case where b=AS is given globally, not per stream*/ + remote_bw=get_remaining_bandwidth_for_video(md->bandwidth,call->audio_bw); + } else { + remote_bw = lp_config_get_int(call->core->config, "net", "default_max_bandwidth", 1500); + } + bw=get_min_bandwidth(get_remaining_bandwidth_for_video(linphone_core_get_upload_bandwidth(call->core),call->audio_bw),remote_bw); + return bw; +} + +static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ + int bw=0; const MSList *elem; RtpProfile *prof=rtp_profile_new("Call profile"); bool_t first=TRUE; - int remote_bw=0; LinphoneCore *lc=call->core; int up_ptime=0; - const LinphoneCallParams *params=&call->params; + const LinphoneCallParams *params=call->params; + *used_pt=-1; + if (desc->type==SalAudio) + bw=get_ideal_audio_bw(call,md,desc); + else if (desc->type==SalVideo) + bw=get_video_bw(call,md,desc); + 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) { + /*first codec in list is the selected one*/ if (desc->type==SalAudio){ - linphone_core_update_allocated_audio_bandwidth_in_call(call,pt); + /*this will update call->audio_bw*/ + linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw); + bw=call->audio_bw; if (params->up_ptime) up_ptime=params->up_ptime; else up_ptime=linphone_core_get_upload_ptime(lc); @@ -1421,27 +2376,10 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m *used_pt=payload_type_get_number(pt); first=FALSE; } - if (desc->bandwidth>0) remote_bw=desc->bandwidth; - else if (md->bandwidth>0) { - /*case where b=AS is given globally, not per stream*/ - remote_bw=md->bandwidth; - if (desc->type==SalVideo){ - remote_bw=get_video_bandwidth(remote_bw,call->audio_bw); - } - } - - if (desc->type==SalAudio){ - int audio_bw=call->audio_bw; - if (params->up_bw){ - if (params->up_bw< audio_bw) - audio_bw=params->up_bw; - } - bw=get_min_bandwidth(audio_bw,remote_bw); - }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw); - if (bw>0) pt->normal_bitrate=bw*1000; - else if (desc->type==SalAudio){ - pt->normal_bitrate=-1; - } + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ + ms_message("Payload type [%s/%i] has explicit bitrate [%i] kbit/s", pt->mime_type, pt->clock_rate, pt->normal_bitrate/1000); + pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000); + } else pt->normal_bitrate=bw*1000; if (desc->ptime>0){ up_ptime=desc->ptime; } @@ -1469,19 +2407,172 @@ static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ LinphoneCore *lc=call->core; LinphoneCall *current=linphone_core_get_current_call(lc); - return !linphone_core_is_in_conference(lc) && + 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; itype == SalAudio) { + session = call->audiostream->ms.sessions.rtp_session; + } else if (stream->type == SalVideo) { + session = call->videostream->ms.sessions.rtp_session; + } else { + // Do nothing for streams that are not audio or video + return; + } + if (stream->rtcp_fb.generic_nack_enabled) + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, TRUE); + else + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, FALSE); + if (stream->rtcp_fb.tmmbr_enabled) + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, TRUE); + else + rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, FALSE); +} + +static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) { + RtpSession *session; + const OrtpRtcpXrConfiguration *localconfig; + const OrtpRtcpXrConfiguration *remoteconfig; + OrtpRtcpXrConfiguration currentconfig; + const SalStreamDescription *localstream; + const SalStreamDescription *remotestream; + SalMediaDescription *remotedesc = sal_call_get_remote_media_description(call->op); + + if (!remotedesc) return; + + localstream = sal_media_description_find_best_stream(call->localdesc, type); + if (!localstream) return; + localconfig = &localstream->rtcp_xr; + remotestream = sal_media_description_find_best_stream(remotedesc, type); + if (!remotestream) return; + remoteconfig = &remotestream->rtcp_xr; + + if (localstream->dir == SalStreamInactive) return; + else if (localstream->dir == SalStreamRecvOnly) { + /* Use local config for unilateral parameters and remote config for collaborative parameters. */ + memcpy(¤tconfig, localconfig, sizeof(currentconfig)); + currentconfig.rcvr_rtt_mode = remoteconfig->rcvr_rtt_mode; + currentconfig.rcvr_rtt_max_size = remoteconfig->rcvr_rtt_max_size; + } else { + memcpy(¤tconfig, remoteconfig, sizeof(currentconfig)); + } + if (type == SalAudio) { + session = call->audiostream->ms.sessions.rtp_session; + } else { + session = call->videostream->ms.sessions.rtp_session; + } + rtp_session_configure_rtcp_xr(session, ¤tconfig); +} +void static start_dtls( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) { + if (sal_stream_description_has_dtls(sd) == TRUE) { + /*DTLS*/ + SalDtlsRole salRole = sd->dtls_role; + if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ + /* give the peer certificate fingerprint to dtls context */ + ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); + ms_dtls_srtp_set_role(sessions->dtls_context, (salRole == SalDtlsRoleIsClient)?MSDtlsSrtpRoleIsClient:MSDtlsSrtpRoleIsServer); /* set the role to client */ + ms_dtls_srtp_start(sessions->dtls_context); /* then start the engine, it will send the DTLS client Hello */ + } else { + ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions); + } + } +} +void static start_dtls_on_all_streams(LinphoneCall *call) { + SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); + SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op); + if( remote_desc == NULL || result_desc == NULL ){ + /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ + return; + } + + if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/ + start_dtls(&call->audiostream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalAudio) + ,sal_media_description_find_best_stream(remote_desc,SalAudio)); +#if VIDEO_ENABLED + if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/ + start_dtls(&call->videostream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalVideo) + ,sal_media_description_find_best_stream(remote_desc,SalVideo)); +#endif + return; +} + +void static set_dtls_fingerprint( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) { + if (sal_stream_description_has_dtls(sd) == TRUE) { + /*DTLS*/ + SalDtlsRole salRole = sd->dtls_role; + if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ + /* give the peer certificate fingerprint to dtls context */ + ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint); + } else { + ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions); + } + } +} + +void static set_dtls_fingerprint_on_all_streams(LinphoneCall *call) { + SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); + SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op); + + if( remote_desc == NULL || result_desc == NULL ){ + /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */ + return; + } + + if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/ + set_dtls_fingerprint(&call->audiostream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalAudio) + ,sal_media_description_find_best_stream(remote_desc,SalAudio)); +#if VIDEO_ENABLED + if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/ + set_dtls_fingerprint(&call->videostream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalVideo) + ,sal_media_description_find_best_stream(remote_desc,SalVideo)); +#endif + return; +} + +static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) { + PayloadType *pt; + LinphoneCore *lc = call->core; + const char *local_ip = lp_config_get_string(lc->config, "sound", "rtp_local_addr", "127.0.0.1"); + const char *remote_ip = lp_config_get_string(lc->config, "sound", "rtp_remote_addr", "127.0.0.1"); + int local_port = lp_config_get_int(lc->config, "sound", "rtp_local_port", 17076); + int remote_port = lp_config_get_int(lc->config, "sound", "rtp_remote_port", 17078); + int ptnum = lp_config_get_int(lc->config, "sound", "rtp_ptnum", 0); + const char *rtpmap = lp_config_get_string(lc->config, "sound", "rtp_map", "pcmu/8000/1"); + int symmetric = lp_config_get_int(lc->config, "sound", "rtp_symmetric", 0); + RtpSession *rtp_session = NULL; + pt = rtp_profile_get_payload_from_rtpmap(call->audio_profile, rtpmap); + if (pt != NULL) { + call->rtp_io_audio_profile = rtp_profile_new("RTP IO audio profile"); + rtp_profile_set_payload(call->rtp_io_audio_profile, ptnum, payload_type_clone(pt)); + rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1); + rtp_session_set_profile(rtp_session, call->rtp_io_audio_profile); + rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1); + rtp_session_enable_rtcp(rtp_session, FALSE); + rtp_session_set_payload_type(rtp_session, ptnum); + rtp_session_set_jitter_compensation(rtp_session, linphone_core_get_audio_jittcomp(lc)); + rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric); + } + return rtp_session; +} + +static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t use_arc){ LinphoneCore *lc=call->core; int used_pt=-1; char rtcp_tool[128]={0}; @@ -1494,17 +2585,15 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna const char *recfile; const SalStreamDescription *local_st_desc; int crypto_idx; + MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; + bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); 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 */ - stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpSavp,SalAudio); - /* no savp audio stream, use avp */ - if (!stream) - stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalAudio); + stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ + const char *rtp_addr=stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr; + bool_t is_multicast=ms_is_multicast(rtp_addr); playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; captcard=lc->sound_conf.capt_sndcard; @@ -1513,35 +2602,42 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); if (used_pt!=-1){ - call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); + bool_t ok = TRUE; + call->current_params->audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); if (playcard==NULL) { ms_warning("No card defined for playback !"); } if (captcard==NULL) { ms_warning("No card defined for capture !"); } - /*Replace soundcard filters by inactive file players or recorders - when placed in recvonly or sendonly mode*/ - if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){ + /*Don't use file or soundcard capture when placed in recv-only mode*/ + if (stream->rtp_port==0 + || stream->dir==SalStreamRecvOnly + || (stream->multicast_role == SalMulticastReceiver && is_multicast)){ captcard=NULL; playfile=NULL; - }else if (stream->dir==SalStreamSendOnly){ + } + if (next_state == LinphoneCallPaused){ + /*in paused state, we never use soundcard*/ playcard=NULL; captcard=NULL; recfile=NULL; /*And we will eventually play "playfile" if set by the user*/ - /*playfile=NULL;*/ } - if (send_ringbacktone){ + if (call->playing_ringbacktone){ captcard=NULL; playfile=NULL;/* it is setup later*/ + if (lp_config_get_int(lc->config,"sound","send_ringback_without_playback", 0) == 1){ + playcard = NULL; + recfile = NULL; + } } /*if playfile are supplied don't use soundcards*/ - if (lc->use_files) { + if (lc->use_files || use_rtp_io) { captcard=NULL; playcard=NULL; } - if (call->params.in_conference){ + if (call->params->in_conference){ /* first create the graph without soundcard resources*/ captcard=playcard=NULL; } @@ -1550,295 +2646,437 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna captcard=playcard=NULL; } use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc); + audio_stream_enable_echo_canceller(call->audiostream, use_ec); if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate); 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); + media_stream_set_adaptive_bitrate_algorithm(&call->audiostream->ms, + ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc))); audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc)); - if (!call->params.in_conference && call->params.record_file) - audio_stream_mixed_record_open(call->audiostream,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, - used_pt, - linphone_core_get_audio_jittcomp(lc), - playfile, - recfile, - playcard, - captcard, - use_ec - ); - post_configure_audio_streams(call); - if (muted && !send_ringbacktone){ - audio_stream_set_mic_gain(call->audiostream,0); + rtp_session_set_jitter_compensation(call->audiostream->ms.sessions.rtp_session,linphone_core_get_audio_jittcomp(lc)); + 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); } - if (stream->dir==SalStreamSendOnly && playfile!=NULL){ + /* valid local tags are > 0 */ + if (sal_stream_description_has_srtp(stream) == TRUE) { + local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + + if (crypto_idx >= 0) { + ms_media_stream_sessions_set_srtp_recv_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,stream->crypto[0].master_key); + ms_media_stream_sessions_set_srtp_send_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + } else { + ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); + } + } + configure_rtp_session_for_rtcp_fb(call, stream); + configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); + if (is_multicast) + rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl); + + if (use_rtp_io) { + io.input.type = io.output.type = MSResourceRtp; + io.input.session = io.output.session = create_audio_rtp_io_session(call); + if (io.input.session == NULL) { + ok = FALSE; + } + }else { + if (playcard){ + io.output.type = MSResourceSoundcard; + io.output.soundcard = playcard; + }else{ + io.output.type = MSResourceFile; + io.output.file = recfile; + } + if (captcard){ + io.input.type = MSResourceSoundcard; + io.input.soundcard = captcard; + }else{ + io.input.type = MSResourceFile; + io.input.file = playfile; + } + + } + if (ok == TRUE) { + audio_stream_start_from_io(call->audiostream, + call->audio_profile, + rtp_addr, + stream->rtp_port, + stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr, + (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0, + used_pt, + &io + ); + post_configure_audio_streams(call, (call->all_muted || call->audio_muted) && !call->playing_ringbacktone); + } + + ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core)); + + if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){ int pause_time=500; ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); } - if (send_ringbacktone){ + if (call->playing_ringbacktone){ setup_ring_player(lc,call); } - audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); - - /* valid local tags are > 0 */ - if (stream->proto == SalProtoRtpSavp) { - local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalAudio); - crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); - if (crypto_idx >= 0) { - audio_stream_enable_srtp( - call->audiostream, - stream->crypto[0].algo, - local_st_desc->crypto[crypto_idx].master_key, - stream->crypto[0].master_key); - call->audiostream_encrypted=TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - call->audiostream_encrypted=FALSE; - } - }else call->audiostream_encrypted=FALSE; - if (call->params.in_conference){ + if (call->params->in_conference){ /*transform the graph to connect it to the conference filter */ - mute=stream->dir==SalStreamRecvOnly; + mute = stream->dir==SalStreamRecvOnly; linphone_call_add_to_conf(call, mute); } - call->current_params.in_conference=call->params.in_conference; - call->current_params.low_bandwidth=call->params.low_bandwidth; + call->current_params->in_conference=call->params->in_conference; + call->current_params->low_bandwidth=call->params->low_bandwidth; }else ms_warning("No audio stream accepted ?"); } } -static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){ +#ifdef VIDEO_ENABLED +static RtpSession * create_video_rtp_io_session(LinphoneCall *call) { + PayloadType *pt; + LinphoneCore *lc = call->core; + const char *local_ip = lp_config_get_string(lc->config, "video", "rtp_local_addr", "127.0.0.1"); + const char *remote_ip = lp_config_get_string(lc->config, "video", "rtp_remote_addr", "127.0.0.1"); + int local_port = lp_config_get_int(lc->config, "video", "rtp_local_port", 19076); + int remote_port = lp_config_get_int(lc->config, "video", "rtp_remote_port", 19078); + int ptnum = lp_config_get_int(lc->config, "video", "rtp_ptnum", 0); + const char *rtpmap = lp_config_get_string(lc->config, "video", "rtp_map", "vp8/90000/1"); + int symmetric = lp_config_get_int(lc->config, "video", "rtp_symmetric", 0); + RtpSession *rtp_session = NULL; + pt = rtp_profile_get_payload_from_rtpmap(call->video_profile, rtpmap); + if (pt != NULL) { + call->rtp_io_video_profile = rtp_profile_new("RTP IO video profile"); + rtp_profile_set_payload(call->rtp_io_video_profile, ptnum, payload_type_clone(pt)); + rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1); + rtp_session_set_profile(rtp_session, call->rtp_io_video_profile); + rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1); + rtp_session_enable_rtcp(rtp_session, FALSE); + rtp_session_set_payload_type(rtp_session, ptnum); + rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric); + } + return rtp_session; +} +#endif + +static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallState next_state){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; - /* look for savp stream first */ - const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpSavp,SalVideo); - char rtcp_tool[128]={0}; - snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); - - /* no savp audio stream, use avp */ - if (!vstream) - vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); - + const SalStreamDescription *vstream; + MSFilter* source = NULL; + bool_t reused_preview = FALSE; + bool_t use_rtp_io = lp_config_get_int(lc->config, "video", "rtp_io", FALSE); + MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER; + /* shutdown preview */ if (lc->previewstream!=NULL) { - video_preview_stop(lc->previewstream); + if( lc->video_conf.reuse_preview_source == FALSE) video_preview_stop(lc->previewstream); + else source = video_preview_stop_reuse_source(lc->previewstream); lc->previewstream=NULL; } - + + vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo); if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; + const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo); + bool_t is_multicast=ms_is_multicast(rtp_addr); call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); - if (used_pt!=-1){ - call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt); - VideoStreamDir dir=VideoStreamSendRecv; - MSWebCam *cam=lc->video_conf.device; - bool_t is_inactive=FALSE; - call->current_params.has_video=TRUE; + if (used_pt!=-1){ + MediaStreamDir dir= MediaStreamSendRecv; + bool_t is_inactive=FALSE; + MSWebCam *cam; + + call->current_params->video_codec = rtp_profile_get_payload(call->video_profile, used_pt); + call->current_params->has_video=TRUE; video_stream_enable_adaptive_bitrate_control(call->videostream, - linphone_core_adaptive_rate_control_enabled(lc)); + linphone_core_adaptive_rate_control_enabled(lc)); + media_stream_set_adaptive_bitrate_algorithm(&call->videostream->ms, + ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc))); video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc)); + rtp_session_set_jitter_compensation(call->videostream->ms.sessions.rtp_session, linphone_core_get_video_jittcomp(lc)); + if (lc->video_conf.preview_vsize.width!=0) + video_stream_set_preview_size(call->videostream,lc->video_conf.preview_vsize); + video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc)); video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); - if (lc->video_window_id!=0) - video_stream_set_native_window_id(call->videostream,lc->video_window_id); - if (lc->preview_window_id!=0) - video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id); + if (call->video_window_id != NULL) + video_stream_set_native_window_id(call->videostream, call->video_window_id); + else if (lc->video_window_id != NULL) + video_stream_set_native_window_id(call->videostream, lc->video_window_id); + if (lc->preview_window_id != NULL) + video_stream_set_native_preview_window_id(call->videostream, lc->preview_window_id); video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); - - if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ - cam=get_nowebcam_device(); - dir=VideoStreamSendOnly; + + if (is_multicast){ + if (vstream->multicast_role == SalMulticastReceiver) + dir=MediaStreamRecvOnly; + else + dir=MediaStreamSendOnly; + } else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ + dir=MediaStreamSendOnly; }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){ - dir=VideoStreamRecvOnly; + dir=MediaStreamRecvOnly; }else if (vstream->dir==SalStreamSendRecv){ if (lc->video_conf.display && lc->video_conf.capture) - dir=VideoStreamSendRecv; + dir=MediaStreamSendRecv; else if (lc->video_conf.display) - dir=VideoStreamRecvOnly; + dir=MediaStreamRecvOnly; else - dir=VideoStreamSendOnly; + dir=MediaStreamSendOnly; }else{ ms_warning("video stream is inactive."); /*either inactive or incompatible with local capabilities*/ is_inactive=TRUE; } - if (call->camera_active==FALSE || all_inputs_muted){ - cam=get_nowebcam_device(); - } + cam = linphone_call_get_video_device(call); if (!is_inactive){ + if (sal_stream_description_has_srtp(vstream) == TRUE) { + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); + if (crypto_idx >= 0) { + ms_media_stream_sessions_set_srtp_recv_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,vstream->crypto[0].master_key); + ms_media_stream_sessions_set_srtp_send_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + } + } + configure_rtp_session_for_rtcp_fb(call, vstream); + configure_rtp_session_for_rtcp_xr(lc, call, SalVideo); + call->log->video_enabled = TRUE; video_stream_set_direction (call->videostream, dir); ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); 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, - used_pt, linphone_core_get_video_jittcomp(lc), cam); - video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); - } - - if (vstream->proto == SalProtoRtpSavp) { - const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalVideo); - - video_stream_enable_strp( - call->videostream, - vstream->crypto[0].algo, - local_st_desc->crypto[0].master_key, - vstream->crypto[0].master_key - ); - call->videostream_encrypted=TRUE; - }else{ - call->videostream_encrypted=FALSE; + video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0)); + if (is_multicast) + rtp_session_set_multicast_ttl(call->videostream->ms.sessions.rtp_session,vstream->ttl); + + video_stream_use_video_preset(call->videostream, lp_config_get_string(lc->config, "video", "preset", NULL)); + if (lc->video_conf.reuse_preview_source && source) { + ms_message("video_stream_start_with_source kept: %p", source); + video_stream_start_with_source(call->videostream, + call->video_profile, rtp_addr, vstream->rtp_port, + 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, source); + reused_preview = TRUE; + } else { + bool_t ok = TRUE; + if (use_rtp_io) { + io.input.type = io.output.type = MSResourceRtp; + io.input.session = io.output.session = create_video_rtp_io_session(call); + if (io.input.session == NULL) { + ok = FALSE; + ms_warning("Cannot create video RTP IO session"); + } + } else { + io.input.type = MSResourceCamera; + io.input.camera = cam; + io.output.type = MSResourceDefault; + } + if (ok) { + video_stream_start_from_io(call->videostream, + call->video_profile, rtp_addr, vstream->rtp_port, + rtcp_addr, + (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, + used_pt, &io); + } + } + ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core)); } }else ms_warning("No video stream accepted."); }else{ - ms_warning("No valid video stream defined."); + ms_message("No valid video stream defined."); + } + if( reused_preview == FALSE && source != NULL ){ + /* destroy not-reused source filter */ + ms_warning("Video preview (%p) not reused: destroying it.", source); + ms_filter_destroy(source); } #endif } -void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ +static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc) +{ + int i; + const MSCryptoSuite *srtp_suites; + MsZrtpCryptoTypesCount ciphersCount, authTagsCount; + + if (params == NULL) return; + if (lc == NULL) return; + + srtp_suites = linphone_core_get_srtp_crypto_suites(lc); + if (srtp_suites!=NULL) { + for(i=0; srtp_suites[i]!=MS_CRYPTO_SUITE_INVALID && iciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32; + break; + case MS_AES_128_NO_AUTH: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + break; + case MS_NO_CIPHER_SHA1_80: + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_128_SHA1_80: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_256_SHA1_80: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_AES_256_SHA1_32: + params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3; + params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80; + break; + case MS_CRYPTO_SUITE_INVALID: + break; + } + } + } + + /* linphone_core_get_srtp_crypto_suites is used to determine sensible defaults; here each can be overridden */ + ciphersCount = linphone_core_get_zrtp_cipher_suites(lc, params->ciphers); /* if not present in config file, params->ciphers is not modified */ + if (ciphersCount!=0) { /* use zrtp_cipher_suites config only when present, keep config from srtp_crypto_suite otherwise */ + params->ciphersCount = ciphersCount; + } + params->hashesCount = linphone_core_get_zrtp_hash_suites(lc, params->hashes); + authTagsCount = linphone_core_get_zrtp_auth_suites(lc, params->authTags); /* if not present in config file, params->authTags is not modified */ + if (authTagsCount!=0) { + params->authTagsCount = authTagsCount; /* use zrtp_auth_suites config only when present, keep config from srtp_crypto_suite otherwise */ + } + params->sasTypesCount = linphone_core_get_zrtp_sas_suites(lc, params->sasTypes); + params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements); +} + +void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){ LinphoneCore *lc=call->core; - LinphoneAddress *me; - char *cname; - bool_t use_arc; - - call->current_params.audio_codec = NULL; - call->current_params.video_codec = NULL; - - me=linphone_core_get_primary_contact_parsed(lc); - use_arc=linphone_core_adaptive_rate_control_enabled(lc); + bool_t use_arc = linphone_core_adaptive_rate_control_enabled(lc); #ifdef VIDEO_ENABLED - const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); + const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo); #endif + switch (next_state){ + case LinphoneCallIncomingEarlyMedia: + if (linphone_core_get_remote_ringback_tone(lc)){ + call->playing_ringbacktone = TRUE; + } + case LinphoneCallOutgoingEarlyMedia: + if (!call->params->real_early_media){ + call->all_muted = TRUE; + } + break; + default: + call->playing_ringbacktone = FALSE; + call->all_muted = FALSE; + break; + } + + call->current_params->audio_codec = NULL; + call->current_params->video_codec = NULL; + if ((call->audiostream == NULL) && (call->videostream == NULL)) { ms_fatal("start_media_stream() called without prior init !"); return; } - cname=linphone_address_as_string_uri_only(me); - #if defined(VIDEO_ENABLED) if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ /*when video is used, do not make adaptive rate control on audio, it is stupid.*/ use_arc=FALSE; } #endif + ms_message("linphone_call_start_media_streams() call=[%p] local upload_bandwidth=[%i] kbit/s; local download_bandwidth=[%i] kbit/s", + call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc)); + if (call->audiostream!=NULL) { - linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc); + linphone_call_start_audio_stream(call, next_state, use_arc); + } else { + ms_warning("DTLS no audio stream!"); } - call->current_params.has_video=FALSE; + call->current_params->has_video=FALSE; if (call->videostream!=NULL) { - linphone_call_start_video_stream(call,cname,all_inputs_muted); + if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream); + linphone_call_start_video_stream(call, next_state); } - call->all_muted=all_inputs_muted; - call->playing_ringbacktone=send_ringbacktone; call->up_bw=linphone_core_get_upload_bandwidth(lc); - if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { - OrtpZrtpParams params; - /*will be set later when zrtp is activated*/ - call->current_params.media_encryption=LinphoneMediaEncryptionNone; - + /*might be moved in audio/video stream_start*/ + if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { + MSZrtpParams params; + memset(¶ms,0,sizeof(MSZrtpParams)); + /*call->current_params.media_encryption will be set later when zrtp is activated*/ params.zid_file=lc->zrtp_secrets_cache; + params.uri= linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to); + setZrtpCryptoTypesParameters(¶ms,call->core); audio_stream_enable_zrtp(call->audiostream,¶ms); - }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){ - call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? - LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; +#if VIDEO_ENABLED + if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + /*audio stream is already encrypted and video stream is active*/ + memset(¶ms,0,sizeof(MSZrtpParams)); + video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); + } +#endif } - /*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); + set_dtls_fingerprint_on_all_streams(call); + if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { ice_session_start_connectivity_checks(call->ice_session); + } else { + /*should not start dtls until ice is completed*/ + start_dtls_on_all_streams(call); } - goto end; - end: - ms_free(cname); - linphone_address_destroy(me); -} - -void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ - audio_stream_prepare_sound(call->audiostream, NULL, NULL); -#ifdef VIDEO_ENABLED - if (call->videostream) { - video_stream_prepare_video(call->videostream); - } -#endif } void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ - audio_stream_unprepare_sound(call->audiostream); + if(call->audiostream && call->audiostream->ms.state==MSStreamPreparing) audio_stream_unprepare_sound(call->audiostream); #ifdef VIDEO_ENABLED - if (call->videostream) { + if (call->videostream && call->videostream->ms.state==MSStreamPreparing) { video_stream_unprepare_video(call->videostream); } #endif } +static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDescription *local_st_desc, SalStreamDescription *old_stream, SalStreamDescription *new_stream, MediaStream *ms){ + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); + if (crypto_idx >= 0) { + if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) + ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){ + ms_media_stream_sessions_set_srtp_recv_key_b64(&ms->sessions, new_stream->crypto[0].algo,new_stream->crypto[0].master_key); + } + return TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); + } + return FALSE; +} + void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { SalStreamDescription *old_stream; SalStreamDescription *new_stream; - int i; + const SalStreamDescription *local_st_desc; - old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); - new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); - if (old_stream && new_stream) { - const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); - if (local_st_desc) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); - if (crypto_idx >= 0) { - audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); - call->audiostream_encrypted = TRUE; - } else { - 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); - } - } + local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio); + old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio); + new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio); + if (call->audiostream && local_st_desc && old_stream && new_stream && + update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){ } + start_dtls_on_all_streams(call); + #ifdef VIDEO_ENABLED - old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo); - new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo); - if (old_stream && new_stream) { - const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); - if (local_st_desc) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); - if (crypto_idx >= 0) { - video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); - call->videostream_encrypted = TRUE; - } else { - 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); - } - } + local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo); + old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo); + new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo); + if (call->videostream && local_st_desc && old_stream && new_stream && + update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){ } #endif } @@ -1862,71 +3100,118 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ } } -#ifdef BUILD_UPNP + void linphone_call_delete_upnp_session(LinphoneCall *call){ +#ifdef BUILD_UPNP if(call->upnp_session!=NULL) { linphone_upnp_session_destroy(call->upnp_session); call->upnp_session=NULL; } -} #endif //BUILD_UPNP - -static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ - audio_stream_get_local_rtp_stats (st,&log->local_stats); - log->quality=audio_stream_get_average_quality_rating(st); } -void linphone_call_stop_audio_stream(LinphoneCall *call) { + +static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ + float quality=media_stream_get_average_quality_rating(st); + if (quality>=0){ + if (log->quality!=-1){ + log->quality*=quality/5.0; + }else log->quality=quality; + } +} + +static void update_rtp_stats(LinphoneCall *call, int stream_index) { + if (stream_index >= linphone_call_get_stream_count(call)) { + return; + } + + if (call->sessions[stream_index].rtp_session) { + const rtp_stats_t *stats = rtp_session_get_stats(call->sessions[stream_index].rtp_session); + memcpy(&call->stats[stream_index].rtp_stats, stats, sizeof(*stats)); + } +} + +static void linphone_call_stop_audio_stream(LinphoneCall *call) { if (call->audiostream!=NULL) { - rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq); - ortp_ev_queue_flush(call->audiostream_app_evq); - ortp_ev_queue_destroy(call->audiostream_app_evq); - call->audiostream_app_evq=NULL; + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); + media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]); if (call->audiostream->ec){ const char *state_str=NULL; ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str); if (state_str){ ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str)); - lp_config_set_string(call->core->config,"sound","ec_state",state_str); + lp_config_write_relative_file(call->core->config, EC_STATE_STORE, state_str); } } - linphone_call_log_fill_stats (call->log,call->audiostream); + audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats); + linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream); if (call->endpoint){ linphone_call_remove_from_conf(call); } audio_stream_stop(call->audiostream); + update_rtp_stats(call, 0); + rtp_session_unregister_event_queue(call->sessions[0].rtp_session, call->audiostream_app_evq); + ortp_ev_queue_flush(call->audiostream_app_evq); + ortp_ev_queue_destroy(call->audiostream_app_evq); + call->audiostream_app_evq=NULL; call->audiostream=NULL; + call->current_params->audio_codec = NULL; } } -void linphone_call_stop_video_stream(LinphoneCall *call) { +static void linphone_call_stop_video_stream(LinphoneCall *call) { #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ - rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq); + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); + media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]); + linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); + video_stream_stop(call->videostream); + call->videostream=NULL; + update_rtp_stats(call, 1); + rtp_session_unregister_event_queue(call->sessions[1].rtp_session, call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); call->videostream_app_evq=NULL; - video_stream_stop(call->videostream); - call->videostream=NULL; + call->current_params->video_codec = NULL; } #endif } +static void unset_rtp_profile(LinphoneCall *call, int i){ + if (call->sessions[i].rtp_session) + rtp_session_set_profile(call->sessions[i].rtp_session,&av_profile); +} + 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->audiostream || call->videostream) { + if (call->audiostream && call->videostream) + audio_stream_unlink_video(call->audiostream, call->videostream); + linphone_call_stop_audio_stream(call); + linphone_call_stop_video_stream(call); + + 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; + unset_rtp_profile(call,0); } if (call->video_profile){ - rtp_profile_clear_all(call->video_profile); rtp_profile_destroy(call->video_profile); call->video_profile=NULL; + unset_rtp_profile(call,1); + } + if (call->rtp_io_audio_profile) { + rtp_profile_destroy(call->rtp_io_audio_profile); + call->rtp_io_audio_profile = NULL; + } + if (call->rtp_io_video_profile) { + rtp_profile_destroy(call->rtp_io_video_profile); + call->rtp_io_video_profile = NULL; } } @@ -2005,6 +3290,32 @@ float linphone_call_get_record_volume(LinphoneCall *call){ return LINPHONE_VOLUME_DB_LOWEST; } +float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) { + if(call->audiostream) return audio_stream_get_sound_card_output_gain(call->audiostream); + else { + ms_error("Could not get playback volume: no audio stream"); + return -1.0f; + } +} + +void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) { + if(call->audiostream) audio_stream_set_sound_card_output_gain(call->audiostream, volume); + else ms_error("Could not set playback volume: no audio stream"); +} + +float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) { + if(call->audiostream) return audio_stream_get_sound_card_input_gain(call->audiostream); + else { + ms_error("Could not get record volume: no audio stream"); + return -1.0f; + } +} + +void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) { + if(call->audiostream) audio_stream_set_sound_card_input_gain(call->audiostream, volume); + else ms_error("Could not set record volume: no audio stream"); +} + /** * Obtain real-time quality rating of the call * @@ -2019,14 +3330,24 @@ float linphone_call_get_record_volume(LinphoneCall *call){ * 1-2 = very poor quality
    * 0-1 = can't be worse, mostly unusable
    * - * @returns The function returns -1 if no quality measurement is available, for example if no + * @return The function returns -1 if no quality measurement is available, for example if no * active audio stream exist. Otherwise it returns the quality rating. **/ float linphone_call_get_current_quality(LinphoneCall *call){ + float audio_rating=-1; + float video_rating=-1; + float result; if (call->audiostream){ - return audio_stream_get_quality_rating(call->audiostream); + audio_rating=media_stream_get_quality_rating((MediaStream*)call->audiostream)/5.0; } - return -1; + if (call->videostream){ + video_rating=media_stream_get_quality_rating((MediaStream*)call->videostream)/5.0; + } + if (audio_rating<0 && video_rating<0) result=-1; + else if (audio_rating<0) result=video_rating*5.0; + else if (video_rating<0) result=audio_rating*5.0; + else result=audio_rating*video_rating*5.0; + return result; } /** @@ -2041,41 +3362,217 @@ float linphone_call_get_average_quality(LinphoneCall *call){ return -1; } +static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) { + const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream); + if (qi) { + stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi); + stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi); + } + media_stream_get_local_rtp_stats(stream, &stats->rtp_stats); +} + /** * Access last known statistics for audio stream, for a given call. **/ -const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) { - return &call->stats[LINPHONE_CALL_STATS_AUDIO]; +const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) { + LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_AUDIO]; + if (call->audiostream){ + update_local_stats(stats,(MediaStream*)call->audiostream); + } + return stats; } /** * Access last known statistics for video stream, for a given call. **/ -const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) { - return &call->stats[LINPHONE_CALL_STATS_VIDEO]; -} - -/** - * Enable recording of the call (voice-only). - * This function must be used before the call parameters are assigned to the call. - * The call recording can be started and paused after the call is established with - * linphone_call_start_recording() and linphone_call_pause_recording(). - * @param cp the call parameters - * @param path path and filename of the file where audio is written. -**/ -void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){ - if (cp->record_file){ - ms_free(cp->record_file); - cp->record_file=NULL; +const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { + LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_VIDEO]; + if (call->videostream){ + update_local_stats(stats,(MediaStream*)call->videostream); } - if (path) cp->record_file=ms_strdup(path); + return stats; +} + +static bool_t ice_in_progress(LinphoneCallStats *stats){ + return stats->ice_state==LinphoneIceStateInProgress; } /** - * Retrieves the path for the audio recoding of the call. + * Indicates whether an operation is in progress at the media side. + * It can a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while + * the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time + * in future operations in the call. + * Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not. + * @param call the call + * @return TRUE if media is busy in establishing the connection, FALSE otherwise. **/ -const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){ - return cp->record_file; +bool_t linphone_call_media_in_progress(LinphoneCall *call){ + bool_t ret=FALSE; + if (ice_in_progress(&call->stats[LINPHONE_CALL_STATS_AUDIO]) || ice_in_progress(&call->stats[LINPHONE_CALL_STATS_VIDEO])) + ret=TRUE; + /*TODO: could check zrtp state, upnp state*/ + return ret; +} + +/** + * Get the local loss rate since last report + * @return The sender loss rate +**/ +float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) { + const report_block_t *srb = NULL; + + if (!stats || !stats->sent_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (!srb) + return 0.0; + return 100.0 * report_block_get_fraction_lost(srb) / 256.0; +} + +/** + * Gets the remote reported loss rate since last report + * @return The receiver loss rate +**/ +float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) { + const report_block_t *rrb = NULL; + + if (!stats || !stats->received_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + if (!rrb) + return 0.0; + return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; +} + +/** + * Gets the local interarrival jitter + * @return The interarrival jitter at last emitted sender report +**/ +float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *srb = NULL; + + if (!stats || !call || !stats->sent_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (!srb) + return 0.0; + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; +} + +/** + * Gets the remote reported interarrival jitter + * @return The interarrival jitter at last received receiver report +**/ +float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *rrb = NULL; + + if (!stats || !call || !stats->received_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + if (!rrb) + return 0.0; + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; +} + +rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) { + rtp_stats_t rtp_stats; + memset(&rtp_stats, 0, sizeof(rtp_stats)); + + if (stats) { + memcpy(&rtp_stats, &stats->rtp_stats, sizeof(stats->rtp_stats)); + } + + return rtp_stats; +} + +/** + * Gets the cumulative number of late packets + * @return The cumulative number of late packets +**/ +uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) { + return linphone_call_stats_get_rtp_stats(stats).outoftime; +} + +/** + * Get the bandwidth measurement of the received stream, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the received stream in kbit/s. + */ +float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats) { + return stats->download_bandwidth; +} + +/** + * Get the bandwidth measurement of the sent stream, expressed in kbit/s, including IP/UDP/RTP headers. + * @param[in] stats LinphoneCallStats object + * @return The bandwidth measurement of the sent stream in kbit/s. + */ +float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats) { + return stats->upload_bandwidth; +} + +/** + * Get the state of ICE processing. + * @param[in] stats LinphoneCallStats object + * @return The state of ICE processing. + */ +LinphoneIceState linphone_call_stats_get_ice_state(const LinphoneCallStats *stats) { + return stats->ice_state; +} + +/** + * Get the state of uPnP processing. + * @param[in] stats LinphoneCallStats object + * @return The state of uPnP processing. + */ +LinphoneUpnpState linphone_call_stats_get_upnp_state(const LinphoneCallStats *stats) { + return stats->upnp_state; } /** @@ -2083,11 +3580,11 @@ const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){ * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file(). **/ void linphone_call_start_recording(LinphoneCall *call){ - if (!call->params.record_file){ + if (!call->params->record_file){ ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file()."); return; } - if (call->audiostream && !call->params.in_conference){ + if (call->audiostream && !call->params->in_conference){ audio_stream_mixed_record_start(call->audiostream); } call->record_active=TRUE; @@ -2097,7 +3594,7 @@ void linphone_call_start_recording(LinphoneCall *call){ * Stop call recording. **/ void linphone_call_stop_recording(LinphoneCall *call){ - if (call->audiostream && !call->params.in_conference){ + if (call->audiostream && !call->params->in_conference){ audio_stream_mixed_record_stop(call->audiostream); } call->record_active=FALSE; @@ -2107,36 +3604,86 @@ 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", - call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth, - call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth , - call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth, - call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth +static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs){ + bool_t as_active = as ? (media_stream_get_state(as) == MSStreamStarted) : FALSE; + bool_t vs_active = vs ? (media_stream_get_state(vs) == MSStreamStarted) : FALSE; + + call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as_active) ? (media_stream_get_down_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as_active) ? (media_stream_get_up_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs_active) ? (media_stream_get_down_bw(vs)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs_active) ? (media_stream_get_up_bw(vs)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_download_bandwidth=(as_active) ? (media_stream_get_rtcp_down_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_upload_bandwidth=(as_active) ? (media_stream_get_rtcp_up_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_download_bandwidth=(vs_active) ? (media_stream_get_rtcp_down_bw(vs)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_upload_bandwidth=(vs_active) ? (media_stream_get_rtcp_up_bw(vs)*1e-3) : 0; + if (as_active) { + call->stats[LINPHONE_CALL_STATS_AUDIO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE; + linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); + call->stats[LINPHONE_CALL_STATS_AUDIO].updated=0; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], as); + } + if (vs_active) { + call->stats[LINPHONE_CALL_STATS_VIDEO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE; + linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); + call->stats[LINPHONE_CALL_STATS_VIDEO].updated=0; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], vs); + } + + ms_message( "Bandwidth usage for call [%p]:\n" + "\tRTP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f] kbits/sec\n" + "\tRTCP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f] kbits/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, + call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth, + call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_download_bandwidth, + call->stats[LINPHONE_CALL_STATS_AUDIO].rtcp_upload_bandwidth, + call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_download_bandwidth, + call->stats[LINPHONE_CALL_STATS_VIDEO].rtcp_upload_bandwidth ); + } static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ - char temp[256]; + char temp[256]={0}; char *from=NULL; - if(call) - from = linphone_call_get_remote_address_as_string(call); - if (from) - { - snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from); - free(from); - } - else - { - snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed."); - } - if (lc->vtable.display_warning!=NULL) - lc->vtable.display_warning(lc,temp); + + from = linphone_call_get_remote_address_as_string(call); + snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : ""); + if (from) ms_free(from); + + ms_message("On call [%p]: %s",call,temp); + linphone_core_notify_display_warning(lc,temp); linphone_core_terminate_call(lc,call); + linphone_core_play_named_tone(lc,LinphoneToneCallLost); +} + +static void change_ice_media_destinations(LinphoneCall *call) { + const char *rtp_addr; + const char *rtcp_addr; + int rtp_port; + int rtcp_port; + bool_t result; + + if (call->audiostream && ice_session_check_list(call->ice_session, 0)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 0), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (result == TRUE) { + ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); + rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session, FALSE); + rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + } + } +#ifdef VIDEO_ENABLED + if (call->videostream && ice_session_check_list(call->ice_session, 1)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 1), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (result == TRUE) { + ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE); + rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + } + } +#endif } static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ @@ -2145,19 +3692,37 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ int ping_time; if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + LinphoneCallParams *params = linphone_call_params_copy(call->current_params); + switch (call->params->media_encryption) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + /* preserve media encryption param because at that time ZRTP/SRTP-DTLS negociation may still be ongoing*/ + params->media_encryption=call->params->media_encryption; + break; + case LinphoneMediaEncryptionSRTP: + case LinphoneMediaEncryptionNone: + /*keep all values to make sure a warning will be generated by compiler if new enum value is added*/ + break; + } + switch (ice_session_state(call->ice_session)) { case IS_Completed: ice_session_select_candidates(call->ice_session); - if (ice_session_role(call->ice_session) == IR_Controlling) { - linphone_core_update_call(call->core, call, &call->current_params); + if (ice_session_role(call->ice_session) == IR_Controlling + && lp_config_get_int(call->core->config, "sip", "update_call_when_ice_completed", TRUE)) { + params->internal_call_update = TRUE; + linphone_core_update_call(call->core, call, params); } + change_ice_media_destinations(call); + start_dtls_on_all_streams(call); break; case IS_Failed: if (ice_session_has_completed_check_list(call->ice_session) == TRUE) { ice_session_select_candidates(call->ice_session); if (ice_session_role(call->ice_session) == IR_Controlling) { /* At least one ICE session has succeeded, so perform a call update. */ - linphone_core_update_call(call->core, call, &call->current_params); + params->internal_call_update = TRUE; + linphone_core_update_call(call->core, call, params); } } break; @@ -2165,6 +3730,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; } linphone_core_update_ice_state_in_call_stats(call); + linphone_call_params_unref(params); } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { if (evd->info.ice_processing_successful==TRUE) { @@ -2184,7 +3750,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ linphone_core_start_update_call(call->core, call); break; case LinphoneCallUpdatedByRemote: - linphone_core_start_accept_call_update(call->core, call); + linphone_core_start_accept_call_update(call->core, call,call->prevstate,linphone_call_state_to_string(call->prevstate)); break; case LinphoneCallOutgoingInit: linphone_call_stop_media_streams_for_ice_gathering(call); @@ -2192,130 +3758,168 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; case LinphoneCallIdle: linphone_call_stop_media_streams_for_ice_gathering(call); + linphone_call_update_local_media_description_from_ice_or_upnp(call); + sal_call_set_local_media_description(call->op,call->localdesc); linphone_core_notify_incoming_call(call->core, call); break; default: break; } } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { - linphone_core_start_accept_call_update(call->core, call); - linphone_core_update_ice_state_in_call_stats(call); + if (call->state==LinphoneCallUpdatedByRemote){ + linphone_core_start_accept_call_update(call->core, call,call->prevstate,linphone_call_state_to_string(call->prevstate)); + linphone_core_update_ice_state_in_call_stats(call); + } } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { ice_session_restart(call->ice_session); ice_session_set_role(call->ice_session, IR_Controlling); - linphone_core_update_call(call->core, call, &call->current_params); + linphone_core_update_call(call->core, call, call->current_params); + } +} + + +/*do not change the prototype of this function, it is also used internally in linphone-daemon.*/ +void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + + if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session); + if(stats->received_rtcp != NULL) + freemsg(stats->received_rtcp); + stats->received_rtcp = evd->packet; + evd->packet = NULL; + stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; + update_local_stats(stats,ms); + } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { + memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t)); + if (stats->sent_rtcp != NULL) + freemsg(stats->sent_rtcp); + stats->sent_rtcp = evd->packet; + evd->packet = NULL; + stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; + update_local_stats(stats,ms); + } +} + +void linphone_call_stats_uninit(LinphoneCallStats *stats){ + if (stats->received_rtcp) { + freemsg(stats->received_rtcp); + stats->received_rtcp=NULL; + } + if (stats->sent_rtcp){ + freemsg(stats->sent_rtcp); + stats->sent_rtcp=NULL; + } +} + +void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){ + LinphoneCallStats *stats=&call->stats[stream_index]; + LinphoneCore *lc=call->core; + if (stats->updated){ + switch(stats->updated) { + case LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE: + case LINPHONE_CALL_STATS_SENT_RTCP_UPDATE: + linphone_reporting_on_rtcp_update(call, stream_index); + break; + default:break; + } + linphone_core_notify_call_stats_updated(lc, call, stats); + stats->updated = 0; + } +} + +void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ + MediaStream *ms=stream_index==0 ? (MediaStream *)call->audiostream : (MediaStream *)call->videostream; /*assumption to remove*/ + OrtpEvQueue *evq; + OrtpEvent *ev; + + if (ms==NULL) return; + /* Ensure there is no dangling ICE check list. */ + if (call->ice_session == NULL) ms->ice_check_list = NULL; + + switch(ms->type){ + case MSAudio: + audio_stream_iterate((AudioStream*)ms); + break; + case MSVideo: +#ifdef VIDEO_ENABLED + video_stream_iterate((VideoStream*)ms); +#endif + break; + default: + ms_error("linphone_call_handle_stream_events(): unsupported stream type."); + return; + break; + } + /*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/ + while ((evq=stream_index==0 ? call->audiostream_app_evq : call->videostream_app_evq) && (NULL != (ev=ortp_ev_queue_get(evq)))){ + OrtpEventType evt=ortp_event_get_type(ev); + OrtpEventData *evd=ortp_event_get_data(ev); + + linphone_call_stats_fill(&call->stats[stream_index],ms,ev); + linphone_call_notify_stats_updated(call,stream_index); + + if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ + if (ms->type==MSAudio) + linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); + else if (ms->type==MSVideo) + propagate_encryption_changed(call); + } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { + if (ms->type==MSAudio) + linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); + } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) { + if (ms->type==MSAudio) + linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted); + else if (ms->type==MSVideo) + propagate_encryption_changed(call); + }else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) + || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { + handle_ice_events(call, ev); + } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){ + linphone_core_dtmf_received(call,evd->info.telephone_event); + } + ortp_event_destroy(ev); } } void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){ - LinphoneCore* lc = call->core; 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; - 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); + switch (call->state) { + case LinphoneCallStreamsRunning: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallPausedByRemote: + case LinphoneCallPaused: + if (one_second_elapsed){ + float audio_load=0, video_load=0; + if (call->audiostream!=NULL){ + if (call->audiostream->ms.sessions.ticker) + audio_load=ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker); + } + if (call->videostream!=NULL){ + if (call->videostream->ms.sessions.ticker) + video_load=ms_ticker_get_average_load(call->videostream->ms.sessions.ticker); + } + report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream); + ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); } - 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); - ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); + break; + default: + /*no stats for other states*/ + break; } #ifdef BUILD_UPNP linphone_upnp_call_process(call); #endif //BUILD_UPNP -#ifdef VIDEO_ENABLED - if (call->videostream!=NULL) { - OrtpEvent *ev; - - /* Ensure there is no dangling ICE check list. */ - if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL; - - // Beware that the application queue should not depend on treatments fron the - // mediastreamer queue. - video_stream_iterate(call->videostream); - - while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) - || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { - handle_ice_events(call, ev); - } - ortp_event_destroy(ev); - } - } -#endif - if (call->audiostream!=NULL) { - OrtpEvent *ev; - - /* Ensure there is no dangling ICE check list. */ - if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL; - - // Beware that the application queue should not depend on treatments fron the - // mediastreamer queue. - audio_stream_iterate(call->audiostream); - - while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){ - OrtpEventType evt=ortp_event_get_type(ev); - OrtpEventData *evd=ortp_event_get_data(ev); - if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ - linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); - } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { - linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); - } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t)); - if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) - freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); - call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; - evd->packet = NULL; - if (lc->vtable.call_stats_updated) - lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) - || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { - handle_ice_events(call, ev); - } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){ - linphone_core_dtmf_received(lc,evd->info.telephone_event); - } - ortp_event_destroy(ev); - } - } - if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 ) + linphone_call_handle_stream_events(call,0); + linphone_call_handle_stream_events(call,1); + if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL + && call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 ) disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); if (disconnected) linphone_core_disconnected(call->core,call); @@ -2324,19 +3928,18 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse void linphone_call_log_completed(LinphoneCall *call){ LinphoneCore *lc=call->core; - call->log->duration=time(NULL)-call->start_time; + call->log->duration=linphone_call_get_duration(call); /*store duration since connected*/ if (call->log->status==LinphoneCallMissed){ char *info; lc->missed_calls++; info=ortp_strdup_printf(ngettext("You have missed %i call.", - "You have missed %i calls.", lc->missed_calls), - lc->missed_calls); - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,info); + "You have missed %i calls.", lc->missed_calls), + lc->missed_calls); + linphone_core_notify_display_status(lc,info); ms_free(info); } - lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log); + lc->call_logs=ms_list_prepend(lc->call_logs,linphone_call_log_ref(call->log)); if (ms_list_size(lc->call_logs)>lc->max_call_logs){ MSList *elem,*prevelem=NULL; /*find the last element*/ @@ -2344,15 +3947,17 @@ void linphone_call_log_completed(LinphoneCall *call){ prevelem=elem; } elem=prevelem; - linphone_call_log_destroy((LinphoneCallLog*)elem->data); + linphone_call_log_unref((LinphoneCallLog*)elem->data); lc->call_logs=ms_list_remove_link(lc->call_logs,elem); } - if (lc->vtable.call_log_updated!=NULL){ - lc->vtable.call_log_updated(lc,call->log); - } + linphone_core_notify_call_log_updated(lc,call->log); 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; } @@ -2360,36 +3965,33 @@ 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); + linphone_core_notify_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; + return call->params->in_conference; } - /** * Perform a zoom of the video displayed during a call. * @param call the call. * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. * @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; halfsize = 0.5 * 1.0 / zoom_factor; @@ -2402,11 +4004,227 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, *cy = 0 + halfsize; if ((*cy + halfsize) > 1) *cy = 1 - halfsize; - + zoom[0] = zoom_factor; zoom[1] = *cx; zoom[2] = *cy; - ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); + ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); }else ms_warning("Could not apply zoom: video output wasn't activated."); } +static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ + LinphoneAddress *ctt=NULL; + LinphoneAddress *ret=NULL; + //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)); + ret=ctt; + } else if (call->op && sal_op_get_contact_address(call->op)!=NULL){ + /* if already choosed, don't change it */ + return NULL; + } else if (call->ping_op && sal_op_get_contact_address(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*/); + ret=linphone_address_clone(sal_op_get_contact_address(call->ping_op));; + } else if (dest_proxy && dest_proxy->op && sal_op_get_contact_address(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*/); + ret=linphone_address_clone(sal_op_get_contact_address(dest_proxy->op)); + } else { + ctt=linphone_core_get_primary_contact_parsed(lc); + if (ctt!=NULL){ + /*otherwise use supplied localip*/ + linphone_address_set_domain(ctt,NULL/*localip*/); + linphone_address_set_port(ctt,-1/*linphone_core_get_sip_port(lc)*/); + ms_message("Contact has not been fixed stack will do"/* to %s",ret*/); + ret=ctt; + } + } + 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_address(call->op, contact); + linphone_address_destroy(contact); + } +} + +LinphonePlayer *linphone_call_get_player(LinphoneCall *call){ + if (call->player==NULL) + call->player=linphone_call_build_player(call); + return call->player; +} + +void linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){ + LinphoneCallParams *cp=NULL; + if (params) cp=linphone_call_params_copy(params); + if (call->params) linphone_call_params_unref(call->params); + call->params=cp; +} + +static int send_dtmf_handler(void *data, unsigned int revents){ + LinphoneCall *call = (LinphoneCall*)data; + /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ + if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0) + { + /* In Band DTMF */ + if (call->audiostream!=NULL){ + audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence); + } + else + { + ms_error("Cannot send RFC2833 DTMF when we are not in communication."); + return FALSE; + } + } + if (linphone_core_get_use_info_for_dtmf(call->core)!=0){ + /* Out of Band DTMF (use INFO method) */ + sal_call_send_dtmf(call->op,*call->dtmf_sequence); + } + + /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/ + if (call->dtmfs_timer!=NULL) { + memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence)); + } + /* continue only if the dtmf sequence is not empty*/ + if (call->dtmf_sequence!=NULL&&*call->dtmf_sequence!='\0') { + return TRUE; + } else { + linphone_call_cancel_dtmfs(call); + return FALSE; + } +} +int linphone_call_send_dtmf(LinphoneCall *call,char dtmf){ + if (call==NULL){ + ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF."); + return -1; + } + call->dtmf_sequence = &dtmf; + send_dtmf_handler(call,0); + call->dtmf_sequence = NULL; + return 0; +} + +int linphone_call_send_dtmfs(LinphoneCall *call,char *dtmfs) { + if (call==NULL){ + ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence."); + return -1; + } + if (call->dtmfs_timer!=NULL){ + ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence."); + return -2; + } + if (dtmfs != NULL) { + int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200); + call->dtmf_sequence = ms_strdup(dtmfs); + call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer"); + } + return 0; +} + +void linphone_call_cancel_dtmfs(LinphoneCall *call) { + /*nothing to do*/ + if (!call || !call->dtmfs_timer) return; + + sal_cancel_timer(call->core->sal, call->dtmfs_timer); + belle_sip_object_unref(call->dtmfs_timer); + call->dtmfs_timer = NULL; + if (call->dtmf_sequence != NULL) { + ms_free(call->dtmf_sequence); + call->dtmf_sequence = NULL; + } +} + +void * linphone_call_get_native_video_window_id(const LinphoneCall *call) { + if (call->video_window_id) { + /* The video id was previously set by the app. */ + return call->video_window_id; + } +#ifdef VIDEO_ENABLED + else if (call->videostream) { + /* It was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only). */ + return video_stream_get_native_window_id(call->videostream); + } +#endif + return 0; +} + +void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) { + call->video_window_id = id; +#ifdef VIDEO_ENABLED + if (call->videostream) { + video_stream_set_native_window_id(call->videostream, id); + } +#endif +} + +MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) { + if (call->all_muted || call->camera_enabled == FALSE) + return get_nowebcam_device(); + else + return call->core->video_conf.device; +} + + +void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) { + if (call != NULL && call->audiostream != NULL){ + audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); + } +} + +int linphone_call_get_stream_count(LinphoneCall *call) { + // Revisit when multiple media streams will be implemented +#ifdef VIDEO_ENABLED + return 2; +#else + return 1; +#endif +} + +MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) { + // Revisit when multiple media streams will be implemented + if (stream_index == 0) { + return MSAudio; + } + return MSVideo; +} + +RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { + return NULL; + } + + rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); + return meta_rtp; +} + +RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { + return NULL; + } + + rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); + return meta_rtcp; +} \ No newline at end of file diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1e1a7a64b..3d124d147 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1,6 +1,7 @@ /* linphone Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) +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 @@ -17,16 +18,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define _GNU_SOURCE - #include "linphonecore.h" #include "sipsetup.h" #include "lpconfig.h" #include "private.h" +#include "quality_reporting.h" +#include "lime.h" #include +#include +#include #include -#include +#include +#include #include "mediastreamer2/mediastream.h" #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/msvolume.h" @@ -34,20 +38,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/dtmfgen.h" #ifdef INET6 -#ifndef WIN32 +#ifndef _WIN32 #include #endif #endif #ifdef HAVE_CONFIG_H #include "config.h" -#include "liblinphone_gitversion.h" +#ifndef ANDROID /*on Android LIBLINPHONE version is passed from root Makefile*/ + #include "liblinphone_gitversion.h" +#endif #else #ifndef LIBLINPHONE_GIT_VERSION #define LIBLINPHONE_GIT_VERSION "unknown" #endif #endif +#ifdef __APPLE__ +#include "TargetConditionals.h" +#endif + +#ifdef HAVE_ZLIB +#define COMPRESSED_LOG_COLLECTION_EXTENSION "gz" +#ifdef _WIN32 +#include +#include +#ifndef fileno +#define fileno _fileno +#endif +#define unlink _unlink +#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +#define SET_BINARY_MODE(file) +#endif +#include +#else +#define COMPRESSED_LOG_COLLECTION_EXTENSION "txt" +#endif +#define LOG_COLLECTION_DEFAULT_PATH "." +#define LOG_COLLECTION_DEFAULT_PREFIX "linphone" +#define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024) + /*#define UNSTANDART_GSM_11K 1*/ @@ -60,20 +91,33 @@ static const char *liblinphone_version= LIBLINPHONE_VERSION #endif ; +static OrtpLogFunc liblinphone_log_func = NULL; +static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled; +static char * liblinphone_log_collection_path = NULL; +static char * liblinphone_log_collection_prefix = NULL; +static int liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE; +static ortp_mutex_t liblinphone_log_collection_mutex; +static bool_t liblinphone_serialize_logs = FALSE; static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime); static void linphone_core_run_hooks(LinphoneCore *lc); -static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" +#include "contact_providers_priv.h" + const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); +#if defined(LINPHONE_WINDOWS_PHONE) || defined(LINPHONE_WINDOWS_UNIVERSAL) +#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; @@ -90,293 +134,6 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ } -/*prevent a gcc bug with %c*/ -static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){ - return strftime(s, max, fmt, tm); -} - -static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){ - struct tm loctime; -#ifdef WIN32 -#if !defined(_WIN32_WCE) - loctime=*localtime(&start_time); - /*FIXME*/ -#endif /*_WIN32_WCE*/ -#else - localtime_r(&start_time,&loctime); -#endif - my_strftime(cl->start_date,sizeof(cl->start_date),"%c",&loctime); -} - -LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ - LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1); - cl->dir=call->dir; - cl->start_date_time=call->start_time; - set_call_log_date(cl,cl->start_date_time); - cl->from=from; - cl->to=to; - cl->status=LinphoneCallAborted; /*default status*/ - return cl; -} - -void call_logs_write_to_config_file(LinphoneCore *lc){ - MSList *elem; - char logsection[32]; - int i; - char *tmp; - LpConfig *cfg=lc->config; - - if (linphone_core_get_global_state (lc)==LinphoneGlobalStartup) return; - - for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){ - LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; - snprintf(logsection,sizeof(logsection),"call_log_%i",i); - lp_config_clean_section(cfg,logsection); - lp_config_set_int(cfg,logsection,"dir",cl->dir); - lp_config_set_int(cfg,logsection,"status",cl->status); - tmp=linphone_address_as_string(cl->from); - lp_config_set_string(cfg,logsection,"from",tmp); - ms_free(tmp); - tmp=linphone_address_as_string(cl->to); - lp_config_set_string(cfg,logsection,"to",tmp); - ms_free(tmp); - if (cl->start_date_time) - lp_config_set_int64(cfg,logsection,"start_date_time",(int64_t)cl->start_date_time); - else lp_config_set_string(cfg,logsection,"start_date",cl->start_date); - lp_config_set_int(cfg,logsection,"duration",cl->duration); - if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey); - lp_config_set_float(cfg,logsection,"quality",cl->quality); - lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled); - lp_config_set_string(cfg,logsection,"call_id",cl->call_id); - } - for(;imax_call_logs;++i){ - snprintf(logsection,sizeof(logsection),"call_log_%i",i); - lp_config_clean_section(cfg,logsection); - } -} - -static time_t string_to_time(const char *date){ -#ifndef WIN32 - struct tm tmtime={0}; - strptime(date,"%c",&tmtime); - return mktime(&tmtime); -#else - return 0; -#endif -} - -static void call_logs_read_from_config_file(LinphoneCore *lc){ - char logsection[32]; - int i; - const char *tmp; - uint64_t sec; - LpConfig *cfg=lc->config; - for(i=0;;++i){ - snprintf(logsection,sizeof(logsection),"call_log_%i",i); - if (lp_config_has_section(cfg,logsection)){ - LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1); - cl->dir=lp_config_get_int(cfg,logsection,"dir",0); - cl->status=lp_config_get_int(cfg,logsection,"status",0); - tmp=lp_config_get_string(cfg,logsection,"from",NULL); - if (tmp) cl->from=linphone_address_new(tmp); - tmp=lp_config_get_string(cfg,logsection,"to",NULL); - if (tmp) cl->to=linphone_address_new(tmp); - sec=lp_config_get_int64(cfg,logsection,"start_date_time",0); - if (sec) { - /*new call log format with date expressed in seconds */ - cl->start_date_time=(time_t)sec; - set_call_log_date(cl,cl->start_date_time); - }else{ - tmp=lp_config_get_string(cfg,logsection,"start_date",NULL); - if (tmp) { - strncpy(cl->start_date,tmp,sizeof(cl->start_date)); - cl->start_date_time=string_to_time(cl->start_date); - } - } - cl->duration=lp_config_get_int(cfg,logsection,"duration",0); - tmp=lp_config_get_string(cfg,logsection,"refkey",NULL); - if (tmp) cl->refkey=ms_strdup(tmp); - cl->quality=lp_config_get_float(cfg,logsection,"quality",-1); - cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0); - tmp=lp_config_get_string(cfg,logsection,"call_id",NULL); - if (tmp) cl->call_id=ms_strdup(tmp); - lc->call_logs=ms_list_append(lc->call_logs,cl); - }else break; - } -} - - - -/** - * @addtogroup call_logs - * @{ -**/ - -/** - * Returns a human readable string describing the call. - * - * @note: the returned char* must be freed by the application (use ms_free()). -**/ -char * linphone_call_log_to_str(LinphoneCallLog *cl){ - char *status; - char *tmp; - char *from=linphone_address_as_string (cl->from); - char *to=linphone_address_as_string (cl->to); - switch(cl->status){ - case LinphoneCallAborted: - status=_("aborted"); - break; - case LinphoneCallSuccess: - status=_("completed"); - break; - case LinphoneCallMissed: - status=_("missed"); - break; - default: - status="unknown"; - } - tmp=ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"), - (cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"), - cl->start_date, - from, - to, - status, - cl->duration/60, - cl->duration%60); - ms_free(from); - ms_free(to); - return tmp; -} - -/** - * Returns RTP statistics computed locally regarding the call. - * -**/ -const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl){ - return &cl->local_stats; -} - -/** - * Returns RTP statistics computed by remote end and sent back via RTCP. - * - * @note Not implemented yet. -**/ -const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl){ - return &cl->remote_stats; -} - -const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl){ - return cl->call_id; -} - -/** - * Assign a user pointer to the call log. -**/ -void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){ - cl->user_pointer=up; -} - -/** - * Returns the user pointer associated with the call log. -**/ -void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl){ - return cl->user_pointer; -} - - - -/** - * Associate a persistent reference key to the call log. - * - * The reference key can be for example an id to an external database. - * It is stored in the config file, thus can survive to process exits/restarts. - * -**/ -void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){ - if (cl->refkey!=NULL){ - ms_free(cl->refkey); - cl->refkey=NULL; - } - if (refkey) cl->refkey=ms_strdup(refkey); -} - -/** - * Get the persistent reference key associated to the call log. - * - * The reference key can be for example an id to an external database. - * It is stored in the config file, thus can survive to process exits/restarts. - * -**/ -const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){ - return cl->refkey; -} - -/** - * Returns origin (ie from) address of the call. -**/ -LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl){ - return cl->from; -} - -/** - * Returns destination address (ie to) of the call. -**/ -LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl){ - return cl->to; -} - -/** - * Returns remote address (that is from or to depending on call direction). -**/ -LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl){ - return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to; -} - -/** - * Returns the direction of the call. -**/ -LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){ - return cl->dir; -} - -/** - * Returns the status of the call. -**/ -LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){ - return cl->status; -} - -/** - * Returns the start date of the call, expressed as a POSIX time_t. -**/ -time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){ - return cl->start_date_time; -} - -/** - * Returns duration of the call. -**/ -int linphone_call_log_get_duration(LinphoneCallLog *cl){ - return cl->duration; -} - -/** - * Returns overall quality indication of the call. -**/ -float linphone_call_log_get_quality(LinphoneCallLog *cl){ - return cl->quality; -} - -/** @} */ - -void linphone_call_log_destroy(LinphoneCallLog *cl){ - if (cl->from!=NULL) linphone_address_destroy(cl->from); - if (cl->to!=NULL) linphone_address_destroy(cl->to); - if (cl->refkey!=NULL) ms_free(cl->refkey); - if (cl->call_id) ms_free(cl->call_id); - ms_free(cl); -} - /** * Returns TRUE if the LinphoneCall asked to autoanswer * @@ -401,10 +158,523 @@ const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _Lin return linphone_call_get_remote_address(call); } +static void linphone_core_log_collection_handler(OrtpLogLevel level, const char *fmt, va_list args); + +void linphone_core_set_log_handler(OrtpLogFunc logfunc) { + if (ortp_logv_out == linphone_core_log_collection_handler) { + ms_message("There is already a log collection handler, keep it"); + liblinphone_log_func = logfunc; + } else + ortp_set_log_handler(logfunc); +} + +void linphone_core_set_log_file(FILE *file) { + if (file == NULL) file = stdout; + ortp_set_log_file(file); +} + +void linphone_core_set_log_level(OrtpLogLevel loglevel) { + OrtpLogLevel mask = loglevel; + switch (loglevel) { + case ORTP_TRACE: + case ORTP_DEBUG: + mask |= ORTP_DEBUG; + case ORTP_MESSAGE: + mask |= ORTP_MESSAGE; + case ORTP_WARNING: + mask |= ORTP_WARNING; + case ORTP_ERROR: + mask |= ORTP_ERROR; + case ORTP_FATAL: + mask |= ORTP_FATAL; + break; + case ORTP_LOGLEV_END: + break; + } + linphone_core_set_log_level_mask(mask); +} + +void linphone_core_set_log_level_mask(OrtpLogLevel loglevel) { + ortp_set_log_level_mask(loglevel); + if (loglevel == 0) { + sal_disable_log(); + } else { + sal_enable_log(); + } +} + +static void linphone_core_log_collection_handler(OrtpLogLevel level, const char *fmt, va_list args) { + const char *lname="undef"; + char *msg; + char *log_filename1; + char *log_filename2; + FILE *log_file; + struct timeval tp; + struct tm *lt; + time_t tt; + struct stat statbuf; + + if (liblinphone_log_func != NULL) { +#ifndef _WIN32 + va_list args_copy; + va_copy(args_copy, args); + liblinphone_log_func(level, fmt, args_copy); + va_end(args_copy); +#else + /* This works on 32 bits, luckily. */ + /* TODO: va_copy is available in Visual Studio 2013. */ + liblinphone_log_func(level, fmt, args); +#endif + } + + ortp_gettimeofday(&tp, NULL); + tt = (time_t)tp.tv_sec; + lt = localtime((const time_t*)&tt); + switch(level){ + case ORTP_DEBUG: + lname = "DEBUG"; + break; + case ORTP_MESSAGE: + lname = "MESSAGE"; + break; + case ORTP_WARNING: + lname = "WARNING"; + break; + case ORTP_ERROR: + lname = "ERROR"; + break; + case ORTP_FATAL: + lname = "FATAL"; + break; + default: + ortp_fatal("Bad level !"); + } + msg = ortp_strdup_vprintf(fmt, args); + + log_filename1 = ortp_strdup_printf("%s/%s1.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + log_filename2 = ortp_strdup_printf("%s/%s2.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + ortp_mutex_lock(&liblinphone_log_collection_mutex); + log_file = fopen(log_filename1, "a"); + fstat(fileno(log_file), &statbuf); + if (statbuf.st_size > liblinphone_log_collection_max_file_size) { + fclose(log_file); + log_file = fopen(log_filename2, "a"); + fstat(fileno(log_file), &statbuf); + if (statbuf.st_size > liblinphone_log_collection_max_file_size) { + fclose(log_file); + unlink(log_filename1); + rename(log_filename2, log_filename1); + log_file = fopen(log_filename2, "a"); + } + } + fprintf(log_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s %s\n", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), lname, msg); + fflush(log_file); + fclose(log_file); + ortp_mutex_unlock(&liblinphone_log_collection_mutex); + + ortp_free(log_filename1); + ortp_free(log_filename2); + ortp_free(msg); +} + +const char * linphone_core_get_log_collection_path(void) { + if (liblinphone_log_collection_path != NULL) { + return liblinphone_log_collection_path; + } + return LOG_COLLECTION_DEFAULT_PATH; +} + +void linphone_core_set_log_collection_path(const char *path) { + if (liblinphone_log_collection_path != NULL) { + ms_free(liblinphone_log_collection_path); + liblinphone_log_collection_path = NULL; + } + if (path != NULL) { + liblinphone_log_collection_path = ms_strdup(path); + } +} + +const char * linphone_core_get_log_collection_prefix(void) { + if (liblinphone_log_collection_prefix != NULL) { + return liblinphone_log_collection_prefix; + } + return LOG_COLLECTION_DEFAULT_PREFIX; +} + +void linphone_core_set_log_collection_prefix(const char *prefix) { + if (liblinphone_log_collection_prefix != NULL) { + ms_free(liblinphone_log_collection_prefix); + liblinphone_log_collection_prefix = NULL; + } + if (prefix != NULL) { + liblinphone_log_collection_prefix = ms_strdup(prefix); + } +} + +int linphone_core_get_log_collection_max_file_size(void) { + return liblinphone_log_collection_max_file_size; +} + +void linphone_core_set_log_collection_max_file_size(int size) { + liblinphone_log_collection_max_file_size = size; +} + +const char *linphone_core_get_log_collection_upload_server_url(LinphoneCore *core) { + return lp_config_get_string(core->config, "misc", "log_collection_upload_server_url", NULL); +} + +void linphone_core_set_log_collection_upload_server_url(LinphoneCore *core, const char *server_url) { + lp_config_set_string(core->config, "misc", "log_collection_upload_server_url", server_url); +} + +LinphoneLogCollectionState linphone_core_log_collection_enabled(void) { + return liblinphone_log_collection_state; +} + +void linphone_core_enable_log_collection(LinphoneLogCollectionState state) { + if (liblinphone_log_collection_state == state) return; + + /* at first call of this function, set liblinphone_log_func to the current + * ortp log function */ + if( liblinphone_log_func == NULL ){ + liblinphone_log_func = ortp_logv_out; + } + liblinphone_log_collection_state = state; + if (state != LinphoneLogCollectionDisabled) { + ortp_mutex_init(&liblinphone_log_collection_mutex, NULL); + if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) { + liblinphone_log_func = NULL; + } else { + liblinphone_log_func = ortp_logv_out; + } + ortp_set_log_handler(linphone_core_log_collection_handler); + } else { + ortp_set_log_handler(liblinphone_log_func); + } +} + +static void clean_log_collection_upload_context(LinphoneCore *lc) { + char *filename = ms_strdup_printf("%s/%s_log.%s", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX, + COMPRESSED_LOG_COLLECTION_EXTENSION); + unlink(filename); + ms_free(filename); + if (lc && lc->log_collection_upload_information) { + ms_free(lc->log_collection_upload_information); + lc->log_collection_upload_information=NULL; + } +} + +static void process_io_error_upload_log_collection(void *data, const belle_sip_io_error_event_t *event) { + LinphoneCore *core = (LinphoneCore *)data; + ms_error("I/O Error during log collection upload to %s", linphone_core_get_log_collection_upload_server_url(core)); + linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "I/O Error"); + clean_log_collection_upload_context(core); +} + +static void process_auth_requested_upload_log_collection(void *data, belle_sip_auth_event_t *event) { + LinphoneCore *core = (LinphoneCore *)data; + ms_error("Error during log collection upload: auth requested to connect %s", linphone_core_get_log_collection_upload_server_url(core)); + linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Auth requested"); + clean_log_collection_upload_context(core); +} + +/** + * Callback called when posting a log collection file to server (following rcs5.1 recommendation) + * + * @param[in] bh The body handler + * @param[in] msg The belle sip message + * @param[in] data The user data associated with the handler, contains the LinphoneCore object + * @param[in] offset The current position in the input buffer + * @param[in] buffer The ouput buffer where to copy the data to be uploaded + * @param[in,out] size The size in byte of the data requested, as output it will contain the effective copied size + * + */ +static int log_collection_upload_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size) { + LinphoneCore *core = (LinphoneCore *)data; + + /* If we've not reach the end of file yet, fill the buffer with more data */ + if (offset < linphone_content_get_size(core->log_collection_upload_information)) { + char *log_filename = ms_strdup_printf("%s/%s_log.%s", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX, + COMPRESSED_LOG_COLLECTION_EXTENSION); +#ifdef HAVE_ZLIB + FILE *log_file = fopen(log_filename, "rb"); +#else + FILE *log_file = fopen(log_filename, "r"); +#endif + if (fseek(log_file, offset, SEEK_SET)) { + ms_error("Cannot seek file [%s] at position [%lu] errno [%s]",log_filename,(unsigned long)offset,strerror(errno)); + + } else { + *size = fread(buffer, 1, *size, log_file); + } + fclose(log_file); + ms_free(log_filename); + return BELLE_SIP_CONTINUE; + } else { + *size=0; + return BELLE_SIP_STOP; + } + + +} + +/** + * Callback called during upload of a log collection to server. + * It is just forwarding the call and some parameters to the vtable defined callback. + */ +static void log_collection_upload_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total) { + LinphoneCore *core = (LinphoneCore *)data; + linphone_core_notify_log_collection_upload_progress_indication(core, offset, total); +} + +/** + * Callback function called when we have a response from server during the upload of the log collection to the server (rcs5.1 recommandation) + * Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server + * to upload the file. The server response to this second post is processed by this same function + * + * @param[in] data The user-defined pointer associated with the request, it contains the LinphoneCore object + * @param[in] event The response from server + */ +static void process_response_from_post_file_log_collection(void *data, const belle_http_response_event_t *event) { + LinphoneCore *core = (LinphoneCore *)data; + + /* Check the answer code */ + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 204) { /* This is the reply to the first post to the server - an empty file */ + /* Start uploading the file */ + belle_http_request_listener_callbacks_t cbs = { 0 }; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + belle_sip_multipart_body_handler_t *bh; + char* ua; + char *first_part_header; + belle_sip_user_body_handler_t *first_part_bh; + + linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateInProgress, NULL); + + /* Temporary storage for the Content-disposition header value */ + first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information)); + + /* Create a user body handler to take care of the file and add the content disposition and content-type headers */ + first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, log_collection_upload_on_send_body, core); + belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header)); + belle_sip_free(first_part_header); + belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, + (belle_sip_header_t *)belle_sip_header_content_type_create(linphone_content_get_type(core->log_collection_upload_information), linphone_content_get_subtype(core->log_collection_upload_information))); + + /* Insert it in a multipart body handler which will manage the boundaries of multipart message */ + bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh); + ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); + uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core)); + req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL); + ms_free(ua); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh)); + cbs.process_response = process_response_from_post_file_log_collection; + cbs.process_io_error = process_io_error_upload_log_collection; + cbs.process_auth_requested = process_auth_requested_upload_log_collection; + l = belle_http_request_listener_create_from_callbacks(&cbs, core); + belle_http_provider_send_request(core->http_provider, req, l); + } + if (code == 200) { /* The file has been uploaded correctly, get the server reply */ + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + xmlChar *file_url = NULL; + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + xmlMessageBody = xmlParseDoc((const xmlChar *)body); + cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + cur=cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + if (file_url != NULL) { + linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateDelivered, (const char *)file_url); + } + clean_log_collection_upload_context(core); + } + } +} + +#ifdef HAVE_ZLIB +#define COMPRESS_FILE_PTR gzFile +#define COMPRESS_OPEN gzopen +#define COMPRESS_CLOSE gzclose +#else +#define COMPRESS_FILE_PTR FILE* +#define COMPRESS_OPEN fopen +#define COMPRESS_CLOSE fclose +#endif + +/** + * If zlib is not available the two log files are simply concatenated. + */ +static int compress_file(FILE *input_file, COMPRESS_FILE_PTR output_file) { + char buffer[131072]; /* 128kB */ + int bytes; + + while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) { + if (bytes < 0) return bytes; +#ifdef HAVE_ZLIB + bytes = gzwrite(output_file, buffer, bytes); +#else + bytes = fwrite(buffer, 1, bytes, output_file); +#endif + if (bytes < 0) return bytes; + } + return 0; +} + +static int prepare_log_collection_file_to_upload(const char *filename) { + char *input_filename = NULL; + char *output_filename = NULL; + FILE *input_file = NULL; + COMPRESS_FILE_PTR output_file = NULL; + int ret = 0; + + ortp_mutex_lock(&liblinphone_log_collection_mutex); + output_filename = ms_strdup_printf("%s/%s", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename); + output_file = COMPRESS_OPEN(output_filename, "w"); + if (output_file == NULL) goto error; + input_filename = ms_strdup_printf("%s/%s1.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + input_file = fopen(input_filename, "r"); + if (input_file == NULL) goto error; + ret = compress_file(input_file, output_file); + if (ret < 0) goto error; + fclose(input_file); + ms_free(input_filename); + input_filename = ms_strdup_printf("%s/%s2.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + input_file = fopen(input_filename, "r"); + if (input_file != NULL) { + ret = compress_file(input_file, output_file); + if (ret < 0) goto error; + } + +error: + if (input_file != NULL) fclose(input_file); + if (output_file != NULL) COMPRESS_CLOSE(output_file); + if (input_filename != NULL) ms_free(input_filename); + if (output_filename != NULL) ms_free(output_filename); + ortp_mutex_unlock(&liblinphone_log_collection_mutex); + return ret; +} + +static size_t get_size_of_file_to_upload(const char *filename) { + struct stat statbuf; + char *output_filename = ms_strdup_printf("%s/%s", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename); + FILE *output_file = fopen(output_filename, "rb"); + fstat(fileno(output_file), &statbuf); + fclose(output_file); + ms_free(output_filename); + return statbuf.st_size; +} + +void linphone_core_upload_log_collection(LinphoneCore *core) { + if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) { + /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ + belle_http_request_listener_callbacks_t cbs = { 0 }; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + char *name; + + core->log_collection_upload_information = (LinphoneContent *)malloc(sizeof(LinphoneContent)); + memset(core->log_collection_upload_information, 0, sizeof(LinphoneContent)); +#ifdef HAVE_ZLIB + linphone_content_set_type(core->log_collection_upload_information, "application"); + linphone_content_set_subtype(core->log_collection_upload_information, "gzip"); +#else + linphone_content_set_type(core->log_collection_upload_information, "text"); + linphone_content_set_subtype(core->log_collection_upload_information,"plain"); +#endif + name = ms_strdup_printf("%s_log.%s", + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX, + COMPRESSED_LOG_COLLECTION_EXTENSION); + linphone_content_set_name(core->log_collection_upload_information, name); + if (prepare_log_collection_file_to_upload(name) < 0) return; + linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name)); + uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core)); + req = belle_http_request_create("POST", uri, NULL, NULL, NULL); + cbs.process_response = process_response_from_post_file_log_collection; + cbs.process_io_error = process_io_error_upload_log_collection; + cbs.process_auth_requested = process_auth_requested_upload_log_collection; + l = belle_http_request_listener_create_from_callbacks(&cbs, core); + belle_http_provider_send_request(core->http_provider, req, l); + ms_free(name); + } +} + +char * linphone_core_compress_log_collection() { + char *filename = NULL; + if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) return NULL; + filename = ms_strdup_printf("%s_log.%s", + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX, + COMPRESSED_LOG_COLLECTION_EXTENSION); + if (prepare_log_collection_file_to_upload(filename) < 0) { + ms_free(filename); + return NULL; + } + ms_free(filename); + return ms_strdup_printf("%s/%s_log.%s", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX, + COMPRESSED_LOG_COLLECTION_EXTENSION); +} + +void linphone_core_reset_log_collection() { + char *filename; + ortp_mutex_lock(&liblinphone_log_collection_mutex); + clean_log_collection_upload_context(NULL); + filename = ms_strdup_printf("%s/%s1.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + unlink(filename); + ms_free(filename); + filename = ms_strdup_printf("%s/%s2.log", + liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, + liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX); + unlink(filename); + ms_free(filename); + ortp_mutex_unlock(&liblinphone_log_collection_mutex); +} + /** * Enable logs in supplied FILE*. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_file and #linphone_core_set_log_level instead. * * @param file a C FILE* where to fprintf logs. If null stdout is used. * @@ -412,30 +682,36 @@ const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _Lin 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); + linphone_core_set_log_level(ORTP_MESSAGE); } /** * Enable logs through the user's supplied log callback. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_handler and #linphone_core_set_log_level instead. * * @param logfunc The address of a OrtpLogFunc callback whose protoype is * typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args); * **/ 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); + linphone_core_set_log_level(ORTP_MESSAGE); + linphone_core_set_log_handler(logfunc); } /** * Entirely disable logging. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_level instead. **/ -void linphone_core_disable_logs(){ - ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); +void linphone_core_disable_logs(void){ + linphone_core_set_log_level(ORTP_ERROR); +} + +void linphone_core_serialize_logs(void) { + liblinphone_serialize_logs = TRUE; } @@ -454,15 +730,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",0); + 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){ @@ -491,8 +772,25 @@ static void sound_config_read(LinphoneCore *lc) /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); if (devid){ - MSSndCard *card=ms_alsa_card_new_custom(devid,devid); - ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + MSSndCard* card; + const char* delim=","; + size_t l=strlen(devid); + char* d=malloc(l+1); + char* i; + memcpy(d,devid,l+1); + for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){ + char s=*i; + *i='\0'; + card=ms_alsa_card_new_custom(d+l,d+l); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + *i=s; + l=i-d+1; + } + if(d[l]!='\0') { + card=ms_alsa_card_new_custom(d+l,d+l); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + } + free(d); } tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1); if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp); @@ -544,9 +842,8 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_set_ringback(lc,tmpbuf); linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC)); - check_sound_device(lc); lc->sound_conf.latency=0; -#ifndef __ios +#ifndef __ios tmp=TRUE; #else tmp=FALSE; /* on iOS we have builtin echo cancellation.*/ @@ -565,6 +862,27 @@ static void sound_config_read(LinphoneCore *lc) /*just parse requested stream feature once at start to print out eventual errors*/ linphone_core_get_audio_features(lc); + + _linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); +} + +static void certificates_config_read(LinphoneCore *lc) +{ + const char *rootca; +#ifdef __linux + struct stat sb; + rootca=lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs"); + if (stat("/etc/ssl/certs", &sb) != 0 || !S_ISDIR(sb.st_mode)) + { + ms_warning("/etc/ssl/certs not found, using %s instead", ROOT_CA_FILE); + rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE); + } +#else + rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE); +#endif + linphone_core_set_root_ca(lc,rootca); + linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); + linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); } static void sip_config_read(LinphoneCore *lc) @@ -574,22 +892,13 @@ static void sip_config_read(LinphoneCore *lc) LCSipTransports tr; int i,tmp; int ipv6; - int random_port; - - tmp=lp_config_get_int(lc->config,"sip","use_info",0); - linphone_core_set_use_info_for_dtmf(lc,tmp); if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); } + sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0)); 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)); - - tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",1); - linphone_core_set_use_rfc2833_for_dtmf(lc,tmp); ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); if (ipv6==-1){ @@ -597,41 +906,17 @@ static void sip_config_read(LinphoneCore *lc) } linphone_core_enable_ipv6(lc,ipv6); memset(&tr,0,sizeof(tr)); - - tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",0); - 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")); -#else - sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); -#endif - linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); - linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); + tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060); + tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060); + /*we are not listening inbound connection for tls, port has no meaning*/ + tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM); + + certificates_config_read(lc); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); /*start listening on ports*/ - linphone_core_set_sip_transports(lc,&tr); + linphone_core_set_sip_transports(lc,&tr); tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL); if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) { @@ -655,21 +940,24 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); + tmp=lp_config_get_int(lc->config,"sip","lime",FALSE); + linphone_core_enable_lime(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); linphone_core_set_inc_timeout(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0); linphone_core_set_in_call_timeout(lc,tmp); - + tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4); linphone_core_set_delayed_timeout(lc,tmp); /* get proxies config */ for(i=0;; i++){ - LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i); + LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i); if (cfg!=NULL){ linphone_core_add_proxy_config(lc,cfg); + linphone_proxy_config_unref(cfg); }else{ break; } @@ -697,14 +985,18 @@ static void sip_config_read(LinphoneCore *lc) lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); lc->sip_conf.register_only_when_upnp_is_ok= lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); - lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); + lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0); lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000); lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); 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)); + sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1)); + lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1); + linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000)); + sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound")); + lc->sip_conf.save_auth_info = lp_config_get_int(lc->config, "sip", "save_auth_info", 1); } static void rtp_config_read(LinphoneCore *lc) @@ -714,6 +1006,8 @@ static void rtp_config_read(LinphoneCore *lc) int nortp_timeout; bool_t rtp_no_xmit_on_audio_mute; bool_t adaptive_jitt_comp_enabled; + const char* tmp; + int tmp_int; if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) { if (min_port <= 0) min_port = 1; @@ -746,14 +1040,37 @@ static void rtp_config_read(LinphoneCore *lc) linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE); linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); + lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE); + linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0)); + if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL))) + linphone_core_set_audio_multicast_addr(lc,tmp); + else + lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3"); + if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1) + linphone_core_enable_audio_multicast(lc,tmp_int); + if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0) + linphone_core_set_audio_multicast_ttl(lc,tmp_int); + else + lc->rtp_conf.audio_multicast_ttl=1;/*local network*/ + if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL))) + linphone_core_set_video_multicast_addr(lc,tmp); + else + lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3"); + if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1) + linphone_core_set_video_multicast_ttl(lc,tmp_int); + else + lc->rtp_conf.video_multicast_ttl=1;/*local network*/ + if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0) + linphone_core_enable_video_multicast(lc,tmp_int); } -static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ +static PayloadType * find_payload(const MSList *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ PayloadType *candidate=NULL; - int i; PayloadType *it; - for(i=0;inext){ + it=(PayloadType*)elem->data; if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0 && (clock_rate==it->clock_rate || clock_rate<=0) && (channels==it->channels || channels<=0) ){ @@ -775,7 +1092,28 @@ static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int c return candidate; } -static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadType **ret){ +static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const MSList* from) { + const MSList *elem; + for(elem=from;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if ((strcasecmp(type, payload_type_get_mime(pt)) == 0) + && (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate==pt->clock_rate) + && (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels==pt->channels)) { + return pt; + } + } + return NULL; +} + +static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type, const char *mime){ + if (type == SalVideo && lp_config_get_int(lc->config, "video", "rtp_io", FALSE)){ + return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/ + } + return ms_filter_codec_supported(mime); +} + + +static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){ char codeckey[50]; const char *mime,*fmtp; int rate,channels,enabled; @@ -783,7 +1121,7 @@ static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadTy LpConfig *config=lc->config; *ret=NULL; - snprintf(codeckey,50,"%s_%i",type,index); + snprintf(codeckey,50,"%s_codec_%i",type==SalAudio ? "audio" : "video", index); mime=lp_config_get_string(config,codeckey,"mime",NULL); if (mime==NULL || strlen(mime)==0 ) return FALSE; @@ -791,77 +1129,57 @@ static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadTy fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL); channels=lp_config_get_int(config,codeckey,"channels",0); enabled=lp_config_get_int(config,codeckey,"enabled",1); - pt=find_payload(lc->default_profile,mime,rate,channels,fmtp); - if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; - //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate); - if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported", - mime,rate,fmtp ? fmtp : ""); + if (!linphone_core_codec_supported(lc, type, mime)){ + ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate); + return TRUE; + } + pt=find_payload(type==SalAudio ? lc->default_audio_codecs : lc->default_video_codecs,mime,rate,channels,fmtp); + if (!pt){ + MSList **default_list=(type==SalAudio) ? &lc->default_audio_codecs : &lc->default_video_codecs; + if (type==SalAudio) + ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels); + else + ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate); + pt=payload_type_new(); + pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : PAYLOAD_VIDEO; + pt->mime_type=ortp_strdup(mime); + pt->clock_rate=rate; + pt->channels=channels; + payload_type_set_number(pt,-1); /*dynamic assignment*/ + payload_type_set_recv_fmtp(pt,fmtp); + *default_list=ms_list_append(*default_list, pt); + } + if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; + else pt->flags&=~PAYLOAD_TYPE_ENABLED; *ret=pt; return TRUE; } -#define RANK_END 10000 +/*this function merges the payload types from the codec default list with the list read from configuration file. + * If a new codec becomes supported in Liblinphone or if the list from configuration file is empty or incomplete, all the supported codecs are added + * automatically. This 'l' list is entirely destroyed and rewritten.*/ +static MSList *add_missing_codecs(const MSList *default_list, MSList *l){ + const MSList *elem; + MSList *newlist; -typedef struct codec_desc{ - const char *name; - int rate; -}codec_desc_t; - -static codec_desc_t codec_pref_order[]={ - {"SILK", 16000}, - {"speex", 16000}, - {"speex", 8000}, - {"pcmu",8000}, - {"pcma",8000}, - {"VP8",90000}, - {"H264",90000}, - {"MP4V-ES",90000}, - {NULL,0} -}; - -static int find_codec_rank(const char *mime, int clock_rate){ - int i; - 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; - } - return RANK_END; -} - -static int codec_compare(const PayloadType *a, const PayloadType *b){ - int ra,rb; - ra=find_codec_rank(a->mime_type,a->clock_rate); - rb=find_codec_rank(b->mime_type,b->clock_rate); - if (ra>rb) return 1; - if (radefault_profile,i); - if (pt){ - if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO) - pt=NULL; - else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED - && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){ - pt=NULL; - } - if (pt && ms_filter_codec_supported(pt->mime_type)){ - if (ms_list_find(l,pt)==NULL){ - /*unranked codecs are disabled by default*/ - if (find_codec_rank(pt->mime_type, pt->clock_rate)!=RANK_END){ - payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); - } - ms_message("Adding new codec %s/%i with fmtp %s", - pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : ""); - l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare); - } + for(elem=default_list; elem!=NULL; elem=elem->next){ + MSList *elem2=ms_list_find(l,elem->data); + if (!elem2){ + PayloadType *pt=(PayloadType*)elem->data; + /*this codec from default list should be inserted in the list*/ + if (!elem->prev){ + l=ms_list_prepend(l,pt); + }else{ + const MSList *after=ms_list_find(l,elem->prev->data); + l=ms_list_insert(l, after->next, pt); } + ms_message("Supported codec %s/%i fmtp=%s automatically added to codec list.", pt->mime_type, + pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : ""); } } - return l; + newlist=ms_list_copy_with_data(l,(void *(*)(void*))payload_type_clone); + ms_list_free(l); + return newlist; } static MSList *codec_append_if_new(MSList *l, PayloadType *pt){ @@ -881,22 +1199,27 @@ static void codecs_config_read(LinphoneCore *lc) PayloadType *pt; MSList *audio_codecs=NULL; MSList *video_codecs=NULL; - for (i=0;get_codec(lc,"audio_codec",i,&pt);i++){ + + lc->codecs_conf.dyn_pt=96; + lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101); + + for (i=0;get_codec(lc,SalAudio,i,&pt);i++){ if (pt){ - if (!ms_filter_codec_supported(pt->mime_type)){ - ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else audio_codecs=codec_append_if_new(audio_codecs,pt); + audio_codecs=codec_append_if_new(audio_codecs, pt); } } - audio_codecs=add_missing_codecs(lc,SalAudio,audio_codecs); - for (i=0;get_codec(lc,"video_codec",i,&pt);i++){ + if( lp_config_get_int(lc->config, "misc", "add_missing_audio_codecs", 1) == 1 ){ + audio_codecs=add_missing_codecs(lc->default_audio_codecs,audio_codecs); + } + + for (i=0;get_codec(lc,SalVideo,i,&pt);i++){ if (pt){ - if (!ms_filter_codec_supported(pt->mime_type)){ - ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else video_codecs=codec_append_if_new(video_codecs,(void *)pt); + video_codecs=codec_append_if_new(video_codecs, pt); } } - video_codecs=add_missing_codecs(lc,SalVideo,video_codecs); + if( lp_config_get_int(lc->config, "misc", "add_missing_video_codecs", 1) == 1 ){ + video_codecs=add_missing_codecs(lc->default_video_codecs,video_codecs); + } linphone_core_set_audio_codecs(lc,audio_codecs); linphone_core_set_video_codecs(lc,video_codecs); linphone_core_update_allocated_audio_bandwidth(lc); @@ -922,10 +1245,11 @@ static void build_video_devices_table(LinphoneCore *lc){ static void video_config_read(LinphoneCore *lc){ #ifdef VIDEO_ENABLED - int capture, display, self_view; + int capture, display, self_view, reuse_source; + int automatic_video=1; #endif - const char *str; -#ifdef VIDEO_ENABLED + const char *str; +#ifdef VIDEO_ENABLED LinphoneVideoPolicy vpol; memset(&vpol, 0, sizeof(LinphoneVideoPolicy)); #endif @@ -938,19 +1262,26 @@ static void video_config_read(LinphoneCore *lc){ linphone_core_set_preferred_video_size_by_name(lc, lp_config_get_string(lc->config,"video","size","cif")); + linphone_core_set_preview_video_size_by_name(lc, + lp_config_get_string(lc->config,"video","preview_size",NULL)); + + linphone_core_set_preferred_framerate(lc,lp_config_get_float(lc->config,"video","framerate",0)); + #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); + reuse_source=lp_config_get_int(lc->config,"video","reuse_source",0); + 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_enable_video_source_reuse(lc, reuse_source); linphone_core_set_video_policy(lc,&vpol); #endif } @@ -961,6 +1292,7 @@ static void ui_config_read(LinphoneCore *lc) int i; for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){ linphone_core_add_friend(lc,lf); + linphone_friend_unref(lf); } call_logs_read_from_config_file(lc); } @@ -986,400 +1318,363 @@ bool_t linphone_core_tunnel_available(void){ #endif } -/** - * Enable adaptive rate control. - * - * @ingroup media_parameters - * - * Adaptive rate control consists in using RTCP feedback provided information to dynamically - * control the output bitrate of the audio and video encoders, so that we can adapt to the network conditions and - * available bandwidth. Control of the audio encoder is done in case of audio-only call, and control of the video encoder is done for audio & video calls. - * Adaptive rate control feature is enabled by default. -**/ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){ lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled); } -/** - * Returns whether adaptive rate control is enabled. - * - * @ingroup media_parameters - * - * See linphone_core_enable_adaptive_rate_control(). -**/ bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE); } +void linphone_core_set_adaptive_rate_algorithm(LinphoneCore *lc, const char* algorithm){ + lp_config_set_string(lc->config,"net","adaptive_rate_algorithm",algorithm); +} + +const char * linphone_core_get_adaptive_rate_algorithm(const LinphoneCore *lc){ + return lp_config_get_string(lc->config, "net", "adaptive_rate_algorithm", "Simple"); +} + bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE); } -/** - * 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. - * - * @param lc the LinphoneCore object - * @param bw the bandwidth in kbits/s, 0 for infinite - */ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ lc->net_conf.download_bw=bw; + linphone_core_update_allocated_audio_bandwidth(lc); if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",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 - * configure audio & video codec's output bitrate. - * - * @param lc the LinphoneCore object - * @param bw the bandwidth in kbits/s, 0 for infinite - */ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ lc->net_conf.upload_bw=bw; + linphone_core_update_allocated_audio_bandwidth(lc); if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw); } -/** - * Retrieve the maximum available download bandwidth. - * - * @ingroup media_parameters - * - * This value was set by linphone_core_set_download_bandwidth(). - * -**/ +void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) { + sal_set_transport_timeout(lc->sal, timeout_ms); + if (linphone_core_ready(lc)) + lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms); +} + +int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) { + return sal_get_transport_timeout(lc->sal); +} + +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); +} + int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ return lc->net_conf.download_bw; } -/** - * Retrieve the maximum available upload bandwidth. - * - * @ingroup media_parameters - * - * This value was set by linphone_core_set_upload_bandwidth(). - * -**/ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; } -/** - * Set audio packetization time linphone expects to receive from peer. - * A value of zero means that ptime is not specified. - * @ingroup media_parameters - */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) { lp_config_set_int(lc->config,"rtp","download_ptime",ptime); } -/** - * Get audio packetization time linphone expects to receive from peer. - * A value of zero means that ptime is not specified. - * @ingroup media_parameters - */ int linphone_core_get_download_ptime(LinphoneCore *lc) { return lp_config_get_int(lc->config,"rtp","download_ptime",0); } -/** - * Set audio packetization time linphone will send (in absence of requirement from peer) - * A value of 0 stands for the current codec default packetization time. - * - * @ingroup media_parameters -**/ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ lp_config_set_int(lc->config,"rtp","upload_ptime",ptime); } -/** - * Set audio packetization time linphone will send (in absence of requirement from peer) - * A value of 0 stands for the current codec default packetization time. - * - * - * @ingroup media_parameters -**/ int linphone_core_get_upload_ptime(LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","upload_ptime",0); } - - -/** - * Returns liblinphone's version as a string. - * - * @ingroup misc - * -**/ const char * linphone_core_get_version(void){ return liblinphone_version; } -static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){ - PayloadType *pt; - pt=payload_type_clone(const_pt); - if (number==-1){ - /*look for a free number */ - MSList *elem; - int i; - for(i=lc->dyn_pt;ipayload_types;elem!=NULL;elem=elem->next){ - PayloadType *it=(PayloadType*)elem->data; - if (payload_type_get_number(it)==i){ - already_assigned=TRUE; - break; - } - } - if (!already_assigned){ - number=i; - lc->dyn_pt=i+1; - break; - } - } - if (number==-1){ - ms_fatal("FIXME: too many codecs, no more free numbers."); - } +static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){ + MSList **codec_list=const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : &lc->default_audio_codecs; + if (linphone_core_codec_supported(lc, (const_pt->type == PAYLOAD_VIDEO) ? SalVideo : SalAudio, const_pt->mime_type)){ + PayloadType *pt=payload_type_clone(const_pt); + int number=-1; + payload_type_set_enable(pt,enabled); + if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp); + /*Set a number to the payload type from the statically defined (RFC3551) profile, if not static, -1 is returned + and the payload type number will be determined dynamically later, at call time.*/ + payload_type_set_number(pt, + (number=rtp_profile_find_payload_number(&av_profile, pt->mime_type, pt->clock_rate, pt->channels)) + ); + ms_message("Codec %s/%i fmtp=[%s] number=%i, enabled=%i) added to default capabilities.", pt->mime_type, pt->clock_rate, + pt->recv_fmtp ? pt->recv_fmtp : "", number, (int)payload_type_enabled(pt)); + *codec_list=ms_list_append(*codec_list,pt); } - ms_message("assigning %s/%i payload type number %i",pt->mime_type,pt->clock_rate,number); - payload_type_set_number(pt,number); - if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp); - rtp_profile_set_payload(lc->default_profile,number,pt); - lc->payload_types=ms_list_append(lc->payload_types,pt); } -static void linphone_core_handle_static_payloads(LinphoneCore *lc){ +static void linphone_core_register_static_payloads(LinphoneCore *lc){ RtpProfile *prof=&av_profile; int i; for(i=0;itype==PAYLOAD_VIDEO) continue; +#endif + if (find_payload_type_from_list( + pt->mime_type, pt->clock_rate, pt->type!=PAYLOAD_VIDEO ? pt->channels : LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS, + pt->type==PAYLOAD_VIDEO ? lc->default_video_codecs : lc->default_audio_codecs)==NULL){ + linphone_core_register_payload_type(lc,pt,NULL,FALSE); } } } } static void linphone_core_free_payload_types(LinphoneCore *lc){ - rtp_profile_clear_all(lc->default_profile); - rtp_profile_destroy(lc->default_profile); - ms_list_for_each(lc->payload_types,(void (*)(void*))payload_type_destroy); - ms_list_free(lc->payload_types); - lc->payload_types=NULL; + ms_list_free_with_data(lc->default_audio_codecs, (void (*)(void*))payload_type_destroy); + ms_list_free_with_data(lc->default_video_codecs, (void (*)(void*))payload_type_destroy); } void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){ lc->state=gstate; - if (lc->vtable.global_state_changed){ - lc->vtable.global_state_changed(lc,gstate,message); - } + linphone_core_notify_global_state_changed(lc,gstate,message); } -static void misc_config_read (LinphoneCore *lc) { + +static void misc_config_read(LinphoneCore *lc) { LpConfig *config=lc->config; - 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); + const char *uuid; + + lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",30); + 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); + + lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path",".")); } - - - -static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, - const char *factory_config_path, void * userdata) -{ - ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); - memset (lc, 0, sizeof (LinphoneCore)); - lc->data=userdata; - lc->ringstream_autorelease=TRUE; - - memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable)); - - linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); - ortp_init(); - lc->dyn_pt=96; - lc->default_profile=rtp_profile_new("default profile"); - linphone_core_assign_payload_type(lc,&payload_type_pcmu8000,0,NULL); - linphone_core_assign_payload_type(lc,&payload_type_gsm,3,NULL); - linphone_core_assign_payload_type(lc,&payload_type_pcma8000,8,NULL); - linphone_core_assign_payload_type(lc,&payload_type_speex_nb,110,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_speex_wb,111,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_speex_uwb,112,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-11"); - linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL); - -#if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED) - /*shorten the DNS lookup time and send more retransmissions on mobiles: - - to workaround potential packet losses - - to avoid hanging for 30 seconds when the network doesn't work despite the phone thinks it does. - */ - _linphone_core_configure_resolver(); -#endif - -#ifdef ENABLE_NONSTANDARD_GSM - { - PayloadType *pt; - pt=payload_type_clone(&payload_type_gsm); - pt->clock_rate=11025; - linphone_core_assign_payload_type(lc,pt,-1,NULL); - pt->clock_rate=22050; - linphone_core_assign_payload_type(lc,pt,-1,NULL); - payload_type_destroy(pt); - } -#endif - -#ifdef VIDEO_ENABLED - 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"); - 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_vp8,103,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");*/ -#endif - - /*add all payload type for which we don't care about the number */ - linphone_core_assign_payload_type(lc,&payload_type_ilbc,-1,"mode=30"); - linphone_core_assign_payload_type(lc,&payload_type_amr,-1,"octet-align=1"); - linphone_core_assign_payload_type(lc,&payload_type_amrwb,-1,"octet-align=1"); - linphone_core_assign_payload_type(lc,&payload_type_lpc1015,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_16,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_24,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_32,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g726_40,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_16,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_24,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_32,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_40,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_nb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_mb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_wb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_silk_swb,-1,NULL); - linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); - linphone_core_handle_static_payloads(lc); - - ms_init(); - /* create a mediastreamer2 event queue and set it as global */ - /* This allows to run event's callback in linphone_core_iterate() */ - lc->msevq=ms_event_queue_new(); - ms_set_global_event_queue(lc->msevq); - - lc->config=lp_config_new(config_path); - if (factory_config_path) - lp_config_read_file(lc->config,factory_config_path); - - lc->sal=sal_init(); - sal_set_user_pointer(lc->sal,lc); - sal_set_callbacks(lc->sal,&linphone_sal_callbacks); - - lc->network_last_check = 0; - lc->network_last_status = FALSE; - +static void linphone_core_start(LinphoneCore * lc) { sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); rtp_config_read(lc); codecs_config_read(lc); - sip_config_read(lc); /* this will start eXosip*/ + sip_config_read(lc); 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 - lc->tunnel=linphone_core_tunnel_new(lc); - if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); + if (lc->tunnel) { + linphone_tunnel_configure(lc->tunnel); + } #endif - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Ready")); + + linphone_core_notify_display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } -/** - * Instanciates a LinphoneCore object. - * @ingroup initializing - * - * The LinphoneCore object is the primary handle for doing all phone actions. - * It should be unique within your application. - * @param vtable a LinphoneCoreVTable structure holding your application callbacks - * @param config_path a path to a config file. If it does not exists it will be created. - * The config file is used to store all settings, call logs, friends, proxies... so that all these settings - * become persistent over the life of the LinphoneCore object. - * It is allowed to set a NULL config file. In that case LinphoneCore will not store any settings. - * @param factory_config_path a path to a read-only config file that can be used to - * to store hard-coded preference such as proxy settings or internal preferences. - * The settings in this factory file always override the one in the normal config file. - * It is OPTIONAL, use NULL if unneeded. - * @param userdata an opaque user pointer that can be retrieved at any time (for example in - * callbacks) using linphone_core_get_user_data(). - * -**/ +void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { + linphone_core_notify_configuring_status(lc, state, message); + + if (state == LinphoneConfiguringSuccessful) { + if (linphone_core_is_provisioning_transient(lc) == TRUE) + linphone_core_set_provisioning_uri(lc, NULL); + } + + linphone_core_start(lc); +} + + +static int linphone_core_serialization_ref = 0; + +static void linphone_core_activate_log_serialization_if_needed(void) { + if (liblinphone_serialize_logs == TRUE) { + linphone_core_serialization_ref++; + if (linphone_core_serialization_ref == 1) + ortp_set_log_thread_id(ortp_thread_self()); + } +} + +static void linphone_core_deactivate_log_serialization_if_needed(void) { + if (liblinphone_serialize_logs == TRUE) { + --linphone_core_serialization_ref; + if (linphone_core_serialization_ref == 0) + ortp_set_log_thread_id(0); + } +} + +static void linphone_core_register_default_codecs(LinphoneCore *lc){ + const char *aac_fmtp162248, *aac_fmtp3244; + bool_t opus_enabled=TRUE; + /*default enabled audio codecs, in order of preference*/ +#if defined(__arm__) || defined(_M_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 (ms_get_cpu_count()==1) opus_enabled=FALSE; +#endif + linphone_core_register_payload_type(lc,&payload_type_opus,"useinbandfec=1",opus_enabled); + linphone_core_register_payload_type(lc,&payload_type_silk_wb,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_speex_wb,"vbr=on",TRUE); + linphone_core_register_payload_type(lc,&payload_type_speex_nb,"vbr=on",TRUE); + linphone_core_register_payload_type(lc,&payload_type_pcmu8000,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_pcma8000,NULL,TRUE); + + /*other audio codecs, not enabled by default, in order of preference*/ + linphone_core_register_payload_type(lc,&payload_type_gsm,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g722,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_ilbc,"mode=30",FALSE); + linphone_core_register_payload_type(lc,&payload_type_amr,"octet-align=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_amrwb,"octet-align=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_g729,"annexb=no",FALSE); + /* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported + * for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */ + if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) { + ms_message("Using SBR for AAC"); + aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; + aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1"; + } else { + aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; + aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"; + } + linphone_core_register_payload_type(lc,&payload_type_aaceld_16k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_22k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_32k,aac_fmtp3244,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_44k,aac_fmtp3244,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aaceld_48k,aac_fmtp162248,FALSE); + linphone_core_register_payload_type(lc,&payload_type_isac,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_speex_uwb,"vbr=on",FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_nb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_mb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_silk_swb,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_16,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_24,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_32,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_g726_40,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_16,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE); + linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE); + + + + +#ifdef VIDEO_ENABLED + /*default enabled video codecs, in order of preference*/ + linphone_core_register_payload_type(lc,&payload_type_vp8,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_h264,"profile-level-id=42801F",TRUE); + linphone_core_register_payload_type(lc,&payload_type_mp4v,"profile-level-id=3",TRUE); + linphone_core_register_payload_type(lc,&payload_type_h263_1998,"CIF=1;QCIF=1",FALSE); + linphone_core_register_payload_type(lc,&payload_type_h263,NULL,FALSE); +#endif + /*register all static payload types declared in av_profile of oRTP, if not already declared above*/ + linphone_core_register_static_payloads(lc); +} + +static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata){ + const char *remote_provisioning_uri = NULL; + LinphoneCoreVTable* local_vtable= linphone_core_v_table_new(); + ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); + + lc->config=lp_config_ref(config); + lc->data=userdata; + lc->ringstream_autorelease=TRUE; + linphone_task_list_init(&lc->hooks); + + memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable)); + _linphone_core_add_listener(lc, local_vtable, TRUE); + + linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); + ortp_init(); + linphone_core_activate_log_serialization_if_needed(); + + ms_init(); + + linphone_core_register_default_codecs(lc); + /* Get the mediastreamer2 event queue */ + /* This allows to run event's callback in linphone_core_iterate() */ + lc->msevq=ms_factory_get_event_queue(ms_factory_get_fallback()); + + lc->sal=sal_init(); + + sal_set_user_pointer(lc->sal,lc); + sal_set_callbacks(lc->sal,&linphone_sal_callbacks); + +#ifdef TUNNEL_ENABLED + lc->tunnel=linphone_core_tunnel_new(lc); +#endif + + lc->network_last_check = 0; + lc->network_last_status = FALSE; + + lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0"); + lc->http_verify_policy = belle_tls_verify_policy_new(); + belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy); + + certificates_config_read(lc); + + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); + if (remote_provisioning_uri == NULL) { + linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); + } // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate) +} + LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { - LinphoneCore *core=ms_new(LinphoneCore,1); - linphone_core_init(core,vtable,config_path, factory_config_path, userdata); + LinphoneCore *lc; + LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path); + lc=linphone_core_new_with_config(vtable, config, userdata); + lp_config_unref(config); + return lc; +} + +LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) +{ + LinphoneCore *core = ms_new0(LinphoneCore, 1); + linphone_core_init(core, vtable, config, userdata); return core; } -/** - * Returns the list of available audio codecs. - * - * This list is unmodifiable. The ->data field of the MSList points a PayloadType - * structure holding the codec information. - * It is possible to make copy of the list with ms_list_copy() in order to modify it - * (such as the order of codecs). - * @ingroup media_parameters -**/ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) { return lc->codecs_conf.audio_codecs; } -/** - * Returns the list of available video codecs. - * - * This list is unmodifiable. The ->data field of the MSList points a PayloadType - * structure holding the codec information. - * It is possible to make copy of the list with ms_list_copy() in order to modify it - * (such as the order of codecs). - * @ingroup media_parameters -**/ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) { return lc->codecs_conf.video_codecs; } -/** - * Sets the local "from" identity. - * - * @ingroup proxies - * This data is used in absence of any proxy configuration or when no - * default proxy configuration is set. See LinphoneProxyConfig -**/ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) { LinphoneAddress *ctt; + if( lc->sip_conf.contact != NULL && strcmp(lc->sip_conf.contact, contact) == 0){ + /* changing for the same contact: no need to do anything */ + return 0; + } + if ((ctt=linphone_address_new(contact))==0) { ms_error("Bad contact url: %s",contact); return -1; } + if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact); lc->sip_conf.contact=ms_strdup(contact); + lp_config_set_string(lc->config, "sip", "contact", lc->sip_conf.contact); + + /* clean the guessed contact, we have to regenerate it */ if (lc->sip_conf.guessed_contact!=NULL){ ms_free(lc->sip_conf.guessed_contact); lc->sip_conf.guessed_contact=NULL; @@ -1389,28 +1684,6 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) } -/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ -void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ - const char *ip; - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress - && (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){ - strncpy(result,ip,LINPHONE_IPADDR_SIZE); - return; - } -#ifdef BUILD_UPNP - else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { - ip = linphone_upnp_context_get_external_ipaddress(lc->upnp); - strncpy(result,ip,LINPHONE_IPADDR_SIZE); - return; - } -#endif //BUILD_UPNP - if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0) - return; - /*else fallback to SAL routine that will attempt to find the most realistic interface */ - sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE); -} - static void update_primary_contact(LinphoneCore *lc){ char *guessed=NULL; char tmp[LINPHONE_IPADDR_SIZE]; @@ -1425,23 +1698,18 @@ static void update_primary_contact(LinphoneCore *lc){ ms_error("Could not parse identity contact !"); url=linphone_address_new("sip:unknown@unkwownhost"); } - linphone_core_get_local_ip(lc, NULL, tmp); + linphone_core_get_local_ip(lc, AF_UNSPEC, NULL, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); 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); } -/** - * Returns the default identity when no proxy configuration is used. - * - * @ingroup proxies -**/ const char *linphone_core_get_primary_contact(LinphoneCore *lc){ char *identity; @@ -1456,64 +1724,86 @@ const char *linphone_core_get_primary_contact(LinphoneCore *lc){ return identity; } -/** - * Tells LinphoneCore to guess local hostname automatically in primary contact. - * - * @ingroup proxies -**/ void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){ lc->sip_conf.guess_hostname=val; } -/** - * Returns TRUE if hostname part of primary contact is guessed automatically. - * - * @ingroup proxies -**/ bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){ return lc->sip_conf.guess_hostname; } -/** - * Same as linphone_core_get_primary_contact() but the result is a LinphoneAddress object - * instead of const char* - * - * @ingroup proxies -**/ +void linphone_core_enable_lime(LinphoneCore *lc, bool_t val){ + if (linphone_core_ready(lc)){ + lp_config_set_int(lc->config,"sip","lime",val); + } +} + +bool_t linphone_core_lime_enabled(const LinphoneCore *lc){ + return (lp_config_get_int(lc->config,"sip", "lime", FALSE) && lime_is_available()); +} + +bool_t linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc){ + return linphone_core_lime_enabled(lc) && (lp_config_get_int(lc->config,"sip", "lime_for_file_sharing", TRUE) && lime_is_available()); +} + LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){ return linphone_address_new(linphone_core_get_primary_contact(lc)); } /** * Sets the list of audio codecs. + * @param[in] lc The LinphoneCore object + * @param[in] codecs \mslist{PayloadType} + * @return 0 * * @ingroup media_parameters * The list is taken by the LinphoneCore thus the application should not free it. * This list is made of struct PayloadType describing the codec parameters. **/ -int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs) -{ +int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs){ if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs); lc->codecs_conf.audio_codecs=codecs; _linphone_core_codec_config_write(lc); + linphone_core_update_allocated_audio_bandwidth(lc); return 0; } /** * Sets the list of video codecs. + * @param[in] lc The LinphoneCore object + * @param[in] codecs \mslist{PayloadType} + * @return 0 * * @ingroup media_parameters * The list is taken by the LinphoneCore thus the application should not free it. * This list is made of struct PayloadType describing the codec parameters. **/ -int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs) -{ +int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs){ if (lc->codecs_conf.video_codecs!=NULL) ms_list_free(lc->codecs_conf.video_codecs); lc->codecs_conf.video_codecs=codecs; _linphone_core_codec_config_write(lc); return 0; } +/** + * Enable RFC3389 generic confort noise algorithm (CN payload type). + * It is disabled by default, because this algorithm is only relevant for legacy codecs (PCMU, PCMA, G722). + * @param lc the LinphoneCore + * @param enabled TRUE if enabled, FALSE otherwise. +**/ +void linphone_core_enable_generic_confort_noise(LinphoneCore *lc, bool_t enabled){ + lp_config_set_int(lc->config, "misc", "use_cn", enabled); +} + +/** + * Returns enablement of RFC3389 generic confort noise algorithm. + * @param lc the LinphoneCore + * @return TRUE or FALSE. +**/ +bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc){ + return lp_config_get_int(lc->config, "misc", "use_cn", FALSE); +} + const MSList * linphone_core_get_friend_list(const LinphoneCore *lc) { return lc->friends; @@ -1618,24 +1908,39 @@ bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc){ return lc->rtp_conf.rtp_no_xmit_on_audio_mute; } -/** - * Sets the nominal audio jitter buffer size in milliseconds. - * - * @ingroup media_parameters -**/ -void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value) -{ - lc->rtp_conf.audio_jitt_comp=value; +static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){ + LinphoneCall *call; + MSList *it; + for (it=lc->calls;it!=NULL;it=it->next){ + MediaStream *ms; + call=(LinphoneCall*)it->data; + ms = stype==MSAudio ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; + if (ms){ + RtpSession *s=ms->sessions.rtp_session; + if (s){ + if (value>0){ + ms_message("Jitter buffer size set to [%i] ms on call [%p]",value,call); + rtp_session_set_jitter_compensation(s,value); + rtp_session_enable_jitter_buffer(s,TRUE); + }else if (value==0){ + ms_warning("Jitter buffer is disabled per application request on call [%p]",call); + rtp_session_enable_jitter_buffer(s,FALSE); + } + } + } + } } -/** - * Sets the nominal video jitter buffer size in milliseconds. - * - * @ingroup media_parameters -**/ -void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value) +void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int milliseconds) { - lc->rtp_conf.video_jitt_comp=value; + lc->rtp_conf.audio_jitt_comp=milliseconds; + apply_jitter_value(lc, milliseconds, MSAudio); +} + +void linphone_core_set_video_jittcomp(LinphoneCore *lc, int milliseconds) +{ + lc->rtp_conf.video_jitt_comp=milliseconds; + apply_jitter_value(lc, milliseconds, MSVideo); } void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_xmit_on_audio_mute){ @@ -1644,6 +1949,8 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_ /** * Sets the UDP port used for audio streaming. + * A value if -1 will request the system to allocate the local port randomly. + * This is recommended in order to avoid firewall warnings. * * @ingroup network_parameters **/ @@ -1664,6 +1971,8 @@ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_ /** * Sets the UDP port used for video streaming. + * A value if -1 will request the system to allocate the local port randomly. + * This is recommended in order to avoid firewall warnings. * * @ingroup network_parameters **/ @@ -1698,7 +2007,7 @@ void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){ **/ bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) { - return lc->sip_conf.use_info; + return lp_config_get_int(lc->config, "sip", "use_info", 0); } /** @@ -1708,7 +2017,9 @@ bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) **/ void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) { - lc->sip_conf.use_info=use_info; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "sip", "use_info", use_info); + } } /** @@ -1718,7 +2029,7 @@ void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) **/ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) { - return lc->sip_conf.use_rfc2833; + return lp_config_get_int(lc->config, "sip", "use_rfc2833", 1); } /** @@ -1728,39 +2039,25 @@ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) **/ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) { - lc->sip_conf.use_rfc2833=use_rfc2833; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833); + } } /** * Returns the UDP port used by SIP. * - * Deprecated: use linphone_core_get_sip_transports() instead. + * @deprecated use linphone_core_get_sip_transports() instead. * @ingroup network_parameters **/ -int linphone_core_get_sip_port(LinphoneCore *lc) -{ - LCSipTransports *tr=&lc->sip_conf.transports; - return tr->udp_port>0 ? tr->udp_port : (tr->tcp_port > 0 ? tr->tcp_port : tr->tls_port); +int linphone_core_get_sip_port(LinphoneCore *lc){ + LCSipTransports tr; + linphone_core_get_sip_transports_used(lc,&tr); + return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port); } static char _ua_name[64]="Linphone"; -static char _ua_version[64]=LINPHONE_VERSION; - -#ifdef HAVE_EXOSIP_GET_VERSION -extern const char *eXosip_get_version(); -#endif - -static void apply_user_agent(LinphoneCore *lc){ - char ua_string[256]; - snprintf(ua_string,sizeof(ua_string)-1,"%s/%s (eXosip2/%s)",_ua_name,_ua_version, -#ifdef HAVE_EXOSIP_GET_VERSION - eXosip_get_version() -#else - "unknown" -#endif - ); - if (lc->sal) sal_set_user_agent(lc->sal,ua_string); -} +static char _ua_version[64]=LIBLINPHONE_VERSION; /** * Sets the user agent string used in SIP messages. @@ -1768,9 +2065,15 @@ static void apply_user_agent(LinphoneCore *lc){ * @ingroup misc **/ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){ - strncpy(_ua_name,name,sizeof(_ua_name)-1); - strncpy(_ua_version,ver,sizeof(_ua_version)); - apply_user_agent(lc); + char ua_string[256]; + snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:""); + if (lc->sal) { + sal_set_user_agent(lc->sal, ua_string); + sal_append_stack_string_to_user_agent(lc->sal); + } +} +const char *linphone_core_get_user_agent(LinphoneCore *lc){ + return sal_get_user_agent(lc->sal); } const char *linphone_core_get_user_agent_name(void){ @@ -1784,8 +2087,7 @@ const char *linphone_core_get_user_agent_version(void){ static void transport_error(LinphoneCore *lc, const char* transport, int port){ char *msg=ortp_strdup_printf("Could not start %s transport on port %i, maybe this port is already used.",transport,port); ms_warning("%s",msg); - if (lc->vtable.display_warning) - lc->vtable.display_warning(lc,msg); + linphone_core_notify_display_warning(lc,msg); ms_free(msg); } @@ -1797,68 +2099,102 @@ static bool_t transports_unchanged(const LCSipTransports * tr1, const LCSipTrans tr2->tls_port==tr1->tls_port; } -static int apply_transports(LinphoneCore *lc){ +int _linphone_core_apply_transports(LinphoneCore *lc){ Sal *sal=lc->sal; const char *anyaddr; LCSipTransports *tr=&lc->sip_conf.transports; - + const char* listening_address; /*first of all invalidate all current registrations so that we can register again with new transports*/ __linphone_core_invalidate_registers(lc); - + if (lc->sip_conf.ipv6_enabled) anyaddr="::0"; else anyaddr="0.0.0.0"; sal_unlisten_ports(sal); - if (tr->udp_port>0){ - if (sal_listen_port (sal,anyaddr,tr->udp_port,SalTransportUDP,FALSE)!=0){ - transport_error(lc,"udp",tr->udp_port); - return -1; + + listening_address = lp_config_get_string(lc->config,"sip","bind_address",anyaddr); + + if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){ + if (sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE)!=0){ + transport_error(lc,"udp+tunnel",tr->udp_port); + } + }else{ + if (tr->udp_port!=0){ + if (sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE)!=0){ + transport_error(lc,"udp",tr->udp_port); + } + } + if (tr->tcp_port!=0){ + if (sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE)!=0){ + transport_error(lc,"tcp",tr->tcp_port); + } + } + if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){ + if (tr->tls_port!=0){ + if (sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE)!=0){ + transport_error(lc,"tls",tr->tls_port); + } + } } } - if (tr->tcp_port>0){ - if (sal_listen_port (sal,anyaddr,tr->tcp_port,SalTransportTCP,FALSE)!=0){ - transport_error(lc,"tcp",tr->tcp_port); - } - } - if (tr->tls_port>0){ - if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){ - 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) * * A zero value port for a given transport means the transport - * is not used. + * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be choosen randomly by the system. * * @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; - 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=LC_SIP_TRANSPORT_RANDOM; + } + if (tr.tcp_port>0){ + tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; + } + if (tr.tls_port>0){ + tr.tls_port=LC_SIP_TRANSPORT_RANDOM; + } + } + + 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; - return apply_transports(lc); + return _linphone_core_apply_transports(lc); } /** - * Retrieves the ports used for each transport (udp, tcp). + * Retrieves the port configuration used for each transport (udp, tcp, tls). * A zero value port for a given transport means the transport - * is not used. + * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be chosen randomly by the system. * @ingroup network_parameters **/ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){ @@ -1866,10 +2202,23 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){ return 0; } +/** + * Retrieves the real port number assigned for each sip transport (udp, tcp, tls). + * A zero value means that the transport is not activated. + * If LC_SIP_TRANSPORT_RANDOM was passed to linphone_core_set_sip_transports(), the random port choosed by the system is returned. + * @ingroup network_parameters + * @param lc the LinphoneCore + * @param tr a LCSipTransports structure. +**/ +void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr){ + tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP); + tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP); + tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS); +} /** * Sets the UDP port to be used by SIP. * - * Deprecated: use linphone_core_set_sip_transports() instead. + * @deprecated use linphone_core_set_sip_transports() instead. * @ingroup network_parameters **/ void linphone_core_set_sip_port(LinphoneCore *lc,int port) @@ -1903,31 +2252,45 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ if (lc->sip_conf.ipv6_enabled!=val){ lc->sip_conf.ipv6_enabled=val; if (lc->sal){ - /* we need to restart eXosip */ - apply_transports(lc); + /* we need to update the sip stack */ + _linphone_core_apply_transports(lc); + } + /*update the localip immediately for the network monitor to avoid to "discover" later that we switched to ipv6*/ + linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,lc->localip); + if (linphone_core_ready(lc)){ + lp_config_set_int(lc->config,"sip","use_ipv6",(int)val); } } } static void monitor_network_state(LinphoneCore *lc, time_t curtime){ - char result[LINPHONE_IPADDR_SIZE]; bool_t new_status=lc->network_last_status; + char newip[LINPHONE_IPADDR_SIZE]; /* only do the network up checking every five seconds */ if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){ - linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result); - if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ + linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,newip); + if (strcmp(newip,"::1")!=0 && strcmp(newip,"127.0.0.1")!=0){ new_status=TRUE; - }else new_status=FALSE; - lc->network_last_check=curtime; + }else new_status=FALSE; /*no network*/ + + if (new_status==lc->network_last_status && new_status==TRUE && strcmp(newip,lc->localip)!=0){ + /*IP address change detected*/ + ms_message("IP address change detected."); + set_network_reachable(lc,FALSE,curtime); + lc->network_last_status=FALSE; + } + strncpy(lc->localip,newip,sizeof(lc->localip)); + if (new_status!=lc->network_last_status) { if (new_status){ - ms_message("New local ip address is %s",result); + ms_message("New local ip address is %s",lc->localip); } set_network_reachable(lc,new_status, curtime); lc->network_last_status=new_status; } + lc->network_last_check=curtime; } } @@ -1937,10 +2300,11 @@ static void proxy_update(LinphoneCore *lc){ for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=next){ LinphoneProxyConfig* cfg = (LinphoneProxyConfig*)elem->data; next=elem->next; - if (ms_time(NULL) - cfg->deletion_date > 5) { + if (ms_time(NULL) - cfg->deletion_date > 32) { lc->sip_conf.deleted_proxies =ms_list_remove_link(lc->sip_conf.deleted_proxies,elem); - ms_message("clearing proxy config for [%s]",linphone_proxy_config_get_addr(cfg)); - linphone_proxy_config_destroy(cfg); + ms_message("Proxy config for [%s] is definitely removed from core.",linphone_proxy_config_get_addr(cfg)); + _linphone_proxy_config_release_ops(cfg); + linphone_proxy_config_unref(cfg); } } } @@ -1950,8 +2314,7 @@ static void assign_buddy_info(LinphoneCore *lc, BuddyInfo *info){ if (lf!=NULL){ lf->info=info; ms_message("%s has a BuddyInfo assigned with image %p",info->sip_uri, info->image_data); - if (lc->vtable.buddy_info_updated) - lc->vtable.buddy_info_updated(lc,lf); + linphone_core_notify_buddy_info_updated(lc,lf); }else{ ms_warning("Could not any friend with uri %s",info->sip_uri); } @@ -2036,6 +2399,29 @@ void linphone_core_iterate(LinphoneCore *lc){ time_t curtime=time(NULL); int elapsed; bool_t one_second_elapsed=FALSE; + const char *remote_provisioning_uri = NULL; + if (lc->network_reachable_to_be_notified) { + lc->network_reachable_to_be_notified=FALSE; + linphone_core_notify_network_reachable(lc,lc->network_reachable); + } + if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) { + if (sal_get_root_ca(lc->sal)) { + belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new(); + belle_tls_verify_policy_set_root_ca(tls_policy, sal_get_root_ca(lc->sal)); + belle_http_provider_set_tls_verify_policy(lc->http_provider, tls_policy); + } + + linphone_core_notify_display_status(lc, _("Configuring")); + linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); + + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); + if (remote_provisioning_uri) { + int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); + if (err == -1) { + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI"); + } + } // else linphone_configuring_terminated has already been called in linphone_core_init + } if (curtime-lc->prevtime>=1){ lc->prevtime=curtime; @@ -2050,7 +2436,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (ecs==LinphoneEcCalibratorDone){ int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); int margin=len/2; - + lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0)); } else if (ecs == LinphoneEcCalibratorFailed) { lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/ @@ -2070,10 +2456,16 @@ 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; + && (curtime-lc->dmfs_playing_start_time)>5){ + MSPlayerState state; + bool_t stop=TRUE; + if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){ + if (state==MSPlayerPlaying) stop=FALSE; + } + if (stop) { + ms_message("Releasing inactive tone player."); + linphone_core_stop_dtmf_stream(lc); + } } sal_iterate(lc->sal); @@ -2086,7 +2478,7 @@ void linphone_core_iterate(LinphoneCore *lc){ calls= lc->calls; while(calls!= NULL){ call = (LinphoneCall *)calls->data; - elapsed = curtime-call->start_time; + elapsed = curtime-call->log->start_date_time; /* get immediately a reference to next one in case the one we are going to examine is destroy and removed during linphone_core_start_invite() */ @@ -2106,23 +2498,28 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_delete_upnp_session(call); } #endif //BUILD_UPNP - linphone_core_start_invite(lc,call); + linphone_core_start_invite(lc,call, NULL); } - if (call->state==LinphoneCallIncomingReceived){ - ms_message("incoming call ringing for %i seconds",elapsed); + if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){ + 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); + decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; - call->reason=LinphoneReasonNotAnswered; - linphone_core_terminate_call(lc,call); + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL); + linphone_core_decline_call(lc,call,decline_reason); } } - if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { + if ( (lc->sip_conf.in_call_timeout > 0) + && (call->log->connected_date_time != 0) + && ((curtime - call->log->connected_date_time) > lc->sip_conf.in_call_timeout)) + { ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout); linphone_core_terminate_call(lc,call); } } - + if (linphone_core_video_preview_enabled(lc)){ if (lc->previewstream==NULL && lc->calls==NULL) toggle_video_preview(lc,TRUE); @@ -2137,92 +2534,25 @@ 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 && lp_config_needs_commit(lc->config)){ - lp_config_sync(lc->config); + if (one_second_elapsed) { + if (lp_config_needs_commit(lc->config)) { + lp_config_sync(lc->config); + } + } + + if (liblinphone_serialize_logs == TRUE) { + ortp_logv_flush(); } } -/** - * Interpret a call destination as supplied by the user, and returns a fully qualified - * LinphoneAddress. - * - * @ingroup call_control - * - * A sip address should look like DisplayName . - * Basically this function performs the following tasks - * - if a phone number is entered, prepend country prefix of the default proxy - * configuration, eventually escape the '+' by 00. - * - if no domain part is supplied, append the domain name of the default proxy - * - if no sip: is present, prepend it - * - * The result is a syntaxically correct SIP address. -**/ - 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; - char *tmpurl; - LinphoneAddress *uri; - - if (is_enum(url,&enum_domain)){ - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Looking for telephone number destination...")); - if (enum_lookup(enum_domain,&enumres)<0){ - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Could not resolve this number.")); - ms_free(enum_domain); - return NULL; - } - ms_free(enum_domain); - tmpurl=enumres->sip_address[0]; - uri=linphone_address_new(tmpurl); - enum_lookup_res_free(enumres); - return uri; - } - /* check if we have a "sip:" */ - if (strstr(url,"sip:")==NULL){ - /* this doesn't look like a true sip uri */ - if (strchr(url,'@')!=NULL){ - /* seems like sip: is missing !*/ - tmpurl=ms_strdup_printf("sip:%s",url); - uri=linphone_address_new(tmpurl); - ms_free(tmpurl); - if (uri){ - return uri; - } - } - - if (proxy!=NULL){ - /* append the proxy domain suffix */ - const char *identity=linphone_proxy_config_get_identity(proxy); - char normalized_username[128]; - uri=linphone_address_new(identity); - if (uri==NULL){ - return NULL; - } - linphone_address_set_display_name(uri,NULL); - linphone_proxy_config_normalize_number(proxy,url,normalized_username, - sizeof(normalized_username)); - linphone_address_set_username(uri,normalized_username); - return uri; - }else return NULL; - } - uri=linphone_address_new(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; + LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc); + return linphone_proxy_config_normalize_sip_uri(proxy, url); } /** @@ -2255,18 +2585,39 @@ const char * linphone_core_get_route(LinphoneCore *lc){ return route; } -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->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); +/** + * Start a new call as a consequence of a transfer request received from a call. + * This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application + * wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification. + * @see LinphoneCoreVTable::call_state_changed + * @param lc the LinphoneCore + * @param call a call that has just been notified about LinphoneCallRefered state event. + * @param params the call parameters to be applied to the new call. + * @return a LinphoneCall corresponding to the new call that is attempted to the transfer destination. +**/ +LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ + LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_default_call_parameters(lc); + LinphoneCall *newcall; + + if (call->state!=LinphoneCallPaused){ + ms_message("Automatically pausing current call to accept transfer."); + _linphone_core_pause_call(lc,call); + call->was_automatically_paused=TRUE; } + + if (!params){ + 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) { + call->transfer_target=linphone_call_ref(newcall); + linphone_core_notify_refer_state(lc,call,newcall); + } + return newcall; } void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){ @@ -2275,89 +2626,99 @@ 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; + LinphoneProxyConfig *found_reg_cfg=NULL; + LinphoneProxyConfig *found_noreg_cfg=NULL; LinphoneProxyConfig *default_cfg=lc->default_proxy; - /*always prefer the default proxy if it is matching the destination uri*/ + if (linphone_address_get_domain(uri) == NULL) { + ms_message("cannot seach for proxy for uri [%p] if no domain set. returning default",uri); + return default_cfg; + } + /*return 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*/ + /*otherwise return first registered, then first registering matching, otherwise first matching */ for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; const char *domain=linphone_proxy_config_get_domain(cfg); if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ - found_cfg=cfg; - break; + if (linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk ){ + found_cfg=cfg; + break; + } else if (!found_reg_cfg && linphone_proxy_config_register_enabled(cfg)) { + found_reg_cfg=cfg; + } else if (!found_noreg_cfg){ + found_noreg_cfg=cfg; + } } } +end: + if ( !found_cfg && found_reg_cfg) found_cfg = found_reg_cfg; + else if( !found_cfg && found_noreg_cfg ) found_cfg = found_noreg_cfg; + + if (found_cfg && found_cfg!=default_cfg){ + ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); + }else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/ 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; @@ -2385,50 +2746,62 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) { - return linphone_core_start_invite(lc, call); + return linphone_core_start_invite(lc, call, NULL); } return 0; } -int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ +int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ + linphone_call_create_op(call); + linphone_call_stop_media_streams(call); + ms_media_stream_sessions_uninit(&call->sessions[0]); + ms_media_stream_sessions_uninit(&call->sessions[1]); + linphone_call_init_media_streams(call); + return linphone_core_start_invite(lc,call, NULL); +} + +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination /* = NULL if to be taken from the call log */){ 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); + linphone_call_make_local_media_description(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); + } + if (!lc->use_files) + audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); + } + } + real_url=linphone_address_as_string( destination ? destination : call->log->to); + from=linphone_address_as_string(call->log->from); + if (!lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; + /*we are offering, set local media description before sending the call*/ sal_call_set_local_media_description(call->op,call->localdesc); } - real_url=linphone_address_as_string(call->log->to); - from=linphone_address_as_string(call->log->from); err=sal_call(call->op,from,real_url); + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } + call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ - if (lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,barmsg); + linphone_core_notify_display_status(lc,barmsg); ms_free(barmsg); if (err<0){ - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Could not call")); + linphone_core_notify_display_status(lc,_("Could not call")); linphone_call_stop_media_streams(call); linphone_call_set_state(call,LinphoneCallError,"Call failed"); }else { @@ -2508,90 +2881,106 @@ 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); + sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy)); + if (with_contact && proxy && proxy->op){ + const SalAddress *contact; + if ((contact=sal_op_get_contact_address(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_address(op,new_contact); + sal_address_destroy(new_contact); + } + } + sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/ +} -/** - * Initiates an outgoing call given a destination LinphoneAddress - * - * @ingroup call_control - * @param lc the LinphoneCore object - * @param addr the destination of the call (sip address). - @param params call parameters - * - * The LinphoneAddress can be constructed directly using linphone_address_new(), or - * created by linphone_core_interpret_url(). - * The application doesn't own a reference to the returned LinphoneCall object. - * Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. - * - * @return a LinphoneCall object or NULL in case of failure -**/ 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; bool_t defer = FALSE; + LinphoneCallParams *cp = linphone_call_params_copy(params); linphone_core_preempt_sound_resources(lc); - + if(!linphone_core_can_we_add_call(lc)){ - if (lc->vtable.display_warning) - lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); + linphone_core_notify_display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); 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); + cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy); + cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000; + }else{ + cp->avpf_enabled=linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled; + if (cp->avpf_enabled) cp->avpf_rr_interval=linphone_core_get_avpf_rr_interval(lc) * 1000; + } /* if no proxy or no identity defined for this proxy, default to primary contact*/ if (from==NULL) from=linphone_core_get_primary_contact(lc); 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),cp,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); + linphone_call_params_destroy(cp); return NULL; } + /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); + call->log->start_date_time=ms_time(NULL); + linphone_call_init_media_streams(call); + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { /* Defer the start of the call after the ICE gathering process. */ - linphone_call_init_media_streams(call); - linphone_call_start_media_streams_for_ice_gathering(call); - call->start_time=time(NULL); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); - } else { - defer = TRUE; - } + if (linphone_call_prepare_ice(call,FALSE)==1) + defer=TRUE; } else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { #ifdef BUILD_UPNP - linphone_call_init_media_streams(call); - call->start_time=time(NULL); if (linphone_core_update_upnp(lc,call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); @@ -2613,14 +3002,14 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); sal_op_set_user_pointer(call->ping_op,call); - call->start_time=time(NULL); defer = TRUE; } } - - if (defer==FALSE) linphone_core_start_invite(lc,call); + + if (defer==FALSE) linphone_core_start_invite(lc,call,NULL); if (real_url!=NULL) ms_free(real_url); + linphone_call_params_destroy(cp); return call; } @@ -2630,6 +3019,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 #LinphoneCallConnected. **/ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { @@ -2658,7 +3051,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * @param lc linphone core object * @param call a running call you want to transfer * @param dest a running call whose remote person will receive the transfer - * + * * @ingroup call_control * * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. @@ -2666,6 +3059,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 #LinphoneCallConnected. **/ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ int result = sal_call_refer_with_replaces (call->op,dest->op); @@ -2673,7 +3070,7 @@ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, return result; } -bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ +bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc){ LinphoneCall *call = linphone_core_get_current_call(lc); if(call != NULL) { @@ -2685,54 +3082,29 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ } bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ - if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ - int i; - for(i=0;in_active_streams;i++){ - SalStreamDescription *sd=&md->streams[i]; - if (sd->proto!=SalProtoRtpSavp){ - return TRUE; - } - } - } - return FALSE; + return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !sal_media_description_has_srtp(md); } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ char *barmesg; char *tmp; LinphoneAddress *from_parsed; - SalMediaDescription *md; bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE); - const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc); - - 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){ - if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ - sal_call_decline(call->op,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } - } from_parsed=linphone_address_new(sal_op_get_from(call->op)); linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), - (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):_(".")); - if (lc->vtable.show) lc->vtable.show(lc); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,barmesg); + (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):"."); + linphone_core_notify_show_interface(lc); + linphone_core_notify_display_status(lc,barmesg); /* play the ring if this is the only 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){ @@ -2748,19 +3120,25 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ }else{ /* else play a tone within the context of the current call */ call->ringing_beep=TRUE; - linphone_core_play_tone(lc); + linphone_core_play_named_tone(lc,LinphoneToneCallWaiting); } linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); + /*from now on, the application is aware of the call and supposed to take background task or already submitted notification to the user. + We can then drop our background task.*/ + if (call->bg_task_id!=0) { + sal_end_background_task(call->bg_task_id); + call->bg_task_id=0; + } if (call->state==LinphoneCallIncomingReceived){ - sal_call_notify_ringing(call->op,propose_early_media || ringback_tone!=NULL); + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ + linphone_call_set_contact_op(call); + + if (propose_early_media){ + linphone_core_accept_early_media(lc,call); + }else sal_call_notify_ringing(call->op,FALSE); - if (propose_early_media || ringback_tone!=NULL){ - linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); - md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc,call,md); - } if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ linphone_core_accept_call(lc,call); } @@ -2771,26 +3149,96 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ ms_free(tmp); } + +/** + * When receiving an incoming, accept to start a media session as early-media. + * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. + * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. + * The call can then later be fully accepted using linphone_core_accept_call() or linphone_core_accept_call_with_params(). + * @param lc the linphonecore + * @param call the call + * @param params the call params, can be NULL. + * @return 0 if successful, -1 otherwise. + * @ingroup call_control +**/ +int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params) { + if (call->state==LinphoneCallIncomingReceived){ + SalMediaDescription* md; + + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ + linphone_call_set_contact_op(call); + + // if parameters are passed, update the media description + if ( params ) { + linphone_call_set_new_params(call,params); + linphone_call_make_local_media_description (call); + sal_call_set_local_media_description ( call->op,call->localdesc ); + sal_op_set_sent_custom_header ( call->op,params->custom_headers ); + } + + sal_call_notify_ringing(call->op, TRUE); + + linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); + md=sal_call_get_final_media_description(call->op); + if (md) linphone_core_update_streams(lc, call, md, call->state); + return 0; + }else{ + ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state)); + } + + return -1; +} + +/** + * Accept an early media session for an incoming call. + * This is identical as calling linphone_core_accept_early_media_with_params() with NULL call parameters. + * @see linphone_core_accept_early_media_with_params() + * @param lc the core + * @param call the incoming call + * @return 0 if successful, -1 otherwise. + * @ingroup call_control +**/ +int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){ + return linphone_core_accept_early_media_with_params(lc, call, NULL); +} + int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; - call->camera_active=call->params.has_video; - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - } + int err; + bool_t no_user_consent=call->params->no_user_consent; + + linphone_call_fill_media_multicast_addr(call); + + if (!no_user_consent) linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } #endif //BUILD_UPNP - if (call->params.in_conference){ + if (call->params->in_conference){ subject="Conference"; - }else{ + }else if (!no_user_consent){ subject="Media change"; + }else{ + subject="Refreshing"; } - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Modifying call parameters...")); - sal_call_set_local_media_description (call->op,call->localdesc); - return sal_call_update(call->op,subject); + linphone_core_notify_display_status(lc,_("Modifying call parameters...")); + if (!lc->sip_conf.sdp_200_ack){ + sal_call_set_local_media_description (call->op,call->localdesc); + } else { + sal_call_set_local_media_description (call->op,NULL); + } + if (call->dest_proxy && call->dest_proxy->op){ + /*give a chance to update the contact address if connectivity has changed*/ + sal_op_set_contact_address(call->op,sal_op_get_contact_address(call->dest_proxy->op)); + }else sal_op_set_contact_address(call->op,NULL); + err= sal_call_update(call->op,subject,no_user_consent); + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } + return err; } /** @@ -2809,48 +3257,57 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ **/ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ int err=0; + LinphoneCallState nextstate, initial_state; + +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) + bool_t has_video = FALSE; +#endif + + switch(initial_state=call->state){ + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + nextstate=LinphoneCallEarlyUpdating; + break; + case LinphoneCallStreamsRunning: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + nextstate=LinphoneCallUpdating; + break; + default: + ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state)); + return -1; + } + if (params!=NULL){ - linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); -#ifdef VIDEO_ENABLED - bool_t has_video = call->params.has_video; + linphone_call_set_state(call,nextstate,"Updating call"); +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) + has_video = call->params->has_video; // Video removing if((call->videostream != NULL) && !params->has_video) { - if (call->ice_session != NULL) { - ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list); - call->videostream->ms.ice_check_list = NULL; - } -#ifdef BUILD_UPNP if(call->upnp_session != NULL) { if (linphone_core_update_upnp(lc, call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); } } -#endif //BUILD_UPNP - } - - _linphone_call_params_copy(&call->params,params); - linphone_call_make_local_media_description(lc, call); + } +#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */ + linphone_call_set_new_params(call,params); + err=linphone_call_prepare_ice(call,FALSE); + if (err==1) { + ms_message("Defer call update to gather ICE candidates"); + return 0; + } + +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) // Video adding - if (!has_video && call->params.has_video) { - if (call->ice_session != NULL) { - /* Defer call update until the ICE candidates gathering process has finished. */ - ms_message("Defer call update to gather ICE candidates"); - linphone_call_init_video_stream(call); - video_stream_prepare_video(call->videostream); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else { - return err; - } - } -#ifdef BUILD_UPNP + if (!has_video && call->params->has_video) { if(call->upnp_session != NULL) { ms_message("Defer call update to add uPnP port mappings"); - linphone_call_init_video_stream(call); video_stream_prepare_video(call->videostream); if (linphone_core_update_upnp(lc, call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ @@ -2859,16 +3316,20 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho return err; } } -#endif //BUILD_UPNP } -#endif - err = linphone_core_start_update_call(lc, call); +#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP) + if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) { + /*Restore initial state*/ + linphone_call_set_state(call,initial_state,NULL); + } + }else{ #ifdef VIDEO_ENABLED - if (call->videostream!=NULL){ + if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) { video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); - if (call->camera_active && call->videostream->cam!=lc->video_conf.device){ - video_stream_change_camera(call->videostream,lc->video_conf.device); + video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc)); + if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){ + video_stream_change_camera(call->videostream, lc->video_conf.device); }else video_stream_update_video_params(call->videostream); } #endif @@ -2880,127 +3341,135 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho /** * @ingroup call_control * When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer. - * + * * When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of - * LinphoneCore is to automatically answer the reINIVTE with call parameters unchanged. + * LinphoneCore is defined by the "defer_update_default" option of the "sip" section of the config. If this option is 0 (the default) + * then the LinphoneCore automatically answers the reINIVTE with call parameters unchanged. * However when for example when the remote party updated the call to propose a video stream, it can be useful - * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during - * the call state notifiacation, to deactivate the automatic answer that would just confirm the audio but reject the video. + * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during + * the call state notification, to deactivate the automatic answer that would just confirm the audio but reject the video. * Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer * the reINVITE, with eventually video enabled in the LinphoneCallParams argument. * - * @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal. + * The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made + * in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible + * changes in the media session. However in such case defering the update has no meaning since we just generating an offer. + * + * @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a valid #LinphoneCallUpdatedByRemote notification. **/ int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallUpdatedByRemote){ + if (call->expect_media_in_ack){ + ms_error("linphone_core_defer_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)"); + return -1; + } call->defer_update=TRUE; return 0; + }else{ + ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote"); } - ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote"); return -1; } -int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call){ +int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState next_state, const char *state_info){ SalMediaDescription *md; if (call->ice_session != NULL) { if (ice_session_nb_losing_pairs(call->ice_session) > 0) { /* Defer the sending of the answer until there are no losing pairs left. */ return 0; } - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } -#ifdef BUILD_UPNP - if(call->upnp_session != NULL) { - linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - } -#endif //BUILD_UPNP + linphone_call_make_local_media_description(call); + linphone_call_update_remote_session_id_and_ver(call); + linphone_call_stop_ice_for_inactive_streams(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)) - linphone_core_update_streams (lc,call,md); - linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + if (md && !sal_media_description_empty(md)){ + linphone_core_update_streams(lc, call, md, next_state); + linphone_call_fix_call_parameters(call); + } + linphone_call_set_state(call,next_state,state_info); return 0; } /** * @ingroup call_control * Accept call modifications initiated by other end. - * + * * This call may be performed in response to a #LinphoneCallUpdatedByRemote state notification. * When such notification arrives, the application can decide to call linphone_core_defer_update_call() so that it can * have the time to prompt the user. linphone_call_get_remote_params() can be used to get information about the call parameters * requested by the other party, such as whether a video stream is requested. - * + * * When the user accepts or refuse the change, linphone_core_accept_call_update() can be done to answer to the other party. * If params is NULL, then the same call parameters established before the update request will continue to be used (no change). * If params is not NULL, then the update will be accepted according to the parameters passed. - * Typical example is when a user accepts to start video, then params should indicate that video stream should be used + * Typical example is when a user accepts to start video, then params should indicate that video stream should be used * (see linphone_call_params_enable_video()). * @param lc the linphone core object. * @param call the LinphoneCall object * @param params a LinphoneCallParams object describing the call parameters to accept. - * @return 0 if sucessful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). + * @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). **/ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ - SalMediaDescription *remote_desc; - bool_t keep_sdp_version; -#ifdef VIDEO_ENABLED - bool_t old_has_video = call->params.has_video; -#endif if (call->state!=LinphoneCallUpdatedByRemote){ ms_error("linphone_core_accept_update(): invalid state %s to call this function.", - linphone_call_state_to_string(call->state)); + linphone_call_state_to_string(call->state)); return -1; } + return _linphone_core_accept_call_update(lc, call, params, call->prevstate, linphone_call_state_to_string(call->prevstate)); +} + +int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info){ + SalMediaDescription *remote_desc; + bool_t keep_sdp_version; +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) + bool_t old_has_video = call->params->has_video; +#endif + remote_desc = sal_call_get_remote_media_description(call->op); keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0); if (keep_sdp_version &&(remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) { /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ ms_warning("SDP version has not changed, send same SDP as before."); sal_call_accept(call->op); - linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + linphone_call_set_state(call,next_state,state_info); return 0; } if (params==NULL){ - call->params.has_video=lc->video_policy.automatically_accept || call->current_params.has_video; - }else - 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."); - call->params.has_video=FALSE; - } - if (call->current_params.in_conference) { - ms_warning("Video isn't supported in conference"); - call->params.has_video = FALSE; - } - call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc); - call->camera_active=call->params.has_video; - linphone_call_make_local_media_description(lc,call); - if (call->ice_session != NULL) { - linphone_core_update_ice_from_remote_media_description(call, remote_desc); -#ifdef VIDEO_ENABLED - if ((call->ice_session != NULL) &&!ice_session_candidates_gathered(call->ice_session)) { - if ((call->params.has_video) && (call->params.has_video != old_has_video)) { - linphone_call_init_video_stream(call); - video_stream_prepare_video(call->videostream); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else return 0; - } + linphone_call_params_enable_video(call->params, lc->video_policy.automatically_accept || call->current_params->has_video); + if (!sal_call_is_offerer(call->op)) { + /*reset call param for multicast because this param is only relevant when offering*/ + linphone_call_params_enable_audio_multicast(call->params,FALSE); + linphone_call_params_enable_video_multicast(call->params,FALSE); } -#endif //VIDEO_ENABLED + }else + linphone_call_set_new_params(call,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."); + call->params->has_video=FALSE; + } + if (call->current_params->in_conference) { + ms_warning("Video isn't supported in conference"); + call->params->has_video = FALSE; + } + /*update multicast params according to call params*/ + linphone_call_fill_media_multicast_addr(call); + + linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/ + if (call->ice_session != NULL) { + if (linphone_call_prepare_ice(call,TRUE)==1) + return 0;/*deferred to completion of ICE gathering*/ } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); #ifdef VIDEO_ENABLED - if ((call->params.has_video) && (call->params.has_video != old_has_video)) { - linphone_call_init_video_stream(call); + if ((call->params->has_video) && (call->params->has_video != old_has_video)) { video_stream_prepare_video(call->videostream); if (linphone_core_update_upnp(lc, call)<0) { /* uPnP update failed, proceed with the call anyway. */ @@ -3011,7 +3480,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } #endif //BUILD_UPNP - linphone_core_start_accept_call_update(lc, call); + linphone_core_start_accept_call_update(lc, call, next_state, state_info); return 0; } @@ -3045,13 +3514,11 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){ * @param params the specific parameters for this call, for example whether video is accepted or not. Use NULL to use default parameters. * **/ -int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) -{ - LinphoneProxyConfig *cfg=NULL; - const char *contact=NULL; +int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; + MSList * iterator, *copy; if (call==NULL){ //if just one call is present answer the only one ... @@ -3061,18 +3528,44 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, call = (LinphoneCall*)linphone_core_get_calls(lc)->data; } - if (call->state==LinphoneCallConnected){ - /*call already accepted*/ - return -1; + switch(call->state){ + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + break; + default: + ms_error("linphone_core_accept_call_with_params() call [%p] is in state [%s], operation not permitted.", + call, linphone_call_state_to_string(call->state)); + return -1; + break; } + + for (iterator=copy=ms_list_copy(linphone_core_get_calls(lc));iterator!=NULL;iterator=iterator->next) { + LinphoneCall *a_call=(LinphoneCall*)iterator->data; + if (a_call==call) continue; + switch(a_call->state){ + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingEarlyMedia: + ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]",a_call + ,linphone_call_state_to_string(a_call->state) + ,call); + linphone_core_terminate_call(lc,a_call); + break; + default: + break; /*nothing to do*/ + } + } + ms_list_free(copy); + /* check if this call is supposed to replace an already running one*/ replaced=sal_call_get_replaces(call->op); if (replaced){ LinphoneCall *rc=(LinphoneCall*)sal_op_get_user_pointer (replaced); if (rc){ ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.", - call,rc); + call,rc); linphone_core_terminate_call(lc,rc); } } @@ -3084,9 +3577,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){ @@ -3094,47 +3585,47 @@ 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); + linphone_call_set_new_params(call,params); // There might not be a md if the INVITE was lacking an SDP // In this case we use the parameters as is. - if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - call->camera_active=call->params.has_video; - linphone_call_make_local_media_description(lc,call); + if (md) { + linphone_call_set_compatible_incoming_call_parameters(call, md); + } + linphone_call_prepare_ice(call,TRUE); + linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op,call->localdesc); + sal_op_set_sent_custom_header(call->op,params->custom_headers); } - - if (call->audiostream==NULL) - linphone_call_init_media_streams(call); - if (!was_ringing && call->audiostream->ms.ticker==NULL){ + + /*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.state==MSStreamInitialized && !lc->use_files){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } linphone_call_update_remote_session_id_and_ver(call); + linphone_call_stop_ice_for_inactive_streams(call); sal_call_accept(call->op); - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Connected.")); + linphone_core_notify_display_status(lc,_("Connected.")); lc->current_call=call; linphone_call_set_state(call,LinphoneCallConnected,"Connected"); new_md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc, call, new_md); if (new_md){ + linphone_core_update_streams(lc, call, new_md, LinphoneCallStreamsRunning); + linphone_call_fix_call_parameters(call); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); - }else call->media_pending=TRUE; + }else call->expect_media_in_ack=TRUE; ms_message("call answered."); return 0; @@ -3144,32 +3635,25 @@ 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 linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Call aborted") ); + linphone_core_notify_display_status(lc,_("Call aborted") ); linphone_call_set_state(call,LinphoneCallError,error); return 0; } static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallIncomingReceived){ - if (call->reason!=LinphoneReasonNotAnswered) - call->reason=LinphoneReasonDeclined; + if (call->non_op_error.reason!=SalReasonRequestTimeout) + call->non_op_error.reason=SalReasonDeclined; } /*stop ringing*/ - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); @@ -3177,20 +3661,19 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Call ended") ); + linphone_core_notify_display_status(lc,_("Call ended") ); linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); } int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){ if (call->state==LinphoneCallIncomingReceived){ sal_call_decline(call->op,SalReasonRedirect,redirect_uri); - call->reason=LinphoneReasonDeclined; + sal_error_info_set(&call->non_op_error,SalReasonRedirect,603,"Call redirected",NULL); terminate_call(lc,call); }else{ ms_error("Bad state for call redirection."); return -1; - } + } return 0; } @@ -3218,39 +3701,44 @@ 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; } /** * Decline a pending incoming call, with a reason. - * + * * @ingroup call_control - * + * * @param lc the linphone core * @param call the LinphoneCall, must be in the IncomingReceived state. * @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; } @@ -3273,6 +3761,8 @@ int linphone_core_terminate_all_calls(LinphoneCore *lc){ /** * Returns the current list of calls. + * @param[in] lc The LinphoneCore object + * @return \mslist{LinphoneCall} * * Note that this list is read-only and might be changed by the core after a function call to linphone_core_iterate(). * Similarly the LinphoneCall objects inside it might be destroyed without prior notice. @@ -3299,8 +3789,7 @@ bool_t linphone_core_in_call(const LinphoneCore *lc){ * * @ingroup call_control **/ -LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) -{ +LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){ return lc->current_call; } @@ -3310,44 +3799,44 @@ LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) * * @ingroup call_control **/ -int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) -{ +int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ + int err=_linphone_core_pause_call(lc,call); + if (err==0) call->paused_by_app=TRUE; + return err; +} + +/* Internal version that does not play tone indication*/ +int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject=NULL; if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){ ms_warning("Cannot pause this call, it is not active."); return -1; } - linphone_call_make_local_media_description(lc,call); - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); + if (sal_media_description_has_dir(call->resultdesc, SalStreamSendRecv)) { + subject = "Call on hold"; + } else if (sal_media_description_has_dir(call->resultdesc, SalStreamRecvOnly)) { + subject = "Call on hold for me too"; + } else { + ms_error("No reason to pause this call, it is already paused or inactive."); + return -1; } + linphone_call_set_state(call, LinphoneCallPausing, "Pausing call"); + linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } #endif //BUILD_UPNP - if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){ - sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); - subject="Call on hold"; - }else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){ - sal_media_description_set_dir(call->localdesc,SalStreamSendOnly); - subject="Call on hold for me too"; - }else{ - ms_error("No reason to pause this call, it is already paused or inactive."); - return -1; - } sal_call_set_local_media_description(call->op,call->localdesc); - if (sal_call_update(call->op,subject) != 0){ - if (lc->vtable.display_warning) - lc->vtable.display_warning(lc,_("Could not pause the call")); + if (sal_call_update(call->op,subject,FALSE) != 0){ + linphone_core_notify_display_warning(lc,_("Could not pause the call")); } lc->current_call=NULL; - linphone_call_set_state(call,LinphoneCallPausing,"Pausing call"); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Pausing the current call...")); + linphone_core_notify_display_status(lc,_("Pausing the current call...")); if (call->audiostream || call->videostream) linphone_call_stop_media_streams (call); + call->paused_by_app=FALSE; return 0; } @@ -3361,7 +3850,7 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){ LinphoneCall *call=(LinphoneCall *)elem->data; LinphoneCallState cs=linphone_call_get_state(call); if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){ - linphone_core_pause_call(lc,call); + _linphone_core_pause_call(lc,call); } } return 0; @@ -3369,14 +3858,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); + _linphone_core_pause_call(lc,current_call); + } + if (lc->ringstream){ + linphone_core_stop_ringing(lc); } } @@ -3385,44 +3879,56 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ * * @ingroup call_control **/ -int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) -{ +int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ char temp[255]={0}; - LinphoneCall *call = the_call; const char *subject="Call resuming"; - + if(call->state!=LinphoneCallPaused ){ ms_warning("we cannot resume a call that has not been established and paused before"); return -1; } - if (call->params.in_conference==FALSE){ + 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.",call); + return -1; + } linphone_core_preempt_sound_resources(lc); ms_message("Resuming call %p",call); } + call->was_automatically_paused=FALSE; + /* Stop playing music immediately. If remote side is a conference it prevents the participants to hear it while the 200OK comes back.*/ if (call->audiostream) audio_stream_play(call->audiostream, NULL); - linphone_call_make_local_media_description(lc,the_call); - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - } + linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } #endif //BUILD_UPNP - sal_call_set_local_media_description(call->op,call->localdesc); + if (!lc->sip_conf.sdp_200_ack){ + sal_call_set_local_media_description(call->op,call->localdesc); + } else { + sal_call_set_local_media_description(call->op,NULL); + } sal_media_description_set_dir(call->localdesc,SalStreamSendRecv); - if (call->params.in_conference && !call->current_params.in_conference) subject="Conference"; - if(sal_call_update(call->op,subject) != 0){ + if (call->params->in_conference && !call->current_params->in_conference) subject="Conference"; + if ( sal_call_update(call->op,subject,FALSE) != 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); + linphone_core_notify_display_status(lc,temp); + + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } return 0; } @@ -3436,23 +3942,32 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad * @param lc * @param remote_address * @return the LinphoneCall of the call if found - * + * * @ingroup call_control */ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ + LinphoneCall *call=NULL; LinphoneAddress *raddr=linphone_address_new(remote_address); + if (raddr) { + call=linphone_core_get_call_by_remote_address2(lc, raddr); + linphone_address_unref(raddr); + } + return call; +} +LinphoneCall *linphone_core_get_call_by_remote_address2(LinphoneCore *lc, const LinphoneAddress *raddr){ MSList *elem=ms_list_find_custom(lc->calls,(int (*)(const void*,const void *))remote_address_compare,raddr); + if (elem) return (LinphoneCall*) elem->data; return NULL; } 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; } @@ -3489,6 +4004,9 @@ int linphone_core_get_inc_timeout(LinphoneCore *lc){ **/ void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds){ lc->sip_conf.in_call_timeout=seconds; + if( linphone_core_ready(lc)){ + lp_config_set_int(lc->config, "sip", "in_call_timeout", seconds); + } } /** @@ -3521,31 +4039,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; } /** @@ -3609,9 +4224,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){ - ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); - }else ms_warning("Could not apply gain: gain control wasn't activated."); + set_mic_gain_db(st,gain); } /** @@ -3642,9 +4255,7 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ ms_message("linphone_core_set_playback_gain_db(): no active call."); return; } - if (st->volrecv){ - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); - }else ms_warning("Could not apply gain: gain control wasn't activated."); + set_playback_gain_db(st,gain); } /** @@ -3694,20 +4305,18 @@ static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){ } } if (sndcard==NULL) { - /* get a card that has read+write capabilities */ - sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); - /* otherwise refine to the first card having the right capability*/ - if (sndcard==NULL){ - const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get()); - for(;elem!=NULL;elem=elem->next){ - sndcard=(MSSndCard*)elem->data; - if (ms_snd_card_get_capabilities(sndcard) & cap) break; - } + if ((cap & MS_SND_CARD_CAP_CAPTURE) && (cap & MS_SND_CARD_CAP_PLAYBACK)){ + sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); + }else if (cap & MS_SND_CARD_CAP_CAPTURE){ + sndcard=ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get()); + } + else if (cap & MS_SND_CARD_CAP_PLAYBACK){ + sndcard=ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get()); } if (sndcard==NULL){/*looks like a bug! take the first one !*/ const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get()); if (elem) sndcard=(MSSndCard*)elem->data; - } + } } if (sndcard==NULL) ms_error("Could not find a suitable soundcard !"); return sndcard; @@ -3842,36 +4451,54 @@ 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); - playback=linphone_core_get_playback_device(lc); - capture=linphone_core_get_capture_device(lc); + const char *ringer; + const char *playback; + const char *capture; + char *ringer_copy = NULL; + char *playback_copy = NULL; + char *capture_copy = NULL; + + ringer = linphone_core_get_ringer_device(lc); + if (ringer != NULL) { + ringer_copy = ms_strdup(ringer); + } + playback = linphone_core_get_playback_device(lc); + if (playback != NULL) { + playback_copy = ms_strdup(playback); + } + capture = linphone_core_get_capture_device(lc); + if (capture != NULL) { + capture_copy = ms_strdup(capture); + } ms_snd_card_manager_reload(ms_snd_card_manager_get()); build_sound_devices_table(lc); - linphone_core_set_ringer_device(lc,ringer); - linphone_core_set_playback_device(lc,playback); - linphone_core_set_capture_device(lc,capture); + if (ringer_copy != NULL) { + linphone_core_set_ringer_device(lc, ringer_copy); + ms_free(ringer_copy); + } + if (playback_copy != NULL) { + linphone_core_set_playback_device(lc, playback_copy); + ms_free(playback_copy); + } + if (capture_copy != NULL) { + linphone_core_set_capture_device(lc, capture_copy); + ms_free(capture_copy); + } } -/** - * 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); + char *devid_copy = NULL; + const char *devid = linphone_core_get_video_device(lc); + if (devid != NULL) { + devid_copy = ms_strdup(devid); + } ms_web_cam_manager_reload(ms_web_cam_manager_get()); build_video_devices_table(lc); - linphone_core_set_video_device(lc,devid); + if (devid_copy != NULL) { + linphone_core_set_video_device(lc, devid_copy); + ms_free(devid_copy); + } } char linphone_core_get_sound_source(LinphoneCore *lc) @@ -3935,6 +4562,10 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){ **/ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ sal_set_root_ca(lc->sal, path); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_root_ca(lc->http_verify_policy,path); + } + lp_config_set_string(lc->config,"sip","root_ca",path); } /** @@ -3945,16 +4576,20 @@ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ * @ingroup initializing **/ const char *linphone_core_get_root_ca(LinphoneCore *lc){ - return sal_get_root_ca(lc->sal); + return lp_config_get_string(lc->config,"sip","root_ca",NULL); } /** * Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server. - * + * * @ingroup initializing **/ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ sal_verify_server_certificates(lc->sal,yesno); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON); + } + lp_config_set_int(lc->config,"sip","verify_server_certs",yesno); } /** @@ -3963,11 +4598,17 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ **/ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ sal_verify_server_cn(lc->sal,yesno); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH); + } + lp_config_set_int(lc->config,"sip","verify_server_cn",yesno); } static void notify_end_of_ring(void *ud, MSFilter *f, unsigned int event, void *arg){ LinphoneCore *lc=(LinphoneCore*)ud; - lc->preview_finished=1; + if (event==MS_PLAYER_EOF){ + lc->preview_finished=1; + } } int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata) @@ -3997,7 +4638,7 @@ void linphone_core_set_ringback(LinphoneCore *lc, const char *path){ if (lc->sound_conf.remote_ring!=0){ ms_free(lc->sound_conf.remote_ring); } - lc->sound_conf.remote_ring=ms_strdup(path); + lc->sound_conf.remote_ring=path?ms_strdup(path):NULL; } /** @@ -4010,7 +4651,10 @@ const char * linphone_core_get_ringback(const LinphoneCore *lc){ } /** - * Enables or disable echo cancellation. Value is saved an used for subsequent calls + * Enables or disable echo cancellation. Value is saved and used for subsequent calls. + * This actually controls software echo cancellation. If hardware echo cancellation is available, it will be always used and activated for calls, regardless + * of the value passed to this function. + * When hardware echo cancellation is available, the software one is of course not activated. * * @ingroup media_parameters **/ @@ -4038,36 +4682,35 @@ 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; - if (linphone_core_is_in_conference(lc)){ - lc->conf_ctx.local_muted=val; - st=lc->conf_ctx.local_participant; - }else if (call==NULL){ - ms_warning("linphone_core_mute_mic(): No current call !"); - return; - }else{ - st=call->audiostream; - call->audio_muted=val; +static void linphone_core_mute_audio_stream(LinphoneCore *lc, AudioStream *st, bool_t val) { + if (val) { + audio_stream_set_mic_gain(st, 0); + } else { + audio_stream_set_mic_gain_db(st, lc->sound_conf.soft_mic_lev); } - if (st!=NULL){ - audio_stream_set_mic_gain(st, - (val==TRUE) ? 0 : pow(10,lc->sound_conf.soft_mic_lev/10)); - if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ - audio_stream_mute_rtp(st,val); - } - + + if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ + audio_stream_mute_rtp(st,val); } } -/** - * Returns whether microphone is muted. -**/ + +void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ + LinphoneCall *call; + const MSList *list; + const MSList *elem; + + if (linphone_core_is_in_conference(lc)){ + lc->conf_ctx.local_muted=val; + linphone_core_mute_audio_stream(lc, lc->conf_ctx.local_participant, val); + } + list = linphone_core_get_calls(lc); + for (elem = list; elem != NULL; elem = elem->next) { + call = (LinphoneCall *)elem->data; + call->audio_muted = val; + linphone_core_mute_audio_stream(lc, call->audiostream, val); + } +} + bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { LinphoneCall *call=linphone_core_get_current_call(lc); if (linphone_core_is_in_conference(lc)){ @@ -4079,13 +4722,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)){ @@ -4102,38 +4753,10 @@ bool_t linphone_core_agc_enabled(const LinphoneCore *lc){ return lc->sound_conf.agc; } -/** - * Send the specified dtmf. - * - * @ingroup media_parameters - * This function only works during calls. The dtmf is automatically played to the user. - * @param lc The LinphoneCore object - * @param dtmf The dtmf name specified as a char, such as '0', '#' etc... - * -**/ void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) { LinphoneCall *call=linphone_core_get_current_call(lc); - if (call==NULL){ - ms_warning("linphone_core_send_dtmf(): no active call"); - return; - } - /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ - if (linphone_core_get_use_rfc2833_for_dtmf(lc)!=0 || linphone_core_get_use_info_for_dtmf(lc)==0) - { - /* In Band DTMF */ - if (call->audiostream!=NULL){ - audio_stream_send_dtmf(call->audiostream,dtmf); - } - else - { - ms_error("we cannot send RFC2833 dtmf when we are not in communication"); - } - } - if (linphone_core_get_use_info_for_dtmf(lc)!=0){ - /* Out of Band DTMF (use INFO method) */ - sal_call_send_dtmf(call->op,dtmf); - } + linphone_call_send_dtmf(call, dtmf); } void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ @@ -4142,6 +4765,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); } @@ -4150,7 +4784,8 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ return lc->net_conf.stun_server; } -bool_t linphone_core_upnp_available(const LinphoneCore *lc){ + +bool_t linphone_core_upnp_available(){ #ifdef BUILD_UPNP return TRUE; #else @@ -4175,21 +4810,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){ @@ -4212,8 +4832,8 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) char ipstring [INET6_ADDRSTRLEN]; 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; } @@ -4231,13 +4851,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) { @@ -4251,73 +4890,86 @@ 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; + 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; } -/** - * Get the list of call logs (past calls). - * - * @ingroup call_logs -**/ + + +/******************************************************************************* + * Call log related functions * + ******************************************************************************/ + const MSList * linphone_core_get_call_logs(LinphoneCore *lc){ return lc->call_logs; } -/** - * Erase the call log. - * - * @ingroup call_logs -**/ void linphone_core_clear_call_logs(LinphoneCore *lc){ lc->missed_calls=0; - ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); + ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_unref); lc->call_logs=ms_list_free(lc->call_logs); 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); - linphone_call_log_destroy(cl); + linphone_call_log_unref(cl); } + + + 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); + MSVideoSize vsize=lc->video_conf.preview_vsize.width!=0 ? lc->video_conf.preview_vsize : lc->video_conf.vsize; 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 (lc->preview_window_id!=0) + video_preview_set_size(lc->previewstream,vsize); + if (display_filter) + video_preview_set_display_filter_name(lc->previewstream,display_filter); + if (lc->preview_window_id != NULL) video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id); + video_preview_set_fps(lc->previewstream,linphone_core_get_preferred_framerate(lc)); video_preview_start(lc->previewstream,lc->video_conf.device); } }else{ @@ -4329,37 +4981,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; @@ -4368,14 +4989,68 @@ 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); +} + +void linphone_core_enable_video_source_reuse(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.reuse_preview_source = enable; + if( linphone_core_ready(lc) ){ + lp_config_set_int(lc->config, "video", "reuse_source", lc->video_conf.reuse_preview_source); + } +} + +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: @@ -4433,6 +5108,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); } @@ -4535,7 +5213,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { const char *linphone_core_get_static_picture(LinphoneCore *lc) { const char *path=NULL; #ifdef VIDEO_ENABLED - path=ms_static_image_get_default_image(); + path=ms_static_image_get_default_image(); #else ms_warning("Video support not compiled."); #endif @@ -4572,7 +5250,7 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) { if (vs && vs->source) { if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) { - float fps; + float fps; ms_filter_call_method(vs->source, MS_FILTER_GET_FPS,(void *)&fps); return fps; @@ -4589,27 +5267,64 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) { * * @ingroup media_parameters **/ -unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ +void * 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 - * Set the native video window id where the video is to be displayed. - * If not set the core will create its own window. -**/ -void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){ +/* 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, void *id){ #ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call(lc); + LinphoneCall *call; + MSList *elem; +#endif + + if ((id != NULL) +#ifndef _WIN32 + && ((unsigned long)id != (unsigned long)-1) +#endif + ){ + 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 +} + +void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id){ + if ((id == NULL) +#ifndef _WIN32 + || ((unsigned long)id == (unsigned long)-1) +#endif + ){ + 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 } @@ -4619,31 +5334,46 @@ 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){ +void * 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){ +void linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *id){ + if ((id == NULL) +#ifndef _WIN32 + || ((unsigned long)id == (unsigned long)-1) +#endif + ) { + unset_video_window_id(lc,TRUE,id); + } lc->preview_window_id=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); + { + 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 } @@ -4653,19 +5383,14 @@ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long **/ void linphone_core_show_video(LinphoneCore *lc, bool_t show){ #ifdef VIDEO_ENABLED - ms_error("linphone_core_show_video %d", show); LinphoneCall *call=linphone_core_get_current_call(lc); + ms_error("linphone_core_show_video %d", show); if (call!=NULL && call->videostream){ video_stream_show_video(call->videostream,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; } @@ -4687,36 +5412,57 @@ 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 - LinphoneCall *call=linphone_core_get_current_call(lc); - if (call!=NULL && call->videostream){ - video_stream_set_device_rotation(call->videostream,rotation); + { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call!=NULL && call->videostream){ + video_stream_set_device_rotation(call->videostream,rotation); + } } #endif } -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" }, +int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { +#ifdef VIDEO_ENABLED + LinphoneCall *call = linphone_core_get_current_call(lc); + if ((call != NULL) && (call->videostream != NULL)) { + return video_stream_get_camera_sensor_rotation(call->videostream); + } #endif - { {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" }, - { {MS_VIDEO_SIZE_IOS_MEDIUM_H,MS_VIDEO_SIZE_IOS_MEDIUM_W} , "ios-medium" }, - { {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" }, - { {0,0} , NULL } + return -1; +} + +static MSVideoSizeDef supported_resolutions[]={ +#if !ANDROID && !TARGET_OS_IPHONE + { { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H } , "1080p" }, +#endif +#if !ANDROID && !TARGET_OS_MAC /*limit to most common sizes because mac video API cannot list supported resolutions*/ + { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, + { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, +#endif + { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H } , "720p" }, +#if !ANDROID && !TARGET_OS_MAC + { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, +#endif +#if !ANDROID && !TARGET_OS_IPHONE + { { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H } , "svga" }, + { { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H } , "4cif" }, +#endif + + { { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H } , "vga" }, +#if TARGET_OS_IPHONE + { { 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" }, +#if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */ + { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, +#endif + { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, + { { 0,0 } , NULL } }; -/** - * Returns the zero terminated table of supported video resolutions. - * - * @ingroup media_parameters -**/ const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){ return supported_resolutions; } @@ -4724,22 +5470,33 @@ const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){ static MSVideoSize video_size_get_by_name(const char *name){ MSVideoSizeDef *pdef=supported_resolutions; MSVideoSize null_vsize={0,0}; + MSVideoSize parsed; + if (!name) return null_vsize; for(;pdef->name!=NULL;pdef++){ if (strcasecmp(name,pdef->name)==0){ return pdef->vsize; } } + if (sscanf(name,"%ix%i",&parsed.width,&parsed.height)==2){ + return parsed; + } ms_warning("Video resolution %s is not supported in linphone.",name); return null_vsize; } +/* warning: function not reentrant*/ static const char *video_size_get_name(MSVideoSize vsize){ MSVideoSizeDef *pdef=supported_resolutions; + static char customsize[64]={0}; for(;pdef->name!=NULL;pdef++){ if (pdef->vsize.width==vsize.width && pdef->vsize.height==vsize.height){ return pdef->name; } } + if (vsize.width && vsize.height){ + snprintf(customsize,sizeof(customsize)-1,"%ix%i",vsize.width,vsize.height); + return customsize; + } return NULL; } @@ -4749,34 +5506,68 @@ static bool_t video_size_supported(MSVideoSize vsize){ return FALSE; } -/** - * Sets the preferred video size. - * - * @ingroup media_parameters - * 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. -**/ +static void update_preview_size(LinphoneCore *lc, MSVideoSize oldvsize, MSVideoSize vsize){ + if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){ + toggle_video_preview(lc,FALSE); + toggle_video_preview(lc,TRUE); + } +} + void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize){ if (video_size_supported(vsize)){ - MSVideoSize oldvsize=lc->video_conf.vsize; - lc->video_conf.vsize=vsize; - if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){ - toggle_video_preview(lc,FALSE); - toggle_video_preview(lc,TRUE); + MSVideoSize oldvsize=lc->video_conf.preview_vsize; + + if (oldvsize.width==0){ + oldvsize=lc->video_conf.vsize; } - if ( linphone_core_ready(lc)) + lc->video_conf.vsize=vsize; + update_preview_size(lc,oldvsize,vsize); + + if (linphone_core_ready(lc)) lp_config_set_string(lc->config,"video","size",video_size_get_name(vsize)); } } -/** - * Sets the preferred video size by its name. - * - * @ingroup media_parameters - * This is identical to linphone_core_set_preferred_video_size() except - * that it takes the name of the video resolution as input. - * Video resolution names are: qcif, svga, cif, vga, 4cif, svga ... -**/ +void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize){ + MSVideoSize oldvsize; + if (vsize.width==0 && vsize.height==0){ + /*special case to reset the forced preview size mode*/ + lc->video_conf.preview_vsize=vsize; + if (linphone_core_ready(lc)) + lp_config_set_string(lc->config,"video","preview_size",NULL); + return; + } + oldvsize=lc->video_conf.preview_vsize; + lc->video_conf.preview_vsize=vsize; + if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){ + toggle_video_preview(lc,FALSE); + toggle_video_preview(lc,TRUE); + } + if (linphone_core_ready(lc)) + lp_config_set_string(lc->config,"video","preview_size",video_size_get_name(vsize)); +} + +MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc){ + return lc->video_conf.preview_vsize; +} + +MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc){ + MSVideoSize ret={0}; +#ifndef VIDEO_ENABLED + ms_error("linphone_core_get_current_preview_video_size() fail. Support for video is disabled"); +#else + if (lc->previewstream){ + ret=video_preview_get_current_size(lc->previewstream); + } +#endif + return ret; +} + +void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name){ + MSVideoSize vsize=video_size_get_by_name(name); + linphone_core_set_preview_video_size(lc,vsize); +} + void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name){ MSVideoSize vsize=video_size_get_by_name(name); MSVideoSize default_vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H}; @@ -4784,28 +5575,33 @@ void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char else linphone_core_set_preferred_video_size(lc,default_vsize); } -/** - * Returns the current preferred video size for sending. - * - * @ingroup media_parameters -**/ -MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc){ +MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc){ return lc->video_conf.vsize; } -/** - * Ask the core to stream audio from and to files, instead of using the soundcard. -**/ -void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){ +char * linphone_core_get_preferred_video_size_name(const LinphoneCore *lc) { + return ms_strdup(video_size_get_name(lc->video_conf.vsize)); +} + +void linphone_core_set_preferred_framerate(LinphoneCore *lc, float fps){ + lc->video_conf.fps=fps; + if (linphone_core_ready(lc)) + lp_config_set_float(lc->config,"video","framerate",fps); +} + +float linphone_core_get_preferred_framerate(LinphoneCore *lc){ + return lc->video_conf.fps; +} + + +void linphone_core_set_use_files(LinphoneCore *lc, bool_t yesno){ lc->use_files=yesno; } -/** - * Sets a wav file to be played when putting somebody on hold, - * or when files are used instead of soundcards (see linphone_core_use_files()). - * - * The file must be a 16 bit linear wav file. -**/ +const char * linphone_core_get_play_file(const LinphoneCore *lc) { + return lc->play_file; +} + void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->play_file!=NULL){ @@ -4814,19 +5610,15 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ } if (file!=NULL) { lc->play_file=ms_strdup(file); - if (call && call->audiostream && call->audiostream->ms.ticker) + if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted) audio_stream_play(call->audiostream,file); } } +const char * linphone_core_get_record_file(const LinphoneCore *lc) { + return lc->rec_file; +} -/** - * Sets a wav file where incoming stream is to be recorded, - * when files are used instead of soundcards (see linphone_core_use_files()). - * - * This feature is different from call recording (linphone_call_params_set_record_file()) - * The file will be a 16 bit linear wav file. -**/ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->rec_file!=NULL){ @@ -4840,17 +5632,24 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ } } +typedef enum{ + LinphoneToneGenerator, + LinphoneLocalPlayer +}LinphoneAudioResourceType; -static MSFilter *get_dtmf_gen(LinphoneCore *lc){ - LinphoneCall *call=linphone_core_get_current_call (lc); +static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType rtype){ + LinphoneCall *call=linphone_core_get_current_call(lc); AudioStream *stream=NULL; + RingStream *ringstream; if (call){ stream=call->audiostream; }else if (linphone_core_is_in_conference(lc)){ stream=lc->conf_ctx.local_participant; } if (stream){ - return stream->dtmfgen; + if (rtype==LinphoneToneGenerator) return stream->dtmfgen; + if (rtype==LinphoneLocalPlayer) return stream->local_player; + return NULL; } if (lc->ringstream==NULL){ float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1); @@ -4858,14 +5657,21 @@ static MSFilter *get_dtmf_gen(LinphoneCore *lc){ if (ringcard == NULL) return NULL; - lc->ringstream=ring_start(NULL,0,ringcard); + ringstream=lc->ringstream=ring_start(NULL,0,ringcard); ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&); lc->dmfs_playing_start_time=time(NULL); }else{ + ringstream=lc->ringstream; if (lc->dmfs_playing_start_time!=0) lc->dmfs_playing_start_time=time(NULL); } - return lc->ringstream->gendtmf; + if (rtype==LinphoneToneGenerator) return ringstream->gendtmf; + if (rtype==LinphoneLocalPlayer) return ringstream->source; + return NULL; +} + +static MSFilter *get_dtmf_gen(LinphoneCore *lc){ + return get_audio_resource(lc,LinphoneToneGenerator); } /** @@ -4882,28 +5688,87 @@ 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); } /** - * @ingroup media_parameters - * Plays a repeated tone to the local user until next further call to #linphone_core_stop_dtmf() - * @param lc #LinphoneCore + * Plays an audio file to the local user. + * This function works at any time, during calls, or when no calls are running. + * It doesn't request the underlying audio system to support multiple playback streams. + * @param lc the linphone core + * @param audiofile path to audio file in wav PCM 16 bit format. + * @ingroup misc **/ -void linphone_core_play_tone(LinphoneCore *lc){ - MSFilter *f=get_dtmf_gen(lc); - MSDtmfGenCustomTone def; - if (f==NULL){ - ms_error("No dtmf generator at this time !"); - return; +int linphone_core_play_local(LinphoneCore *lc, const char *audiofile){ + MSFilter *f=get_audio_resource(lc,LinphoneLocalPlayer); + int loopms=-1; + if (!f) return -1; + ms_filter_call_method(f,MS_PLAYER_SET_LOOP,&loopms); + if (ms_filter_call_method(f,MS_PLAYER_OPEN,(void*)audiofile)!=0){ + return -1; + } + ms_filter_call_method_noarg(f,MS_PLAYER_START); + return 0; +} + +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ + if (linphone_core_tone_indications_enabled(lc)){ + const char *audiofile=linphone_core_get_tone_file(lc,toneid); + if (!audiofile){ + MSFilter *f=get_dtmf_gen(lc); + MSDtmfGenCustomTone def; + if (f==NULL){ + ms_error("No dtmf generator at this time !"); + return; + } + memset(&def,0,sizeof(def)); + def.amplitude=1; + /*these are french tones, excepted the failed one, which is USA congestion tone (does not exist in France)*/ + switch(toneid){ + case LinphoneToneCallOnHold: + case LinphoneToneCallWaiting: + def.duration=300; + def.frequencies[0]=440; + def.interval=2000; + break; + case LinphoneToneBusy: + def.duration=500; + def.frequencies[0]=440; + def.interval=500; + def.repeat_count=3; + break; + case LinphoneToneCallLost: + def.duration=250; + def.frequencies[0]=480; + def.frequencies[0]=620; + def.interval=250; + def.repeat_count=3; + + break; + default: + ms_warning("Unhandled tone id."); + } + if (def.duration>0) + ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); + }else{ + linphone_core_play_local(lc,audiofile); + } + } +} + +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason){ + if (linphone_core_tone_indications_enabled(lc)){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + if (tone->audiofile){ + linphone_core_play_local(lc,tone->audiofile); + }else if (tone->toneid!=LinphoneToneUndefined){ + linphone_core_play_named_tone(lc,tone->toneid); + } + } } - def.duration=300; - def.frequency=500; - def.amplitude=1; - def.interval=2000; - ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); } /** @@ -4924,7 +5789,7 @@ void linphone_core_stop_dtmf(LinphoneCore *lc){ * * @ingroup initializing **/ -void *linphone_core_get_user_data(LinphoneCore *lc){ +void *linphone_core_get_user_data(const LinphoneCore *lc){ return lc->data; } @@ -4946,7 +5811,7 @@ int linphone_core_get_mtu(const LinphoneCore *lc){ * Sets the maximum transmission unit size in bytes. * This information is useful for sending RTP packets. * Default value is 1500. - * + * * @ingroup media_parameters **/ void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ @@ -4961,7 +5826,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; } @@ -4976,11 +5841,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); } } @@ -4996,12 +5857,13 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran /** * Retrieve RTP statistics regarding current call. + * @param lc the LinphoneCore * @param local RTP statistics computed locally. * @param remote RTP statistics computed by far end (obtained via RTCP feedback). * * @note Remote RTP statistics is not implemented yet. * - * @returns 0 or -1 if no call is running. + * @return 0 or -1 if no call is running. **/ int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote){ @@ -5021,7 +5883,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); @@ -5039,44 +5905,65 @@ 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); lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout); lp_config_set_int(lc->config,"sip","delayed_timeout",config->delayed_timeout); - lp_config_set_int(lc->config,"sip","use_info",config->use_info); - lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833); lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); 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); - + if (lc->network_reachable) { + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + _linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */ + } - for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); - linphone_proxy_config_edit(cfg); /* to unregister */ + ms_message("Unregistration started."); + + for (i=0;i<20&&still_registered;i++){ + still_registered=FALSE; + sal_iterate(lc->sal); + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg); + still_registered|=(state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress); + } + ms_usleep(100000); + } + if (i>=20) ms_warning("Cannot complete unregistration, giving up"); } + config->proxies=ms_list_free_with_data(config->proxies,(void (*)(void*)) _linphone_proxy_config_release); - for (i=0;i<20;i++){ - sal_iterate(lc->sal); -#ifndef WIN32 - usleep(100000); -#else - Sleep(100); + config->deleted_proxies=ms_list_free_with_data(config->deleted_proxies,(void (*)(void*)) _linphone_proxy_config_release); + + /*no longuer need to write proxy config if not changedlinphone_proxy_config_write_to_config_file(lc->config,NULL,i);*/ /*mark the end */ + + lc->auth_info=ms_list_free_with_data(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); + + /*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*/ + if (lc->http_provider) { + belle_sip_object_unref(lc->http_provider); + lc->http_provider=NULL; } - - 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 */ - - ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); - ms_list_free(lc->auth_info); - lc->auth_info=NULL; - + if (lc->http_verify_policy){ + belle_sip_object_unref(lc->http_verify_policy); + lc->http_verify_policy=NULL; + } + sal_iterate(lc->sal); /*make sure event are purged*/ sal_uninit(lc->sal); lc->sal=NULL; @@ -5105,6 +5992,9 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); + ms_free(lc->rtp_conf.audio_multicast_addr); + ms_free(lc->rtp_conf.video_multicast_addr); + ms_free(config->srtp_suites); } static void sound_config_uninit(LinphoneCore *lc) @@ -5118,7 +6008,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(); + lc->tones=ms_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy); } static void video_config_uninit(LinphoneCore *lc) @@ -5168,17 +6058,23 @@ void _linphone_core_codec_config_write(LinphoneCore *lc){ static void codecs_config_uninit(LinphoneCore *lc) { _linphone_core_codec_config_write(lc); - ms_list_free(lc->codecs_conf.audio_codecs); - ms_list_free(lc->codecs_conf.video_codecs); + ms_list_free_with_data(lc->codecs_conf.audio_codecs, (void (*)(void*))payload_type_destroy); + ms_list_free_with_data(lc->codecs_conf.video_codecs, (void (*)(void*))payload_type_destroy); } 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_for_each(lc->friends,(void (*)(void *))linphone_friend_unref); 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."); } /** @@ -5189,32 +6085,28 @@ 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); + linphone_task_list_free(&lc->hooks); + lc->video_conf.show_local = FALSE; + while(lc->calls) { 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 @@ -5223,56 +6115,79 @@ 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 + + ms_list_for_each(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release); + lc->chatrooms = ms_list_free(lc->chatrooms); + 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); + ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_unref); lc->call_logs=ms_list_free(lc->call_logs); - + ms_list_for_each(lc->last_recv_msg_ids,ms_free); lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); - - // Free struct variable + if(lc->zrtp_secrets_cache != NULL) { ms_free(lc->zrtp_secrets_cache); } + if(lc->user_certificates_path != NULL) { + ms_free(lc->user_certificates_path); + } if(lc->play_file!=NULL){ ms_free(lc->play_file); } if(lc->rec_file!=NULL){ ms_free(lc->rec_file); } - + if (lc->chat_db_file){ + ms_free(lc->chat_db_file); + } + if(lc->presence_model){ + linphone_presence_model_unref(lc->presence_model); + } linphone_core_free_payload_types(lc); - ortp_exit(); + if (lc->supported_formats) ms_free(lc->supported_formats); + linphone_core_message_storage_close(lc); + ms_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); -#ifdef TUNNEL_ENABLED - if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); -#endif + linphone_core_deactivate_log_serialization_if_needed(); + ms_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy); } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ // 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. + lc->network_reachable_to_be_notified=TRUE; 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; @@ -5281,9 +6196,25 @@ 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 && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { + lc->upnp = linphone_upnp_context_new(lc); + } + } else { + if(!isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } + } +#endif } void linphone_core_refresh_registers(LinphoneCore* lc) { @@ -5358,11 +6289,40 @@ bool_t linphone_core_can_we_add_call(LinphoneCore *lc) return FALSE; } +static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){ + MSSndCard *card=lc->sound_conf.capt_sndcard; + if (card && ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW){ + ms_snd_card_set_usage_hint(card,used); + } +} + +void linphone_core_soundcard_hint_check( LinphoneCore* lc){ + MSList* the_calls = lc->calls; + LinphoneCall* call = NULL; + bool_t dont_need_sound = TRUE; + bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE); + + /* check if the remaining calls are paused */ + while( the_calls ){ + call = the_calls->data; + if( call->state != LinphoneCallPausing && call->state != LinphoneCallPaused ){ + dont_need_sound = FALSE; + break; + } + the_calls = the_calls->next; + } + + /* if no more calls or all calls are paused, we can free the soundcard */ + if ( (lc->calls==NULL || dont_need_sound) && !lc->use_files && !use_rtp_io){ + ms_message("Notifying soundcard that we don't need it anymore for calls."); + notify_soundcard_usage(lc,FALSE); + } +} int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) { - if(linphone_core_can_we_add_call(lc)) - { + if (linphone_core_can_we_add_call(lc)){ + if (lc->calls==NULL) notify_soundcard_usage(lc,TRUE); lc->calls = ms_list_append(lc->calls,call); return 0; } @@ -5385,12 +6345,10 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) return -1; } lc->calls = the_calls; + return 0; } -/** - * Specifiies 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){ ms_free(lc->sound_conf.ringback_tone); @@ -5400,29 +6358,20 @@ void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){ lc->sound_conf.ringback_tone=ms_strdup(file); } -/** - * Returns the ring back tone played to far end during incoming calls. -**/ const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc){ return lc->sound_conf.ringback_tone; } -static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const MSList* from) { - const MSList *elem; - for(elem=from;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - if ((strcasecmp((char*)type, payload_type_get_mime(pt)) == 0) - && (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate==pt->clock_rate) - && (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels==pt->channels)) { - return pt; - } - } - return NULL; +void linphone_core_set_ring_during_incoming_early_media(LinphoneCore *lc, bool_t enable) { + lp_config_set_int(lc->config, "sound", "ring_during_incoming_early_media", (int)enable); } +bool_t linphone_core_get_ring_during_incoming_early_media(const LinphoneCore *lc) { + return (bool_t)lp_config_get_int(lc->config, "sound", "ring_during_incoming_early_media", 0); +} -PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) { - PayloadType* result = find_payload_type_from_list(type, rate, channels, linphone_core_get_audio_codecs(lc)); +LinphonePayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) { + LinphonePayloadType* result = find_payload_type_from_list(type, rate, channels, linphone_core_get_audio_codecs(lc)); if (result) { return result; } else { @@ -5435,6 +6384,21 @@ PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, return NULL; } +const char* linphone_configuring_state_to_string(LinphoneConfiguringState cs){ + switch(cs){ + case LinphoneConfiguringSuccessful: + return "LinphoneConfiguringSuccessful"; + break; + case LinphoneConfiguringFailed: + return "LinphoneConfiguringFailed"; + break; + case LinphoneConfiguringSkipped: + return "LinphoneConfiguringSkipped"; + break; + } + return NULL; +} + const char *linphone_global_state_to_string(LinphoneGlobalState gs){ switch(gs){ case LinphoneGlobalOff: @@ -5448,6 +6412,8 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs){ break; case LinphoneGlobalShutdown: return "LinphoneGlobalShutdown"; + case LinphoneGlobalConfiguring: + return "LinphoneGlobalConfiguring"; break; } return NULL; @@ -5458,18 +6424,32 @@ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){ } LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc){ - LinphoneCallParams *p=ms_new0(LinphoneCallParams,1); + LinphoneCallParams *p=linphone_call_params_new(); linphone_core_init_default_params(lc, p); return p; } +/** + * Create a LinphoneCallParams suitable for linphone_core_invite_with_params(), linphone_core_accept_call_with_params(), linphone_core_accept_early_media_with_params(), + * linphone_core_accept_call_update(). + * The parameters are initialized according to the current LinphoneCore configuration and the current state of the LinphoneCall. + * @param lc the LinphoneCore + * @param call the call for which the parameters are to be build, or NULL in the case where the parameters are to be used for a new outgoing call. + * @return a new LinphoneCallParams + * @ingroup call_control + */ +LinphoneCallParams *linphone_core_create_call_params(LinphoneCore *lc, LinphoneCall *call){ + if (!call) return linphone_core_create_default_call_parameters(lc); + return linphone_call_params_copy(call->params); +} + const char *linphone_reason_to_string(LinphoneReason err){ switch(err){ case LinphoneReasonNone: return "No error"; case LinphoneReasonNoResponse: return "No response"; - case LinphoneReasonBadCredentials: + case LinphoneReasonForbidden: return "Bad credentials"; case LinphoneReasonDeclined: return "Call declined"; @@ -5479,6 +6459,34 @@ 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"; + case LinphoneReasonNoMatch: + return "No match"; + case LinphoneReasonMovedPermanently: + return "Moved permanently"; + case LinphoneReasonGone: + return "Gone"; + case LinphoneReasonTemporarilyUnavailable: + return "Temporarily unavailable"; + case LinphoneReasonAddressIncomplete: + return "Address incomplete"; + case LinphoneReasonNotImplemented: + return "Not implemented"; + case LinphoneReasonBadGateway: + return "Bad gateway"; + case LinphoneReasonServerTimeout: + return "Server timeout"; + case LinphoneReasonUnknown: + return "Unknown error"; } return "unknown error"; } @@ -5514,10 +6522,31 @@ 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) { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (lc->ringstream) { ring_stop(lc->ringstream); lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + lc->ringstream_autorelease=TRUE; + } + if (call && call->ringing_beep){ + linphone_core_stop_dtmf(lc); + call->ringing_beep=FALSE; + } +} + +void linphone_core_stop_dtmf_stream(LinphoneCore* lc) { + if (lc->dmfs_playing_start_time!=0) { + linphone_core_stop_ringing(lc); } } @@ -5528,47 +6557,18 @@ void linphone_core_set_max_calls(LinphoneCore *lc, int max) { lc->max_calls=max; } -typedef struct Hook{ - LinphoneCoreIterateHook fun; - void *data; -}Hook; - -static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){ - Hook *h=ms_new(Hook,1); - h->fun=hook; - h->data=hook_data; - return h; -} - -static void hook_invoke(Hook *h){ - h->fun(h->data); -} void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){ - lc->hooks=ms_list_append(lc->hooks,hook_new(hook,hook_data)); + linphone_task_list_add(&lc->hooks, hook, hook_data); } static void linphone_core_run_hooks(LinphoneCore *lc){ - ms_list_for_each(lc->hooks,(void (*)(void*))hook_invoke); -} - -static void linphone_core_free_hooks(LinphoneCore *lc){ - ms_list_for_each(lc->hooks,(void (*)(void*))ms_free); - ms_list_free(lc->hooks); - lc->hooks=NULL; + linphone_task_list_run(&lc->hooks); } void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){ - MSList *elem; - for(elem=lc->hooks;elem!=NULL;elem=elem->next){ - Hook *h=(Hook*)elem->data; - if (h->fun==hook && h->data==hook_data){ - lc->hooks = ms_list_remove_link(lc->hooks,elem); - ms_free(h); - return; - } - } - ms_error("linphone_core_remove_iterate_hook(): No such hook found."); + linphone_task_list_remove(&lc->hooks, hook, hook_data); + } void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){ @@ -5582,9 +6582,21 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ return lc->zrtp_secrets_cache; } -const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri) { +void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){ + char* new_value; + new_value = path?ms_strdup(path):NULL; + if (lc->user_certificates_path) ms_free(lc->user_certificates_path); + lp_config_set_string(lc->config,"misc","user_certificates_path",lc->user_certificates_path=new_value); + return ; +} + +const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){ + return lc->user_certificates_path; +} + +LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) { MSList *calls; - const LinphoneCall *c; + LinphoneCall *c; const LinphoneAddress *address; char *current_uri; @@ -5613,10 +6625,9 @@ const LinphoneCall* linphone_core_find_call_from_uri(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: @@ -5626,6 +6637,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; @@ -5638,36 +6650,75 @@ void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) { lp_config_set_int(lc->config,"sip","srtp",(int)enabled); } -/** - * Returns whether a media encryption scheme is supported by the LinphoneCore engine -**/ +const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){ + switch(menc){ + case LinphoneMediaEncryptionSRTP: + return "LinphoneMediaEncryptionSRTP"; + case LinphoneMediaEncryptionDTLS: + return "LinphoneMediaEncryptionDTLS"; + case LinphoneMediaEncryptionZRTP: + return "LinphoneMediaEncryptionZRTP"; + case LinphoneMediaEncryptionNone: + return "LinphoneMediaEncryptionNone"; + } + ms_error("Invalid LinphoneMediaEncryption value %i",(int)menc); + return "INVALID"; +} + + bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){ switch(menc){ case LinphoneMediaEncryptionSRTP: - return ortp_srtp_supported(); + return ms_srtp_supported(); + case LinphoneMediaEncryptionDTLS: + return ms_dtls_srtp_available(); case LinphoneMediaEncryptionZRTP: - return ortp_zrtp_available(); + return ms_zrtp_available(); case LinphoneMediaEncryptionNone: return TRUE; } 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){ - if (!ortp_srtp_supported()){ - ms_warning("SRTP not supported by library."); - type="none"; - ret=-1; - }else type="srtp"; - }else if (menc == LinphoneMediaEncryptionZRTP){ - if (!ortp_zrtp_available()){ - ms_warning("ZRTP not supported by library."); - type="none"; - ret=-1; - }else type="zrtp"; + int ret=-1; + + switch(menc){ + case LinphoneMediaEncryptionSRTP: + if (!ms_srtp_supported()){ + ms_warning("SRTP not supported by library."); + type="none"; + ret=-1; + }else{ + type="srtp"; + ret = 0; + } + break; + case LinphoneMediaEncryptionZRTP: + if (!ms_zrtp_available()){ + ms_warning("ZRTP not supported by library."); + type="none"; + ret=-1; + }else { + type="zrtp"; + ret = 0; + } + break; + case LinphoneMediaEncryptionDTLS: + if (!ms_dtls_srtp_available()){ + ms_warning("DTLS not supported by library."); + type="none"; + ret=-1; + }else { + type="dtls"; + ret = 0; + } + break; + case LinphoneMediaEncryptionNone: + type = "none"; + ret = 0; + break; } lp_config_set_string(lc->config,"sip","media_encryption",type); return ret; @@ -5675,11 +6726,13 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncry LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) { const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL); - + if (menc == NULL) return LinphoneMediaEncryptionNone; else if (strcmp(menc, "srtp")==0) return LinphoneMediaEncryptionSRTP; + else if (strcmp(menc, "dtls")==0) + return LinphoneMediaEncryptionDTLS; else if (strcmp(menc, "zrtp")==0) return LinphoneMediaEncryptionZRTP; else @@ -5698,6 +6751,13 @@ 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; + params->avpf_enabled=FALSE; + params->audio_dir=LinphoneMediaDirectionSendRecv; + params->video_dir=LinphoneMediaDirectionSendRecv; + params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE); + params->audio_multicast_enabled=linphone_core_audio_multicast_enabled(lc); + params->video_multicast_enabled=linphone_core_video_multicast_enabled(lc); } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { @@ -5710,25 +6770,25 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) { /** * Set the DSCP field for SIP signaling channel. - * + * * @ingroup network_parameters * * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ sal_set_dscp(lc->sal,dscp); if (linphone_core_ready(lc)){ lp_config_set_int_hex(lc->config,"sip","dscp",dscp); - apply_transports(lc); + _linphone_core_apply_transports(lc); } } /** * Get the DSCP field for SIP signaling channel. - * + * * @ingroup network_parameters * * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_sip_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"sip","dscp",0x1a); @@ -5739,7 +6799,7 @@ int linphone_core_get_sip_dscp(const LinphoneCore *lc){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){ if (linphone_core_ready(lc)) @@ -5751,7 +6811,7 @@ void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_audio_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e); @@ -5762,12 +6822,12 @@ int linphone_core_get_audio_dscp(const LinphoneCore *lc){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ if (linphone_core_ready(lc)) lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp); - + } /** @@ -5775,8 +6835,253 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_video_dscp(const LinphoneCore *lc){ - return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e); + return lp_config_get_int(lc->config,"rtp","video_dscp",0); +} + + +/** + * Sets the database filename where chat messages will be stored. + * If the file does not exist, it will be created. + * @ingroup initializing + * @param lc the linphone core + * @param path filesystem path +**/ +void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ + if (lc->chat_db_file){ + ms_free(lc->chat_db_file); + lc->chat_db_file=NULL; + } + if (path) { + lc->chat_db_file=ms_strdup(path); + linphone_core_message_storage_init(lc); + } +} +void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable) { + lp_config_set_int(lc->config,"sip","sdp_200_ack",lc->sip_conf.sdp_200_ack=enable); +} +bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) { + return lc->sip_conf.sdp_200_ack!=0; +} + +void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) { + lp_config_set_string(core->config, "misc", "file_transfer_server_url", server_url); +} + +const char * linphone_core_get_file_transfer_server(LinphoneCore *core) { + return lp_config_get_string(core->config, "misc", "file_transfer_server_url", NULL); +} + +/** + * This function controls signaling features supported by the core. + * They are typically included in a SIP Supported header. + * @param lc the LinphoneCore + * @param tag the feature tag name + * @ingroup initializing +**/ +void linphone_core_add_supported_tag(LinphoneCore *lc, const char *tag){ + sal_add_supported_tag(lc->sal,tag); + lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal)); +} + +/** + * Remove a supported tag. @see linphone_core_add_supported_tag() + * @param lc the LinphoneCore + * @param tag the tag to remove + * @ingroup initializing +**/ +void linphone_core_remove_supported_tag(LinphoneCore *lc, const char *tag){ + sal_remove_supported_tag(lc->sal,tag); + lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal)); +} + +/** + * Enable RTCP feedback (also known as RTP/AVPF profile). + * Setting LinphoneAVPFDefault is equivalent to LinphoneAVPFDisabled. + * This setting can be overriden per LinphoneProxyConfig with linphone_proxy_config_set_avpf_mode(). + * The value set here is used for calls placed or received out of any proxy configured, or if the proxy config is configured with LinphoneAVPFDefault. + * @param lc the LinphoneCore + * @param mode the mode. + * @ingroup media_parameters +**/ +void linphone_core_set_avpf_mode(LinphoneCore *lc, LinphoneAVPFMode mode){ + if (mode==LinphoneAVPFDefault) mode=LinphoneAVPFDisabled; + lc->rtp_conf.avpf_mode=mode; + if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"rtp","avpf",mode); +} + +/** + * Return AVPF enablement. See linphone_core_set_avpf_mode() . + * @param lc the core + * @return the avpf enablement mode. + * @ingroup media_parameters +**/ +LinphoneAVPFMode linphone_core_get_avpf_mode(const LinphoneCore *lc){ + return lc->rtp_conf.avpf_mode; +} + +/** + * Return the avpf report interval in seconds. + * @param lc the LinphoneCore + * @return the avpf report interval in seconds. + * @ingroup media_parameters +**/ +int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"rtp","avpf_rr_interval",5); +} + +/** + * Set the avpf report interval in seconds. + * This value can be overriden by the proxy config using linphone_proxy_config_set_avpf_rr_interval(). + * @param lc the core + * @param interval interval in seconds. + * @ingroup media_parameters +**/ +void linphone_core_set_avpf_rr_interval(LinphoneCore *lc, int interval){ + lp_config_set_int(lc->config,"rtp","avpf_rr_interval",interval); +} + +int linphone_payload_type_get_type(const LinphonePayloadType *pt) { + return pt->type; +} + +int linphone_payload_type_get_normal_bitrate(const LinphonePayloadType *pt) { + return pt->normal_bitrate; +} + +const char * linphone_payload_type_get_mime_type(const LinphonePayloadType *pt) { + return pt->mime_type; +} + +int linphone_payload_type_get_channels(const LinphonePayloadType *pt) { + return pt->channels; +} + +int linphone_core_set_audio_multicast_addr(LinphoneCore *lc, const char* ip) { + char* new_value; + if (ip && !ms_is_multicast(ip)) { + ms_error("Cannot set multicast audio addr to core [%p] because [%s] is not multicast",lc,ip); + return -1; + } + new_value = ip?ms_strdup(ip):NULL; + if (lc->rtp_conf.audio_multicast_addr) ms_free(lc->rtp_conf.audio_multicast_addr); + lp_config_set_string(lc->config,"rtp","audio_multicast_addr",lc->rtp_conf.audio_multicast_addr=new_value); + return 0; +} + +int linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char* ip) { + char* new_value; + if (ip && !ms_is_multicast(ip)) { + ms_error("Cannot set multicast video addr to core [%p] because [%s] is not multicast",lc,ip); + return -1; + } + new_value = ip?ms_strdup(ip):NULL; + if (lc->rtp_conf.video_multicast_addr) ms_free(lc->rtp_conf.video_multicast_addr); + lp_config_set_string(lc->config,"rtp","video_multicast_addr",lc->rtp_conf.video_multicast_addr=new_value); + return 0; +} + +const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *lc) { + return lc->rtp_conf.audio_multicast_addr; +} + +const char* linphone_core_get_video_multicast_addr(const LinphoneCore *lc){ + return lc->rtp_conf.video_multicast_addr; +} + +int linphone_core_set_audio_multicast_ttl(LinphoneCore *lc, int ttl) { + if (ttl>255) { + ms_error("Cannot set multicast audio ttl to core [%p] to [%i] value must be <256",lc,ttl); + return -1; + } + + lp_config_set_int(lc->config,"rtp","audio_multicast_ttl",lc->rtp_conf.audio_multicast_ttl=ttl); + return 0; +} + +int linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl) { + if (ttl>255) { + ms_error("Cannot set multicast video ttl to core [%p] to [%i] value must be <256",lc,ttl); + return -1; + } + + lp_config_set_int(lc->config,"rtp","video_multicast_ttl",lc->rtp_conf.video_multicast_ttl=ttl); + return 0; +} + +int linphone_core_get_audio_multicast_ttl(const LinphoneCore *lc) { + return lc->rtp_conf.audio_multicast_ttl; +} + + +int linphone_core_get_video_multicast_ttl(const LinphoneCore *lc){ + return lc->rtp_conf.video_multicast_ttl; +} + +void linphone_core_enable_audio_multicast(LinphoneCore *lc, bool_t yesno) { + lp_config_set_int(lc->config,"rtp","audio_multicast_enabled",lc->rtp_conf.audio_multicast_enabled=yesno); +} + + bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *lc) { + return lc->rtp_conf.audio_multicast_enabled; +} + +void linphone_core_enable_video_multicast(LinphoneCore *lc, bool_t yesno) { + lp_config_set_int(lc->config,"rtp","video_multicast_enabled",lc->rtp_conf.video_multicast_enabled=yesno); +} + +bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) { + return lc->rtp_conf.video_multicast_enabled; +} + +void linphone_core_set_video_preset(LinphoneCore *lc, const char *preset) { + lp_config_set_string(lc->config, "video", "preset", preset); +} + +const char * linphone_core_get_video_preset(const LinphoneCore *lc) { + return lp_config_get_string(lc->config, "video", "preset", NULL); +} + +#ifdef ANDROID +static int linphone_core_call_void_method(jobject obj, jmethodID id) { + JNIEnv *env=ms_get_jni_env(); + if (env && obj) { + (*env)->CallVoidMethod(env,obj,id); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + return -1; + } else + return 0; + } else + return -1; +} + +void linphone_core_wifi_lock_acquire(LinphoneCore *lc) { + if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_acquire_id)) + ms_warning("No wifi lock configured or not usable for core [%p]",lc); +} +void linphone_core_wifi_lock_release(LinphoneCore *lc) { + if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_release_id)) + ms_warning("No wifi lock configured or not usable for core [%p]",lc); +} +void linphone_core_multicast_lock_acquire(LinphoneCore *lc) { + if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_acquire_id)) + ms_warning("No multicast lock configured or not usable for core [%p]",lc); +} +void linphone_core_multicast_lock_release(LinphoneCore *lc) { + if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_release_id)) + ms_warning("No wifi lock configured or not usable for core [%p]",lc); +} +#endif + + +LINPHONE_PUBLIC const char *linphone_core_log_collection_upload_state_to_string(const LinphoneCoreLogCollectionUploadState lcus) { + switch (lcus) { + case LinphoneCoreLogCollectionUploadStateInProgress : return "LinphoneCoreLogCollectionUploadStateInProgress"; + case LinphoneCoreLogCollectionUploadStateDelivered : return "LinphoneCoreLogCollectionUploadStateDelivered"; + case LinphoneCoreLogCollectionUploadStateNotDelivered : return "LinphoneCoreLogCollectionUploadStateNotDelivered"; + } + return "UNKNOWN"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2012492c4..cdc275bb1 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -23,6 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "ortp/payloadtype.h" #include "mediastreamer2/mscommon.h" #include "mediastreamer2/msvideo.h" +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/bitratecontrol.h" #ifdef IN_LINPHONE #include "sipsetup.h" @@ -30,13 +32,13 @@ 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 -#ifdef LIBLINPHONE_EXPORTS -#define LINPHONE_PUBLIC __declspec(dllexport) -#else -#define LINPHONE_PUBLIC __declspec(dllimport) +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC #endif #ifdef __cplusplus @@ -50,17 +52,62 @@ 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 -struct _LCSipTransports{ +/** + * Linphone core SIP transport ports. + * Use with #linphone_core_set_sip_transports + * @ingroup initializing + */ +typedef struct _LCSipTransports{ + /** + * udp port to listening on, negative value if not set + * */ int udp_port; + /** + * tcp port to listening on, negative value if not set + * */ int tcp_port; + /** + * dtls port to listening on, negative value if not set + * */ int dtls_port; + /** + * tls port to listening on, negative value if not set + * */ int tls_port; -}; +} LCSipTransports; -typedef struct _LCSipTransports LCSipTransports; + +/** + * Enum describing transport type for LinphoneAddress. + * @ingroup linphone_address +**/ +enum _LinphoneTransportType{ + LinphoneTransportUdp, + LinphoneTransportTcp, + LinphoneTransportTls, + LinphoneTransportDtls +}; +/*this enum MUST be kept in sync with the SalTransport from sal.h*/ + +/** + * Typedef for transport type enum. + * @ingroup linphone_address +**/ +typedef enum _LinphoneTransportType LinphoneTransportType; /** * Object that represents a SIP address. @@ -74,175 +121,10 @@ typedef struct _LCSipTransports LCSipTransports; * return NULL. * * @ingroup linphone_address - * @var LinphoneAddress */ typedef struct SalAddress LinphoneAddress; -#ifdef IN_LINPHONE -#include "linphonefriend.h" -#else -#include "linphone/linphonefriend.h" -#endif -LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *uri); -LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri); -const char *linphone_address_get_scheme(const LinphoneAddress *u); -LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u); -LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u); -LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u); -/** - * Get port number as an integer value. - * - */ -int linphone_address_get_port_int(const LinphoneAddress *u); -/** - * Get port number, null if not present. - */ -const char* linphone_address_get_port(const LinphoneAddress *u); -LINPHONE_PUBLIC void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name); -LINPHONE_PUBLIC void linphone_address_set_username(LinphoneAddress *uri, const char *username); -LINPHONE_PUBLIC void linphone_address_set_domain(LinphoneAddress *uri, const char *host); -void linphone_address_set_port(LinphoneAddress *uri, const char *port); -void linphone_address_set_port_int(LinphoneAddress *uri, int port); -/*remove tags, params etc... so that it is displayable to the user*/ -LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri); -LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u); -char *linphone_address_as_string_uri_only(const LinphoneAddress *u); -LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); -LINPHONE_PUBLIC void linphone_address_destroy(LinphoneAddress *u); - -struct _SipSetupContext; - - -/** - * Enum representing the direction of a call. - * @ingroup call_logs -**/ -enum _LinphoneCallDir { - LinphoneCallOutgoing, /**< outgoing calls*/ - LinphoneCallIncoming /**< incoming calls*/ -}; - -/** - * Typedef for enum - * @ingroup call_logs -**/ -typedef enum _LinphoneCallDir LinphoneCallDir; - -/** - * Enum representing the status of a call - * @ingroup call_logs -**/ -typedef enum _LinphoneCallStatus { - LinphoneCallSuccess, /**< The call was sucessful*/ - LinphoneCallAborted, /**< The call was aborted */ - LinphoneCallMissed, /**< The call was missed (unanswered)*/ - LinphoneCallDeclined /**< The call was declined, either locally or by remote end*/ -} LinphoneCallStatus; - -/** - * Structure representing a call log. - * - * @ingroup call_logs - * -**/ -typedef struct _LinphoneCallLog LinphoneCallLog; - -/** - * Enum describing type of media encryption types. -**/ -enum LinphoneMediaEncryption { - LinphoneMediaEncryptionNone, - LinphoneMediaEncryptionSRTP, - LinphoneMediaEncryptionZRTP -}; - -/** - * Enum describing type of media encryption types. -**/ -typedef enum LinphoneMediaEncryption LinphoneMediaEncryption; - -/*public: */ -LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl); -LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl); -LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl); -LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl); -LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl); -time_t linphone_call_log_get_start_date(LinphoneCallLog *cl); -int linphone_call_log_get_duration(LinphoneCallLog *cl); -float linphone_call_log_get_quality(LinphoneCallLog *cl); -void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up); -void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl); -void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey); -const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl); -const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl); -const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl); -const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl); -char * linphone_call_log_to_str(LinphoneCallLog *cl); - -struct _LinphoneCallParams; - -/** - * The LinphoneCallParams is an object containing various call related parameters. - * It can be used to retrieve parameters from a currently running call or modify the call's characteristics - * dynamically. -**/ -typedef struct _LinphoneCallParams LinphoneCallParams; - -const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp); -const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp); -LINPHONE_PUBLIC LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp); -LINPHONE_PUBLIC void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); -LINPHONE_PUBLIC bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp); -LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp); -void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e); -void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled); -bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp); -bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp); -void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw); -void linphone_call_params_destroy(LinphoneCallParams *cp); -bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp); -void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); -void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path); -const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); -void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); -const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); -/** - * Enum describing failure reasons. - * @ingroup initializing -**/ -enum _LinphoneReason{ - LinphoneReasonNone, - LinphoneReasonNoResponse, /** + */ + 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); + + +#ifdef IN_LINPHONE +#include "buffer.h" +#include "call_log.h" +#include "call_params.h" +#include "content.h" +#include "event.h" +#include "linphonefriend.h" +#include "xmlrpc.h" +#else +#include "linphone/buffer.h" +#include "linphone/call_log.h" +#include "linphone/call_params.h" +#include "linphone/content.h" +#include "linphone/event.h" +#include "linphone/linphonefriend.h" +#include "linphone/xmlrpc.h" +#endif + +LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr); +LINPHONE_PUBLIC LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr); +LINPHONE_PUBLIC LinphoneAddress * linphone_address_ref(LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_address_unref(LinphoneAddress *addr); +LINPHONE_PUBLIC const char *linphone_address_get_scheme(const LinphoneAddress *u); +LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u); +LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u); +LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u); +LINPHONE_PUBLIC int linphone_address_get_port(const LinphoneAddress *u); +LINPHONE_PUBLIC void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name); +LINPHONE_PUBLIC void linphone_address_set_username(LinphoneAddress *uri, const char *username); +LINPHONE_PUBLIC void linphone_address_set_domain(LinphoneAddress *uri, const char *host); +LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, int port); +/*remove tags, params etc... so that it is displayable to the user*/ +LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri); +LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *addr); +LINPHONE_PUBLIC bool_t linphone_address_get_secure(const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled); +LINPHONE_PUBLIC bool_t linphone_address_is_sip(const LinphoneAddress *uri); +LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri); +LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type); +LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u); +LINPHONE_PUBLIC char *linphone_address_as_string_uri_only(const LinphoneAddress *u); +LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); +LINPHONE_PUBLIC bool_t linphone_address_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); +LINPHONE_PUBLIC void linphone_address_set_password(LinphoneAddress *addr, const char *passwd); +LINPHONE_PUBLIC const char *linphone_address_get_password(const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_address_set_header(LinphoneAddress *addr, const char *header_name, const char *header_value); +LINPHONE_PUBLIC void linphone_address_destroy(LinphoneAddress *u); + +/** + * Create a #LinphoneAddress object by parsing the user supplied address, given as a string. + * @param[in] lc #LinphoneCore object + * @param[in] address String containing the user supplied address + * @return The create #LinphoneAddress object + * @ingroup linphone_address + */ +LINPHONE_PUBLIC LinphoneAddress * linphone_core_create_address(LinphoneCore *lc, const char *address); + +struct _SipSetupContext; + + +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 void linphone_info_message_destroy(LinphoneInfoMessage *im); +LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig); + + + +/** + * Structure describing policy regarding video streams establishments. + * @ingroup media_parameters +**/ +struct _LinphoneVideoPolicy{ + bool_t automatically_initiate; /** 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 - */ -LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); -#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register -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. - * @param obj object pointer - * @param val if true, publish will be engaged - * - */ -LINPHONE_PUBLIC 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); - -LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); -LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); - -const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); -LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj); -bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj); -LINPHONE_PUBLIC 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); - -bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); -const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); - -LinphoneReason linphone_proxy_config_get_error(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); -SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig *cfg); -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); -/* - * attached a user data to a proxy config - */ -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); - /** * @} -**/ + */ -typedef struct _LinphoneAccountCreator{ - struct _LinphoneCore *lc; - struct _SipSetupContext *ssctx; - char *username; - char *password; - char *domain; - char *route; - char *email; - int suscribe; - bool_t succeeded; -}LinphoneAccountCreator; - -LinphoneAccountCreator *linphone_account_creator_new(struct _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); -void linphone_account_creator_set_route(LinphoneAccountCreator *obj, const char *route); -void linphone_account_creator_set_email(LinphoneAccountCreator *obj, const char *email); -void linphone_account_creator_set_suscribe(LinphoneAccountCreator *obj, int suscribre); -const char * linphone_account_creator_get_username(LinphoneAccountCreator *obj); -const char * linphone_account_creator_get_domain(LinphoneAccountCreator *obj); -int linphone_account_creator_test_existence(LinphoneAccountCreator *obj); -int linphone_account_creator_test_validation(LinphoneAccountCreator *obj); -LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj); -void linphone_account_creator_destroy(LinphoneAccountCreator *obj); +#include "linphone_proxy_config.h" struct _LinphoneAuthInfo; /** - * @ingroup authentication + * @addtogroup authentication + * @{ * Object holding authentication information. * * @note The object's fields should not be accessed directly. Prefer using @@ -617,19 +1020,137 @@ struct _LinphoneAuthInfo; **/ typedef struct _LinphoneAuthInfo LinphoneAuthInfo; +/** + * Creates a #LinphoneAuthInfo object with supplied information. + * The object can be created empty, that is with all arguments set to NULL. + * 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 object. 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(). +**/ LINPHONE_PUBLIC 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); + const char *passwd, const char *ha1,const char *realm, const char *domain); -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); +/** + * @addtogroup authentication + * Instantiates a new auth info with values from source. + * @param[in] source The #LinphoneAuthInfo object to be cloned + * @return The newly created #LinphoneAuthInfo object. + */ +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo* source); + +/** + * Sets the password. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] passwd The password. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); + +/** + * Sets the username. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] username The username. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); + +/** + * Sets the userid. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] userid The userid. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); + +/** + * Sets the realm. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] realm The realm. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); + +/** + * Sets the domain for which this authentication is valid. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] domain The domain. + * 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. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain); + +/** + * Sets the ha1. + * @param[in] info The #LinphoneAuthInfo object + * @param[in] ha1 The ha1. +**/ +LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); + +/** + * Gets the username. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The username. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthInfo *info); + +/** + * Gets the password. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The password. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *info); + +/** + * Gets the userid. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The userid. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *info); + +/** + * Gets the realm. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The realm. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *info); + +/** + * Gets the domain. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The domain. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *info); + +/** + * Gets the ha1. + * + * @param[in] info The #LinphoneAuthInfo object + * @return The ha1. + */ +LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *info); /* 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); +LINPHONE_PUBLIC void linphone_auth_info_destroy(LinphoneAuthInfo *info); +LINPHONE_PUBLIC LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); + +/** + * @} + */ + + +#ifdef IN_LINPHONE +#include "account_creator.h" +#else +#include "linphone/account_creator.h" +#endif struct _LinphoneChatRoom; @@ -639,11 +1160,16 @@ struct _LinphoneChatRoom; */ /** - * A chat room message to old content to be sent. + * An object to handle the callbacks for the handling a LinphoneChatMessage objects. + */ +typedef struct _LinphoneChatMessageCbs LinphoneChatMessageCbs; + +/** + * A chat room message to hold content to be sent. *
    Can be created by linphone_chat_room_create_message(). */ typedef struct _LinphoneChatMessage LinphoneChatMessage; - + /** * A chat room is the place where text messages are exchanged. *
    Can be created by linphone_core_create_chat_room(). @@ -651,47 +1177,547 @@ 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 #LinphoneCoreMessageReceivedCb 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); + +/** + * File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file. + * + * + * @param lc #LinphoneCore object + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent incoming content information + * @param buff pointer to the received data + * @param size number of bytes to be read from buff. 0 means end of file. + * + */ +typedef void (*LinphoneCoreFileTransferRecvCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size); + +/** + * File transfer send callback prototype. This function is called by the core upon an outgoing File transfer is started. This function is called until size is set to 0. + *
    a #LinphoneContent with a size equal zero + * + * @param lc #LinphoneCore object + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent outgoing content + * @param buff pointer to the buffer where data chunk shall be written by the app + * @param size as input value, it represents the number of bytes expected by the framework. As output value, it means the number of bytes wrote by the application in the buffer. 0 means end of file. + * + */ +typedef void (*LinphoneCoreFileTransferSendCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); + +/** + * File transfer progress indication callback prototype. + * + * @param lc #LinphoneCore object + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent incoming content information + * @param offset The number of bytes sent/received since the beginning of the transfer. + * @param total The total number of bytes to be sent/received. + */ +typedef void (*LinphoneCoreFileTransferProgressIndicationCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); + +/** + * Is composing notification callback prototype. + * + * @param[in] lc #LinphoneCore object + * @param[in] room #LinphoneChatRoom involved in the conversation. + */ +typedef void (*LinphoneCoreIsComposingReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room); + +/** + * Callback for being notified of DTMFs received. + * @param lc the linphone core + * @param call the call that received the dtmf + * @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); + +/** + * LinphoneGlobalState describes the global state of the LinphoneCore object. + * It is notified via the LinphoneCoreVTable::global_state_changed +**/ +typedef enum _LinphoneConfiguringState { + LinphoneConfiguringSuccessful, + LinphoneConfiguringFailed, + LinphoneConfiguringSkipped +} LinphoneConfiguringState; + +/** + * Converts a _LinphoneConfiguringState enum to a string. + * @ingroup misc +**/ +LINPHONE_PUBLIC const char *linphone_configuring_state_to_string(LinphoneConfiguringState cs); + +/** + * Callback prototype for configuring status changes notification + * @param lc the LinphoneCore + * @param message informational message. + */ +typedef void (*LinphoneCoreConfiguringStatusCb)(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); + +/** + * Callback prototype for reporting network change either automatically detected or notified by #linphone_core_set_network_reachable. + * @param lc the LinphoneCore + * @param reachable true if network is reachable. + */ +typedef void (*LinphoneCoreNetworkReachableCb)(LinphoneCore *lc, bool_t reachable); + +/** + * Callback prototype for reporting log collection upload state change. + * @param[in] lc LinphoneCore object + * @param[in] state The state of the log collection upload + * @param[in] info Additional information: error message in case of error state, URL of uploaded file in case of success. + */ +typedef void (*LinphoneCoreLogCollectionUploadStateChangedCb)(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info); + +/** + * Callback prototype for reporting log collection upload progress indication. + * @param[in] lc LinphoneCore object + * @param[in] progress Percentage of the file size of the log collection already uploaded. + */ +typedef void (*LinphoneCoreLogCollectionUploadProgressIndicationCb)(LinphoneCore *lc, size_t offset, size_t total); /** * 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 */ + LinphoneCoreFileTransferRecvCb file_transfer_recv; /**< @deprecated Callback to store file received attached to a #LinphoneChatMessage */ + LinphoneCoreFileTransferSendCb file_transfer_send; /**< @deprecated Callback to collect file chunk to be sent for a #LinphoneChatMessage */ + LinphoneCoreFileTransferProgressIndicationCb file_transfer_progress_indication; /**< @deprecated Callback to indicate file transfer progress */ + LinphoneCoreNetworkReachableCb network_reachable; /**< Callback to report IP network status (I.E up/down )*/ + LinphoneCoreLogCollectionUploadStateChangedCb log_collection_upload_state_changed; /**< Callback to upload collected logs */ + LinphoneCoreLogCollectionUploadProgressIndicationCb log_collection_upload_progress_indication; /**< Callback to indicate log collection upload progress */ + void *user_data; /**data field of the MSList points a PayloadType + * structure holding the codec information. + * It is possible to make copy of the list with ms_list_copy() in order to modify it + * (such as the order of codecs). + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); + +/** + * Returns the list of available video codecs. + * @param[in] lc The LinphoneCore object + * @return \mslist{PayloadType} + * + * This list is unmodifiable. The ->data field of the MSList points a PayloadType + * structure holding the codec information. + * It is possible to make copy of the list with ms_list_copy() in order to modify it + * (such as the order of codecs). + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); + +LINPHONE_PUBLIC void linphone_core_enable_generic_confort_noise(LinphoneCore *lc, bool_t enabled); + +LINPHONE_PUBLIC bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc); + +/** + * Tells whether the specified payload type is enabled. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #LinphonePayloadType we want to know is enabled or not. + * @return TRUE if the payload type is enabled, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const LinphonePayloadType *pt); + +/** + * Tells whether the specified payload type represents a variable bitrate codec. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #LinphonePayloadType we want to know + * @return TRUE if the payload type represents a VBR codec, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt); + +/** + * Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s. + * @param[in] lc the #LinphoneCore object + * @param[in] pt the #LinphonePayloadType to modify. + * @param[in] bitrate the IP bitrate in kbit/s. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, LinphonePayloadType *pt, int bitrate); + +/** + * Get the bitrate explicitely set with linphone_core_set_payload_type_bitrate(). + * @param[in] lc the #LinphoneCore object + * @param[in] pt the #LinphonePayloadType to modify. + * @return bitrate the IP bitrate in kbit/s, or -1 if an error occured. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const LinphonePayloadType *pt); + +/** + * Enable or disable the use of the specified payload type. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #LinphonePayloadType 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, LinphonePayloadType *pt, bool_t enable); + +/** + * Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algorithm * @ingroup media_parameters */ #define LINPHONE_FIND_PAYLOAD_IGNORE_RATE -1 /** - * Wildcard value used by #linphone_core_find_payload_type to ignore channel in search algirithm + * Wildcard value used by #linphone_core_find_payload_type to ignore channel in search algorithm * @ingroup media_parameters */ #define LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS -1 @@ -995,100 +2714,216 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadT * @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE * @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS * @return Returns NULL if not found. - */ -LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; - -int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); - -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 LinphonePayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; /** - * @ingroup proxy - *Create a proxy config with default value from Linphone core. - *@param lc #LinphoneCore object - *@return #LinphoneProxyConfig with defualt value set + * @ingroup media_parameters + * Returns the payload type number assigned for this codec. +**/ +LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); + +/** + * @ingroup media_parameters + * Force a number for a payload type. The LinphoneCore does payload type number assignment automatically. THis function is to be used mainly for tests, in order + * to override the automatic assignment mechanism. +**/ +LINPHONE_PUBLIC void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number); + +LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); + +LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt); + +/** + * @addtogroup proxies + * @{ */ -LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); - -LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -void linphone_core_clear_proxy_config(LinphoneCore *lc); +/** + * Create a proxy config with default values from Linphone core. + * @param[in] lc #LinphoneCore object + * @return #LinphoneProxyConfig with default values set + */ +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); -void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); +/** + * Add a proxy configuration. + * This will start registration on the proxy, if registration is enabled. +**/ +LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); +/** + * Erase all proxies from config. +**/ +LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc); -LINPHONE_PUBLIC void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); +/** + * Removes a proxy configuration. + * + * LinphoneCore will then automatically unregister and place the proxy configuration + * on a deleted list. For that reason, a removed proxy does NOT need to be freed. +**/ +LINPHONE_PUBLIC void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); +/** + * Returns an unmodifiable list of entered proxy configurations. + * @param[in] lc The LinphoneCore object + * @return \mslist{LinphoneProxyConfig} +**/ +LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); -LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); +/** @deprecated Use linphone_core_set_default_proxy_config() instead. */ +#define linphone_core_set_default_proxy(lc, config) linphone_core_set_default_proxy_config(lc, config) + +LINPHONE_PUBLIC void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); + +/** + * @return the default proxy configuration, that is the one used to determine the current identity. + * @deprecated Use linphone_core_get_default_proxy_config() instead. +**/ +LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); + +/** + * @return the default proxy configuration, that is the one used to determine the current identity. + * @param[in] lc LinphoneCore object + * @return The default proxy configuration. +**/ +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_get_default_proxy_config(LinphoneCore *lc); + +/** + * Sets the default proxy. + * + * This default proxy must be part of the list of already entered LinphoneProxyConfig. + * Toggling it as default will make LinphoneCore use the identity associated with + * the proxy configuration in all incoming and outgoing calls. + * @param[in] lc LinphoneCore object + * @param[in] config The proxy configuration to use as the default one. +**/ +LINPHONE_PUBLIC void linphone_core_set_default_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); + +/** + * @} + */ + +/** + * 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) + * @param[in] domain String containing the SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain. + * @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); LINPHONE_PUBLIC void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); -void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); +LINPHONE_PUBLIC void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); -const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc); -const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username); +LINPHONE_PUBLIC const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *sip_domain); -void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info); +LINPHONE_PUBLIC void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info); -void linphone_core_clear_all_auth_info(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc); -void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +/** + * 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 + */ +LINPHONE_PUBLIC void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); -bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc); +/** + * Tells whether the audio adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @return TRUE if the audio adaptive jitter compensation is enabled, FALSE otherwise. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc); -int linphone_core_get_audio_jittcomp(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_audio_jittcomp(LinphoneCore *lc); -void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); +/** + * Sets the nominal audio jitter buffer size in milliseconds. + * The value takes effect immediately for all running and pending calls, if any. + * A value of 0 disables the jitter buffer. + * + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int milliseconds); -void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +/** + * 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 + */ +LINPHONE_PUBLIC void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); -bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc); +/** + * Tells whether the video adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @return TRUE if the video adaptive jitter compensation is enabled, FALSE otherwise. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc); -int linphone_core_get_video_jittcomp(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_video_jittcomp(LinphoneCore *lc); -void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value); +/** + * Sets the nominal video jitter buffer size in milliseconds. + * The value takes effect immediately for all running and pending calls, if any. + * A value of 0 disables the jitter buffer. + * + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_set_video_jittcomp(LinphoneCore *lc, int milliseconds); -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); LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); + +LINPHONE_PUBLIC void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr); + +LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp); /** * * Give access to the UDP sip socket. Can be useful to configure this socket as persistent I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP) @@ -1097,198 +2932,621 @@ LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTran */ 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 + * @return The STUN server address being used. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *lc); /** * @ingroup network_parameters * Return the availability of uPnP. * - * @param lc #LinphoneCore - * @return true if uPnP is available otherwise return false. + * @return true if uPnP is available otherwise return false. */ -bool_t linphone_core_upnp_available(const LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_upnp_available(void); /** * @ingroup network_parameters - * Return the internal state of uPnP. + * Return the internal state of uPnP. * * @param lc #LinphoneCore - * @return an LinphoneUpnpState. + * @return an LinphoneUpnpState. */ -LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); /** * @ingroup network_parameters - * Return the external ip address of router. + * Return the external ip address of router. * In some cases the uPnP can have an external ip address but not a usable uPnP - * (state different of Ok). + * (state different of Ok). * * @param lc #LinphoneCore * @return a null terminated string containing the external ip address. If the - * the external ip address is not available return null. + * the external ip address is not available return null. */ -const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); -void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); +/** + * 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 + */ +LINPHONE_PUBLIC void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); -const char *linphone_core_get_nat_address(const LinphoneCore *lc); +/** + * Get the public IP address of NAT being used. + * @param[in] lc #LinphoneCore object. + * @return The public IP address of NAT being used. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC 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. + * @return 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); -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); -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 const char** linphone_core_get_sound_devices(LinphoneCore *lc); -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); +/** + * 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 + **/ +LINPHONE_PUBLIC void linphone_core_reload_sound_devices(LinphoneCore *lc); -void linphone_core_set_rec_level(LinphoneCore *lc, int level); -const char * linphone_core_get_ringer_device(LinphoneCore *lc); -const char * linphone_core_get_playback_device(LinphoneCore *lc); -const char * linphone_core_get_capture_device(LinphoneCore *lc); -int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid); -int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); -int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device); +LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device); +LINPHONE_PUBLIC int linphone_core_get_ring_level(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_play_level(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_rec_level(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_ring_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC void linphone_core_set_play_level(LinphoneCore *lc, int level); + +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); + +LINPHONE_PUBLIC void linphone_core_set_rec_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC const char * linphone_core_get_ringer_device(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_playback_device(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_capture_device(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); char linphone_core_get_sound_source(LinphoneCore *lc); void linphone_core_set_sound_source(LinphoneCore *lc, char source); +LINPHONE_PUBLIC void linphone_core_stop_ringing(LinphoneCore *lc); LINPHONE_PUBLIC 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); +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); -const char * linphone_core_get_ringback(const LinphoneCore *lc); +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); +/** + * Specify a ring back tone to be played to far end during incoming calls. + * @param[in] lc #LinphoneCore object + * @param[in] ring The path to the ring back tone to be played. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *ring); -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); +/** + * Get the ring back tone played to far end during incoming calls. + * @param[in] lc #LinphoneCore object + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc); -void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); -bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); +/** + * Enable or disable the ring play during an incoming early media call. + * @param[in] lc #LinphoneCore object + * @param[in] enable A boolean value telling whether to enable ringing during an incoming early media call. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC void linphone_core_set_ring_during_incoming_early_media(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether the ring play is enabled during an incoming early media call. + * @param[in] lc #LinphoneCore object + * @ingroup media_paramaters + */ +LINPHONE_PUBLIC bool_t linphone_core_get_ring_during_incoming_early_media(const LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); +LINPHONE_PUBLIC int linphone_core_play_local(LinphoneCore *lc, const char *audiofile); +LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); + +/** + * 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. + * @return 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_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); -bool_t linphone_core_is_rtp_muted(LinphoneCore *lc); +/** + * Tells whether the microphone is enabled. + * @param[in] lc #LinphoneCore object + * @return 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_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc); -void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_is_rtp_muted(LinphoneCore *lc); + +LINPHONE_PUBLIC bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc); +LINPHONE_PUBLIC 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); +/******************************************************************************* + * Call log related functions * + ******************************************************************************/ + +/** + * @addtogroup call_logs + * @{ +**/ + +/** + * Get the list of call logs (past calls). + * @param[in] lc LinphoneCore object + * @return \mslist{LinphoneCallLog} +**/ +LINPHONE_PUBLIC const MSList * linphone_core_get_call_logs(LinphoneCore *lc); + +/** + * Erase the call log. + * @param[in] lc LinphoneCore object +**/ +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. + * @return The number of missed calls. +**/ +LINPHONE_PUBLIC int linphone_core_get_missed_calls_count(LinphoneCore *lc); + +/** + * Reset the counter of missed calls. + * @param[in] lc #LinphoneCore object. +**/ +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. +**/ +LINPHONE_PUBLIC void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); + +/** + * @} +**/ + /* video support */ -bool_t linphone_core_video_supported(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); -bool_t linphone_core_video_enabled(LinphoneCore *lc); + +/** + * 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); + + +/** + * Enable or disable video source reuse when switching from preview to actual video call. + * + * This source reuse is useful when you always display the preview, even before calls are initiated. + * By keeping the video source for the transition to a real video call, you will smooth out the + * source close/reopen cycle. + * + * This function does not have any effect durfing calls. It just indicates the #LinphoneCore to + * initiate future calls with video source reuse or not. + * Also, at the end of a video call, the source will be closed whatsoever for now. + * @param[in] lc #LinphoneCore object + * @param[in] enable TRUE to enable video source reuse. FALSE to disable it for subsequent calls. + * @ingroup media_parameters + * + */ +LINPHONE_PUBLIC void linphone_core_enable_video_source_reuse(LinphoneCore* lc, bool_t enable); + +/** + * Tells whether video capture is enabled. + * @param[in] lc #LinphoneCore object. + * @return 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. + * @return 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); -const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc); +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); +/** + * Returns the zero terminated table of supported video resolutions. + * + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc); -void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); -bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); +/** + * Sets the preferred video size. + * + * @ingroup media_parameters + * 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. +**/LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); +/** + * Sets the video size for the captured (preview) video. + * This method is for advanced usage where a video capture must be set independently of the size of the stream actually sent through the call. + * This allows for example to have the preview window with HD resolution even if due to bandwidth constraint the sent video size is small. + * Using this feature increases the CPU consumption, since a rescaling will be done internally. + * @ingroup media_parameters + * @param lc the linphone core + * @param vsize the video resolution choosed for capuring and previewing. It can be (0,0) to not request any specific preview size and let the core optimize the processing. +**/ +LINPHONE_PUBLIC void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize); +/** + * Sets the preview video size by its name. See linphone_core_set_preview_video_size() for more information about this feature. + * + * @ingroup media_parameters + * Video resolution names are: qcif, svga, cif, vga, 4cif, svga ... +**/ +LINPHONE_PUBLIC void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name); +/** + * Returns video size for the captured video if it was previously set by linphone_core_set_preview_video_size(), otherwise returns a 0,0 size. + * @see linphone_core_set_preview_video_size() + * @ingroup media_parameters + * @param lc the core + * @return a MSVideoSize +**/ +LINPHONE_PUBLIC MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc); +/** + * Returns the effective video size for the captured video as provided by the camera. + * When preview is disabled or not yet started, this function returns a zeroed video size. + * @see linphone_core_set_preview_video_size() + * @ingroup media_parameters + * @param lc the core + * @return a MSVideoSize +**/ +LINPHONE_PUBLIC MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc); +/** + * Returns the current preferred video size for sending. + * + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc); -void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); -bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); +/** + * Get the name of the current preferred video size for sending. + * @param[in] lc #LinphoneCore object. + * @return A string containing the name of the current preferred video size (to be freed with ms_free()). + */ +LINPHONE_PUBLIC char * linphone_core_get_preferred_video_size_name(const LinphoneCore *lc); +/** + * Sets the preferred video size by its name. + * + * @ingroup media_parameters + * This is identical to linphone_core_set_preferred_video_size() except + * that it takes the name of the video resolution as input. + * Video resolution names are: qcif, svga, cif, vga, 4cif, svga ... +**/ +LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name); +/** + * Set the preferred frame rate for video. + * Based on the available bandwidth constraints and network conditions, the video encoder + * remains free to lower the framerate. There is no warranty that the preferred frame rate be the actual framerate. + * used during a call. Default value is 0, which means "use encoder's default fps value". + * @ingroup media_parameters + * @param lc the LinphoneCore + * @param fps the target frame rate in number of frames per seconds. +**/ +LINPHONE_PUBLIC void linphone_core_set_preferred_framerate(LinphoneCore *lc, float fps); +/** + * Returns the preferred video framerate, previously set by linphone_core_set_preferred_framerate(). + * @ingroup media_parameters + * @param lc the linphone core + * @return frame rate in number of frames per seconds. +**/ +LINPHONE_PUBLIC float linphone_core_get_preferred_framerate(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); + + +/** + * 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 + **/ +LINPHONE_PUBLIC 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 */ -int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); -const char *linphone_core_get_static_picture(LinphoneCore *lc); +/** + * 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 + */ +LINPHONE_PUBLIC int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); -/* Set and get frame rate for static picture */ -int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); -float linphone_core_get_static_picture_fps(LinphoneCore *lc); +/** + * Get the path to the image file streamed when "Static picture" is set as the video device. + * @param[in] lc #LinphoneCore object. + * @return The path to the image file streamed when "Static picture" is set as the video device. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC const char *linphone_core_get_static_picture(LinphoneCore *lc); + +/** + * 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 + */ +LINPHONE_PUBLIC 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 + */ +LINPHONE_PUBLIC 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 void * linphone_core_get_native_video_window_id(const LinphoneCore *lc); -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); +/** + * @ingroup media_parameters + * For MacOS, Linux, Windows: core will create its own window + * */ +#define LINPHONE_VIDEO_DISPLAY_AUTO (void*)((unsigned long) 0) +/** + * @ingroup media_parameters + * For MacOS, Linux, Windows: do nothing + * */ -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); +#define LINPHONE_VIDEO_DISPLAY_NONE (void*)((unsigned long) -1) +/** + * @ingroup media_parameters + * Set the native video window id where the video is to be displayed. + * For MacOS, Linux, Windows: if not set or LINPHONE_VIDEO_DISPLAY_AUTO the core will create its own window, unless the special id LINPHONE_VIDEO_DISPLAY_NONE is given. +**/ +LINPHONE_PUBLIC void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id); + +LINPHONE_PUBLIC void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *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); + +LINPHONE_PUBLIC int linphone_core_get_device_rotation(LinphoneCore *lc ); +LINPHONE_PUBLIC void linphone_core_set_device_rotation(LinphoneCore *lc, int 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. + * + * @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 + */ +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); -void linphone_core_set_record_file(LinphoneCore *lc, const char *file); +/** @deprecated Use linphone_core_set_use_files() instead. */ +#define linphone_core_use_files(lc, yesno) linphone_core_set_use_files(lc, yesno) +/** + * Ask the core to stream audio from and to files, instead of using the soundcard. + * @ingroup media_parameters + * @param[in] lc LinphoneCore object + * @param[in] yesno A boolean value asking to stream audio from and to files or not. +**/ +LINPHONE_PUBLIC void linphone_core_set_use_files(LinphoneCore *lc, bool_t yesno); -void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); -void linphone_core_stop_dtmf(LinphoneCore *lc); +/** + * Get the wav file that is played when putting somebody on hold, + * or when files are used instead of soundcards (see linphone_core_set_use_files()). + * + * The file is a 16 bit linear wav file. + * @ingroup media_parameters + * @param[in] lc LinphoneCore object + * @return The path to the file that is played when putting somebody on hold. + */ +LINPHONE_PUBLIC const char * linphone_core_get_play_file(const LinphoneCore *lc); -int linphone_core_get_current_call_duration(const LinphoneCore *lc); +/** + * Sets a wav file to be played when putting somebody on hold, + * or when files are used instead of soundcards (see linphone_core_set_use_files()). + * + * The file must be a 16 bit linear wav file. + * @ingroup media_parameters + * @param[in] lc LinphoneCore object + * @param[in] file The path to the file to be played when putting somebody on hold. +**/ +LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file); + +/** + * Get the wav file where incoming stream is recorded, + * when files are used instead of soundcards (see linphone_core_set_use_files()). + * + * This feature is different from call recording (linphone_call_params_set_record_file()) + * The file is a 16 bit linear wav file. + * @ingroup media_parameters + * @param[in] lc LinphoneCore object + * @return The path to the file where incoming stream is recorded. +**/ +LINPHONE_PUBLIC const char * linphone_core_get_record_file(const LinphoneCore *lc); + +/** + * Sets a wav file where incoming stream is to be recorded, + * when files are used instead of soundcards (see linphone_core_set_use_files()). + * + * This feature is different from call recording (linphone_call_params_set_record_file()) + * The file will be a 16 bit linear wav file. + * @ingroup media_parameters + * @param[in] lc LinphoneCore object + * @param[in] file The path to the file where incoming stream is to be recorded. +**/ +LINPHONE_PUBLIC void linphone_core_set_record_file(LinphoneCore *lc, const char *file); + +LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); +LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); + +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 int linphone_core_get_mtu(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_mtu(LinphoneCore *lc, int mtu); /** * @ingroup network_parameters @@ -1301,44 +3559,52 @@ LINPHONE_PUBLIC void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t * @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); -LINPHONE_PUBLIC void *linphone_core_get_user_data(LinphoneCore *lc); +LINPHONE_PUBLIC void *linphone_core_get_user_data(const 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); +LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC const MSList * linphone_core_get_sip_setups(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; @@ -1347,80 +3613,422 @@ 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); LINPHONE_PUBLIC const MSList *linphone_core_get_calls(LinphoneCore *lc); -LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc); +LINPHONE_PUBLIC 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 */ -void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); -const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); +/** + * 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 + */ +LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); -const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); +/** + * Get the path to the file storing the zrtp secrets cache. + * @param[in] lc #LinphoneCore object. + * @return The path to the file storing the zrtp secrets cache. + * @ingroup initializing + */ +LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); + +/** + * Set the path to the directory storing the user's x509 certificates (used by dtls) + * @param[in] lc #LinphoneCore object + * @param[in] path The path to the directory to use to store the user's certificates. + * @ingroup initializing + */ +LINPHONE_PUBLIC void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path); + +/** + * Get the path to the directory storing the user's certificates. + * @param[in] lc #LinphoneCore object. + * @returns The path to the directory storing the user's certificates. + * @ingroup initializing + */ +LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCore *lc); + +/** + * Search from the list of current calls if a remote address match uri + * @ingroup call_control + * @param lc + * @param uri which should match call remote uri + * @return LinphoneCall or NULL is no match is found + */ +LINPHONE_PUBLIC LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri); LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call); +/** + * Indicates whether the local participant is part of a conference. + * @param lc the linphone core + * @return TRUE if the local participant is in a conference, FALSE otherwise. +**/ LINPHONE_PUBLIC 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_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); 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); +LINPHONE_PUBLIC int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC int linphone_core_stop_conference_recording(LinphoneCore *lc); +/** + * Get 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 + * @return max number of simultaneous calls + */ +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 + */ +LINPHONE_PUBLIC void linphone_core_set_max_calls(LinphoneCore *lc, int max); -int linphone_core_get_max_calls(LinphoneCore *lc); -void linphone_core_set_max_calls(LinphoneCore *lc, int max); +LINPHONE_PUBLIC bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); +/** + * @ingroup initializing + * Check if a media encryption type is supported + * @param lc core + * @param menc LinphoneMediaEncryption + * @return whether a media encryption scheme is supported by the LinphoneCore engine +**/ -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. + * @return 0 if successful, any other value otherwise. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc); + +/** + * Get the media encryption policy being used for RTP packets. + * @param[in] lc #LinphoneCore object. + * @return The media encryption policy being used. + * @ingroup media_parameters */ -LINPHONE_PUBLIC int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); LINPHONE_PUBLIC LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); -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 behaviour when encryption parameters negociation fails on outgoing call. + * @param[in] lc #LinphoneCore object. + * @return TRUE means the call will fail; FALSE means an INVITE will be resent with encryption disabled. + * @ingroup media_parameters */ -void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); +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. + * @ingroup tunnel */ -bool_t linphone_core_tunnel_available(void); +LINPHONE_PUBLIC bool_t linphone_core_tunnel_available(void); +/** + * Linphone tunnel object. + * @ingroup tunnel + */ typedef struct _LinphoneTunnel LinphoneTunnel; + /** * get tunnel instance if available +* @ingroup tunnel +* @param lc core object +* @returns LinphoneTunnel or NULL if not available */ -LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneTunnel *linphone_core_get_tunnel(const 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); + +/** Contact Providers + */ + +typedef unsigned int ContactSearchID; + +typedef struct _LinphoneContactSearch LinphoneContactSearch; +typedef struct _LinphoneContactProvider LinphoneContactProvider; + +typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data ); + +/* + * Remote provisioning + */ + +/** + * Set URI where to download xml configuration file at startup. + * This can also be set from configuration file or factory config file, from [misc] section, item "config-uri". + * Calling this function does not load the configuration. It will write the value into configuration so that configuration + * from remote URI will take place at next LinphoneCore start. + * @param lc the linphone core + * @param uri the http or https uri to use in order to download the configuration. + * @ingroup initializing +**/ +LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri); + +/** + * Get provisioning URI. + * @param lc the linphone core + * @return the provisioning URI. + * @ingroup initializing +**/ +LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc); + +/** + * Gets if the provisioning URI should be removed after it's been applied successfully + * @param lc the linphone core + * @return TRUE if the provisioning URI should be removed, FALSE otherwise + */ +LINPHONE_PUBLIC bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_core_migrate_to_multi_transport(LinphoneCore *lc); + + +/** + * Control when media offer is sent in SIP INVITE. + * @param lc the linphone core + * @param enable true if INVITE has to be sent whitout SDP. + * @ingroup network_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable); +/** + * Media offer control param for SIP INVITE. + * @return true if INVITE has to be sent whitout SDP. + * @ingroup network_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc); + + +/** + * Enum listing frequent telephony tones. +**/ +enum _LinphoneToneID{ + LinphoneToneUndefined, /** For incoming calls behavior is unchanged. + * @param core #LinphoneCore + * @param yesno if yes, subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_audio_multicast(LinphoneCore *core, bool_t yesno); + +/** + * Use to get multicast state of audio stream. + * @param core #LinphoneCore + * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *core); + +/** + * Use to enable multicast rtp for video stream. + * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address. + *
    For incoming calls behavior is unchanged. + * @param core #LinphoneCore + * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by #linphone_core_set_video_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_video_multicast(LinphoneCore *core, bool_t yesno); +/** + * Use to get multicast state of video stream. + * @param core #LinphoneCore + * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_video_multicast_addr + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_multicast_enabled(const LinphoneCore *core); + +/** + * Set the network simulator parameters. + * Liblinphone has the capabability of simulating the effects of a network (latency, lost packets, jitter, max bandwidth). + * Please refer to the oRTP documentation for the meaning of the parameters of the OrtpNetworkSimulatorParams structure. + * This function has effect for future calls, but not for currently running calls, though this behavior may be changed in future versions. + * @warning Due to design of network simulation in oRTP, simulation is applied independently for audio and video stream. This means for example that a bandwidth + * limit of 250kbit/s will have no effect on an audio stream running at 40kbit/s while a videostream targetting 400kbit/s will be highly affected. + * @param lc the LinphoneCore + * @param params the parameters used for the network simulation. + * @return 0 if successful, -1 otherwise. +**/ +LINPHONE_PUBLIC int linphone_core_set_network_simulator_params(LinphoneCore *lc, const OrtpNetworkSimulatorParams *params); + + +/** + * Get the previously set network simulation parameters. + * @see linphone_core_set_network_simulator_params + * @return a OrtpNetworkSimulatorParams structure. +**/ +LINPHONE_PUBLIC const OrtpNetworkSimulatorParams *linphone_core_get_network_simulator_params(const LinphoneCore *lc); + +/** + * Set the video preset to be used for video calls. + * @param[in] lc LinphoneCore object + * @param[in] preset The name of the video preset to be used (can be NULL to use the default video preset). + */ +LINPHONE_PUBLIC void linphone_core_set_video_preset(LinphoneCore *lc, const char *preset); + +/** + * Get the video preset used for video calls. + * @param[in] lc LinphoneCore object + * @return The name of the video preset used for video calls (can be NULL if the default video preset is used). + */ +LINPHONE_PUBLIC const char * linphone_core_get_video_preset(const LinphoneCore *lc); #ifdef __cplusplus } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 57ab7c4ca..ab34a3604 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -21,11 +21,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore_jni.h" #endif #include "linphonecore_utils.h" -#include +#include extern "C" { #include "mediastreamer2/mediastream.h" +#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/msmediaplayer.h" +#include "mediastreamer2/msutils.h" +#include "devices.h" } #include "mediastreamer2/msjava.h" #include "private.h" @@ -39,6 +43,9 @@ extern "C" void libmsilbc_init(); #ifdef HAVE_X264 extern "C" void libmsx264_init(); #endif +#ifdef HAVE_OPENH264 +extern "C" void libmsopenh264_init(); +#endif #ifdef HAVE_AMR extern "C" void libmsamr_init(); #endif @@ -48,19 +55,47 @@ extern "C" void libmssilk_init(); #ifdef HAVE_G729 extern "C" void libmsbcg729_init(); #endif +#ifdef HAVE_WEBRTC +extern "C" void libmswebrtc_init(); +#endif +#ifdef HAVE_CODEC2 +extern "C" void libmscodec2_init(); +#endif +#include #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); +static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *buffer); +static LinphoneBuffer* create_c_linphone_buffer_from_java_linphone_buffer(JNIEnv *env, jobject jbuffer); #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,27 +110,48 @@ 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(); + jstring jdomain=env->NewStringUTF(LogDomain); + jstring jlevname=env->NewStringUTF(levname); + jstring jstr=env->NewStringUTF(str); + env->CallVoidMethod(handler_obj,loghandler_id,jdomain,(jint)lev,jlevname,jstr,NULL); + if (jdomain) env->DeleteLocalRef(jdomain); + if (jlevname) env->DeleteLocalRef(jlevname); + if (jstr) env->DeleteLocalRef(jstr); + }else + linphone_android_log_handler(prio, str); } int dumbMethodForAllowingUsageOfCpuFeaturesFromStaticLibMediastream() { return (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0); } + +int dumbMethodForAllowingUsageOfMsAudioDiffFromStaticLibMediastream() { + return ms_audio_diff(NULL, NULL, NULL, 0, NULL, NULL); +} #endif /*ANDROID*/ + JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef ANDROID ms_set_jvm(ajvm); + #endif /*ANDROID*/ jvm=ajvm; return JNI_VERSION_1_2; @@ -114,99 +170,325 @@ extern "C" void Java_org_linphone_core_LinphoneCoreFactoryImpl_setDebugMode(JNIE linphone_core_disable_logs(); } } + +extern "C" void Java_org_linphone_core_LinphoneCoreFactoryImpl_enableLogCollection(JNIEnv* env + ,jobject thiz + ,jboolean enable) { + linphone_core_enable_log_collection(enable ? LinphoneLogCollectionEnabledWithoutPreviousLogHandler : LinphoneLogCollectionDisabled); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreFactoryImpl_setLogCollectionPath(JNIEnv* env + ,jobject thiz + ,jstring jpath) { + + const char* path = env->GetStringUTFChars(jpath, NULL); + linphone_core_set_log_collection_path(path); + env->ReleaseStringUTFChars(jpath, path); +} // LinphoneCore +/* + * returns the java LinphoneProxyConfig associated with a C LinphoneProxyConfig. +**/ +jobject getProxy(JNIEnv *env, LinphoneProxyConfig *proxy, jobject core){ + jobject jobj=0; + + if (proxy!=NULL){ + jclass proxyClass = (jclass)env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"); + jmethodID proxyCtrId = env->GetMethodID(proxyClass,"", "(Lorg/linphone/core/LinphoneCoreImpl;J)V"); + + void *up=linphone_proxy_config_get_user_data(proxy); + + if (up==NULL){ + jobj=env->NewObject(proxyClass,proxyCtrId,core,(jlong)proxy); + linphone_proxy_config_set_user_data(proxy,(void*)env->NewWeakGlobalRef(jobj)); + linphone_proxy_config_ref(proxy); + }else{ + //promote the weak ref to local ref + jobj=env->NewLocalRef((jobject)up); + if (jobj == NULL){ + //the weak ref was dead + jobj=env->NewObject(proxyClass,proxyCtrId,core,(jlong)proxy); + linphone_proxy_config_set_user_data(proxy,(void*)env->NewWeakGlobalRef(jobj)); + } + } + env->DeleteLocalRef(proxyClass); + } + return jobj; +} + +jobject getCall(JNIEnv *env, LinphoneCall *call){ + jobject jobj=0; + + if (call!=NULL){ + jclass callClass = (jclass)env->FindClass("org/linphone/core/LinphoneCallImpl"); + jmethodID callCtrId = env->GetMethodID(callClass,"", "(J)V"); + + void *up=linphone_call_get_user_pointer(call); + + if (up==NULL){ + jobj=env->NewObject(callClass,callCtrId,(jlong)call); + jobj=env->NewGlobalRef(jobj); + linphone_call_set_user_pointer(call,(void*)jobj); + linphone_call_ref(call); + }else{ + jobj=(jobject)up; + } + env->DeleteLocalRef(callClass); + } + return jobj; +} + +jobject getChatMessage(JNIEnv *env, LinphoneChatMessage *msg){ + jobject jobj = 0; + + if (msg != NULL){ + jclass chatMessageClass = (jclass)env->FindClass("org/linphone/core/LinphoneChatMessageImpl"); + jmethodID chatMessageCtrId = env->GetMethodID(chatMessageClass,"", "(J)V"); + + void *up = linphone_chat_message_get_user_data(msg); + + if (up == NULL) { + jobj = env->NewObject(chatMessageClass,chatMessageCtrId,(jlong)linphone_chat_message_ref(msg)); + jobj = env->NewGlobalRef(jobj); + linphone_chat_message_set_user_data(msg,(void*)jobj); + } else { + jobj = (jobject)up; + } + env->DeleteLocalRef(chatMessageClass); + } + return jobj; +} + +jobject getFriend(JNIEnv *env, LinphoneFriend *lfriend){ + jobject jobj=0; + + if (lfriend != NULL){ + jclass friendClass = (jclass)env->FindClass("org/linphone/core/LinphoneFriendImpl"); + jmethodID friendCtrId = env->GetMethodID(friendClass,"", "(J)V"); + + void *up=linphone_friend_get_user_data(lfriend); + + if (up == NULL){ + jobj=env->NewObject(friendClass,friendCtrId,(jlong)lfriend); + linphone_friend_set_user_data(lfriend,(void*)env->NewWeakGlobalRef(jobj)); + linphone_friend_ref(lfriend); + }else{ + + jobj=env->NewLocalRef((jobject)up); + if (jobj == NULL){ + jobj=env->NewObject(friendClass,friendCtrId,(jlong)lfriend); + linphone_friend_set_user_data(lfriend,(void*)env->NewWeakGlobalRef(jobj)); + } + } + env->DeleteLocalRef(friendClass); + } + return jobj; +} + +jobject getEvent(JNIEnv *env, LinphoneEvent *lev){ + if (lev==NULL) return NULL; + jobject jev=(jobject)linphone_event_get_user_data(lev); + if (jev==NULL){ + jclass linphoneEventClass = (jclass)env->FindClass("org/linphone/core/LinphoneEventImpl"); + jmethodID linphoneEventCtrId = env->GetMethodID(linphoneEventClass,"", "(J)V"); + + jev=env->NewObject(linphoneEventClass,linphoneEventCtrId,(jlong)linphone_event_ref(lev)); + jev=env->NewGlobalRef(jev); + linphone_event_set_user_data(lev,jev); + + env->DeleteLocalRef(linphoneEventClass); + } + return jev; +} + class LinphoneCoreData { public: - LinphoneCoreData(JNIEnv* env, jobject lc,jobject alistener, jobject auserdata) { - + LinphoneCoreData(JNIEnv *env, jobject lc, LinphoneCoreVTable *vTable, jobject alistener) { core = env->NewGlobalRef(lc); listener = env->NewGlobalRef(alistener); - userdata = auserdata?env->NewGlobalRef(auserdata):0; - memset(&vTable,0,sizeof(vTable)); - vTable.show = showInterfaceCb; - vTable.auth_info_requested = authInfoRequested; - vTable.display_status = displayStatusCb; - vTable.display_message = displayMessageCb; - vTable.display_warning = displayMessageCb; - vTable.global_state_changed = globalStateChange; - vTable.registration_state_changed = registrationStateChange; - vTable.call_state_changed = callStateChange; - vTable.call_encryption_changed = callEncryptionChange; - 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.call_stats_updated = callStatsUpdated; - listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); + memset(vTable, 0, sizeof(LinphoneCoreVTable)); + + listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass(alistener)); /*displayStatus(LinphoneCore lc,String message);*/ displayStatusId = env->GetMethodID(listenerClass,"displayStatus","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;)V"); + if (displayStatusId) { + vTable->display_status = displayStatusCb; + } /*void generalState(LinphoneCore lc,int state); */ - globalStateId = env->GetMethodID(listenerClass,"globalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GlobalState;Ljava/lang/String;)V"); globalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GlobalState")); globalStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GlobalState;"); + globalStateId = env->GetMethodID(listenerClass,"globalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GlobalState;Ljava/lang/String;)V"); + if (globalStateId) { + vTable->global_state_changed = globalStateChange; + } /*registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage);*/ - registrationStateId = env->GetMethodID(listenerClass,"registrationState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneProxyConfig;Lorg/linphone/core/LinphoneCore$RegistrationState;Ljava/lang/String;)V"); registrationStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RegistrationState")); registrationStateFromIntId = env->GetStaticMethodID(registrationStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RegistrationState;"); + registrationStateId = env->GetMethodID(listenerClass,"registrationState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneProxyConfig;Lorg/linphone/core/LinphoneCore$RegistrationState;Ljava/lang/String;)V"); + if (registrationStateId) { + vTable->registration_state_changed = registrationStateChange; + } /*callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);*/ - callStateId = env->GetMethodID(listenerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V"); callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State")); callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;"); + callStateId = env->GetMethodID(listenerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V"); + if (callStateId) { + vTable->call_state_changed = callStateChange; + } + + transferStateId = env->GetMethodID(listenerClass,"transferState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;)V"); + if (transferStateId) { + vTable->transfer_state_changed = transferStateChanged; + } /*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"); + if (callStatsUpdatedId) { + vTable->call_stats_updated = callStatsUpdated; + } + + /*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/ + callEncryptionChangedId = env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V"); + if (callEncryptionChangedId) { + vTable->call_encryption_changed = callEncryptionChange; + } + + /*void ecCalibrationStatus(LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);*/ + ecCalibratorStatusClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$EcCalibratorStatus")); + ecCalibratorStatusFromIntId = env->GetStaticMethodID(ecCalibratorStatusClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;"); + ecCalibrationStatusId = env->GetMethodID(listenerClass,"ecCalibrationStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;ILjava/lang/Object;)V"); + + /*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/ + newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); + if (newSubscriptionRequestId) { + vTable->new_subscription_requested = new_subscription_requested; + } + + authInfoRequestedId = env->GetMethodID(listenerClass,"authInfoRequested","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (authInfoRequestedId) { + vTable->auth_info_requested = authInfoRequested; + } + + /*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/ + notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V"); + if (notifyPresenceReceivedId) { + vTable->notify_presence_received = notify_presence_received; + } + + messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); + if (messageReceivedId) { + vTable->message_received = message_received; + } + + isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V"); + if (isComposingReceivedId) { + vTable->is_composing_received = is_composing_received; + } + + dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); + if (dtmfReceivedId) { + vTable->dtmf_received = dtmf_received; + } + + infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V"); + if (infoReceivedId) { + vTable->info_received = infoReceived; + } + + subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState")); + subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;"); + subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V"); + if (subscriptionStateId) { + vTable->subscription_state_changed = subscriptionStateChanged; + } + + publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState")); + publishStateFromIntId = env->GetStaticMethodID(publishStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;"); + publishStateId = env->GetMethodID(listenerClass,"publishStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/PublishState;)V"); + if (publishStateId) { + vTable->publish_state_changed = publishStateChanged; + } + + notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V"); + if (notifyRecvId) { + vTable->notify_received = notifyReceived; + } + + configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState")); + configuringStateFromIntId = env->GetStaticMethodID(configuringStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;"); + configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V"); + if (configuringStateId) { + vTable->configuring_status = configuringStatus; + } + + fileTransferProgressIndicationId = env->GetMethodID(listenerClass, "fileTransferProgressIndication", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;I)V"); + if (fileTransferProgressIndicationId) { + vTable->file_transfer_progress_indication = fileTransferProgressIndication; + } + + fileTransferSendId = env->GetMethodID(listenerClass, "fileTransferSend", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Ljava/nio/ByteBuffer;I)I"); + if (fileTransferSendId) { + vTable->file_transfer_send = fileTransferSend; + } + + fileTransferRecvId = env->GetMethodID(listenerClass, "fileTransferRecv", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;[BI)V"); + if (fileTransferRecvId) { + vTable->file_transfer_recv = fileTransferRecv; + } + + logCollectionUploadStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$LogCollectionUploadState")); + logCollectionUploadStateFromIntId = env->GetStaticMethodID(logCollectionUploadStateClass, "fromInt", "(I)Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;"); + logCollectionUploadProgressId = env->GetMethodID(listenerClass, "uploadProgressIndication", "(Lorg/linphone/core/LinphoneCore;II)V"); + if (logCollectionUploadProgressId) { + vTable->log_collection_upload_progress_indication = logCollectionUploadProgressIndication; + } + logCollectionUploadStateId = env->GetMethodID(listenerClass, "uploadStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;Ljava/lang/String;)V"); + if (logCollectionUploadStateId) { + vTable->log_collection_upload_state_changed = logCollectionUploadStateChange; + } chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State")); chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;"); - /*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/ - callEncryptionChangedId=env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V"); - - /*void ecCalibrationStatus(LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);*/ - ecCalibrationStatusId = env->GetMethodID(listenerClass,"ecCalibrationStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;ILjava/lang/Object;)V"); - ecCalibratorStatusClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$EcCalibratorStatus")); - ecCalibratorStatusFromIntId = env->GetStaticMethodID(ecCalibratorStatusClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;"); - - /*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/ - newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); - - /*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/ - notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V"); - - /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ - textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); - messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); - dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); - proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); - proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); + proxyCtrId = env->GetMethodID(proxyClass,"", "(Lorg/linphone/core/LinphoneCoreImpl;J)V"); callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl")); callCtrId = env->GetMethodID(callClass,"", "(J)V"); + callSetAudioStatsId = env->GetMethodID(callClass, "setAudioStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); + callSetVideoStatsId = env->GetMethodID(callClass, "setVideoStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); chatMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessageImpl")); - if (chatMessageClass) chatMessageCtrId = env->GetMethodID(chatMessageClass,"", "(J)V"); + if (chatMessageClass) { + chatMessageCtrId = env->GetMethodID(chatMessageClass,"", "(J)V"); + } chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl")); chatRoomCtrId = env->GetMethodID(chatRoomClass,"", "(J)V"); friendClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneFriendImpl"));; - friendCtrId =env->GetMethodID(friendClass,"", "(J)V"); + friendCtrId = env->GetMethodID(friendClass,"", "(J)V"); addressClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneAddressImpl")); - addressCtrId =env->GetMethodID(addressClass,"", "(J)V"); + addressCtrId = env->GetMethodID(addressClass,"", "(J)V"); callStatsClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallStatsImpl")); 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"); + + subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); + subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); } ~LinphoneCoreData() { @@ -214,32 +496,44 @@ public: jvm->AttachCurrentThread(&env,NULL); env->DeleteGlobalRef(core); env->DeleteGlobalRef(listener); - if (userdata) env->DeleteGlobalRef(userdata); env->DeleteGlobalRef(listenerClass); env->DeleteGlobalRef(globalStateClass); + env->DeleteGlobalRef(configuringStateClass); 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); + env->DeleteGlobalRef(logCollectionUploadStateClass); } jobject core; jobject listener; - jobject userdata; jclass listenerClass; jmethodID displayStatusId; jmethodID newSubscriptionRequestId; jmethodID notifyPresenceReceivedId; - jmethodID textReceivedId; jmethodID messageReceivedId; + jmethodID isComposingReceivedId; jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; + jmethodID transferStateId; + jmethodID infoReceivedId; + jmethodID subscriptionStateId; + jmethodID authInfoRequestedId; + jmethodID publishStateId; + jmethodID notifyRecvId; + + jclass configuringStateClass; + jmethodID configuringStateId; + jmethodID configuringStateFromIntId; jclass globalStateClass; jmethodID globalStateId; @@ -285,75 +579,118 @@ 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; + + jmethodID fileTransferProgressIndicationId; + jmethodID fileTransferSendId; + jmethodID fileTransferRecvId; + + jclass logCollectionUploadStateClass; + jmethodID logCollectionUploadStateId; + jmethodID logCollectionUploadStateFromIntId; + jmethodID logCollectionUploadProgressId; + LinphoneCoreVTable vTable; - static void showInterfaceCb(LinphoneCore *lc) { - - } - static void byeReceivedCb(LinphoneCore *lc, const char *from) { - - } static void displayStatusCb(LinphoneCore *lc, 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); - env->CallVoidMethod(lcData->listener,lcData->displayStatusId,lcData->core,message ? env->NewStringUTF(message) : NULL); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring msg = message ? env->NewStringUTF(message) : NULL; + env->CallVoidMethod(lcData->listener,lcData->displayStatusId,lcData->core,msg); + handle_possible_java_exception(env, lcData->listener); + if (msg) { + env->DeleteLocalRef(msg); + } } - 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) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring r = realm ? env->NewStringUTF(realm) : NULL; + jstring u = username ? env->NewStringUTF(username) : NULL; + jstring d = domain ? env->NewStringUTF(domain) : NULL; + env->CallVoidMethod(lcData->listener, + lcData->authInfoRequestedId, + lcData->core, + r, + u, + d); + handle_possible_java_exception(env, lcData->listener); + if (r) { + env->DeleteLocalRef(r); + } + if (u) { + env->DeleteLocalRef(u); + } + if (d) { + env->DeleteLocalRef(d); + } } 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring msg = message ? env->NewStringUTF(message) : NULL; env->CallVoidMethod(lcData->listener ,lcData->globalStateId ,lcData->core ,env->CallStaticObjectMethod(lcData->globalStateClass,lcData->globalStateFromIntId,(jint)gstate), - message ? env->NewStringUTF(message) : NULL); + msg); + handle_possible_java_exception(env, lcData->listener); + if (msg) { + env->DeleteLocalRef(msg); + } } static void registrationStateChange(LinphoneCore *lc, LinphoneProxyConfig* proxy,LinphoneRegistrationState state,const char* message) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jproxy; if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring msg = message ? env->NewStringUTF(message) : NULL; env->CallVoidMethod(lcData->listener ,lcData->registrationStateId ,lcData->core - ,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,(jlong)proxy) + ,(jproxy=getProxy(env,proxy,lcData->core)) ,env->CallStaticObjectMethod(lcData->registrationStateClass,lcData->registrationStateFromIntId,(jint)state), - message ? env->NewStringUTF(message) : NULL); - } - jobject getCall(JNIEnv *env , LinphoneCall *call){ - jobject jobj=0; - - if (call!=NULL){ - void *up=linphone_call_get_user_pointer(call); - - if (up==NULL){ - jobj=env->NewObject(callClass,callCtrId,(jlong)call); - jobj=env->NewGlobalRef(jobj); - linphone_call_set_user_pointer(call,(void*)jobj); - linphone_call_ref(call); - }else{ - jobj=(jobject)up; - } + msg); + handle_possible_java_exception(env, lcData->listener); + if (msg) { + env->DeleteLocalRef(msg); } - return jobj; } static void callStateChange(LinphoneCore *lc, LinphoneCall* call,LinphoneCallState state,const char* message) { @@ -361,123 +698,148 @@ 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring msg = message ? env->NewStringUTF(message) : NULL; env->CallVoidMethod(lcData->listener ,lcData->callStateId ,lcData->core - ,(jcall=lcData->getCall(env,call)) + ,(jcall=getCall(env,call)) ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)state), - message ? env->NewStringUTF(message) : NULL); - if (state==LinphoneCallReleased){ + msg); + handle_possible_java_exception(env, lcData->listener); + if (state==LinphoneCallReleased) { linphone_call_set_user_pointer(call,NULL); env->DeleteGlobalRef(jcall); } + if (msg) { + env->DeleteLocalRef(msg); + } } static void callEncryptionChange(LinphoneCore *lc, LinphoneCall* call, bool_t encrypted,const char* authentication_token) { 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); env->CallVoidMethod(lcData->listener ,lcData->callEncryptionChangedId ,lcData->core - ,lcData->getCall(env,call) + ,getCall(env,call) ,encrypted ,authentication_token ? env->NewStringUTF(authentication_token) : NULL); + handle_possible_java_exception(env, lcData->listener); } - 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); env->CallVoidMethod(lcData->listener ,lcData->notifyPresenceReceivedId ,lcData->core - ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)); + ,getFriend(env,my_friend)); + handle_possible_java_exception(env, lcData->listener); } - 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); env->CallVoidMethod(lcData->listener ,lcData->newSubscriptionRequestId ,lcData->core - ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend) + ,getFriend(env,my_friend) ,url ? env->NewStringUTF(url) : NULL); + handle_possible_java_exception(env, lcData->listener); } static void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) { 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); env->CallVoidMethod(lcData->listener ,lcData->dtmfReceivedId ,lcData->core - ,lcData->getCall(env,call) + ,getCall(env,call) ,dtmf); + handle_possible_java_exception(env, lcData->listener); } - static void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) { + static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { + JNIEnv *env = 0; + jobject jmsg; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + /*note: we call linphone_chat_message_ref() because the application does not acquire the object when invoked from a callback*/ + env->CallVoidMethod(lcData->listener + ,lcData->messageReceivedId + ,lcData->core + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) + ,(jmsg = getChatMessage(env, msg))); + handle_possible_java_exception(env, lcData->listener); + } + static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); env->CallVoidMethod(lcData->listener - ,lcData->textReceivedId + ,lcData->isComposingReceivedId ,lcData->core - ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) - ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from) - ,message ? env->NewStringUTF(message) : NULL); + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)); + handle_possible_java_exception(env, lcData->listener); } - 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"); - return; - } - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); - env->CallVoidMethod(lcData->listener - ,lcData->messageReceivedId - ,lcData->core - ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) - ,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); - env->CallVoidMethod(lcData->listener - ,lcData->ecCalibrationStatusId - ,lcData->core - ,env->CallStaticObjectMethod(lcData->ecCalibratorStatusClass,lcData->ecCalibratorStatusFromIntId,(jint)status) - ,delay_ms - ,data ? data : NULL); - if (data != NULL &&status !=LinphoneEcCalibratorInProgress ) { - //final state, releasing global ref - env->DeleteGlobalRef((jobject)data); + + LinphoneCoreVTable *table = (LinphoneCoreVTable*) data; + if (table) { + LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_v_table_get_user_data(table); + if (lcData->ecCalibrationStatusId) { + jobject state = env->CallStaticObjectMethod(lcData->ecCalibratorStatusClass, lcData->ecCalibratorStatusFromIntId, (jint)status); + env->CallVoidMethod(lcData->listener + ,lcData->ecCalibrationStatusId + ,lcData->core + ,state + ,delay_ms + ,NULL); + handle_possible_java_exception(env, lcData->listener); + } + if (status != LinphoneEcCalibratorInProgress) { + linphone_core_v_table_destroy(table); + } } } @@ -487,31 +849,280 @@ 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); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); statsobj = env->NewObject(lcData->callStatsClass, lcData->callStatsId, (jlong)call, (jlong)stats); - callobj = lcData->getCall(env, call); + callobj = getCall(env, call); if (stats->type == LINPHONE_CALL_STATS_AUDIO) env->CallVoidMethod(callobj, lcData->callSetAudioStatsId, statsobj); else env->CallVoidMethod(callobj, lcData->callSetVideoStatsId, statsobj); env->CallVoidMethod(lcData->listener, lcData->callStatsUpdatedId, lcData->core, callobj, statsobj); + handle_possible_java_exception(env, lcData->listener); + } + 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; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + env->CallVoidMethod(lcData->listener + ,lcData->transferStateId + ,lcData->core + ,(jcall=getCall(env,call)) + ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)remote_call_state) + ); + handle_possible_java_exception(env, lcData->listener); + } + static void infoReceived(LinphoneCore *lc, LinphoneCall*call, const LinphoneInfoMessage *info){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneInfoMessage *copy_info=linphone_info_message_copy(info); + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + env->CallVoidMethod(lcData->listener + ,lcData->infoReceivedId + ,lcData->core + ,getCall(env,call) + ,env->NewObject(lcData->infoMessageClass,lcData->infoMessageCtor,(jlong)copy_info) + ); + handle_possible_java_exception(env, lcData->listener); + } + 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; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jevent=getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->subscriptionStateClass,lcData->subscriptionStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->subscriptionStateId + ,lcData->core + ,jevent + ,jstate + ); + handle_possible_java_exception(env, lcData->listener); + 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; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jevent=getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->publishStateClass,lcData->publishStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->publishStateId + ,lcData->core + ,jevent + ,jstate + ); + handle_possible_java_exception(env, lcData->listener); + } + 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; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jevent=getEvent(env,ev); + env->CallVoidMethod(lcData->listener + ,lcData->notifyRecvId + ,lcData->core + ,jevent + ,env->NewStringUTF(evname) + ,content ? create_java_linphone_content(env,content) : NULL + ); + handle_possible_java_exception(env, lcData->listener); } + static void configuringStatus(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + env->CallVoidMethod(lcData->listener, lcData->configuringStateId, lcData->core, env->CallStaticObjectMethod(lcData->configuringStateClass,lcData->configuringStateFromIntId,(jint)status), message ? env->NewStringUTF(message) : NULL); + handle_possible_java_exception(env, lcData->listener); + } + static void fileTransferProgressIndication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { + JNIEnv *env = 0; + jobject jmsg; + size_t progress = (offset * 100) / total; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + env->CallVoidMethod(lcData->listener, + lcData->fileTransferProgressIndicationId, + lcData->core, + (jmsg = getChatMessage(env, message)), + jcontent, + progress); + if (jcontent) { + env->DeleteLocalRef(jcontent); + } + handle_possible_java_exception(env, lcData->listener); + } + + static void fileTransferSend(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size) { + JNIEnv *env = 0; + jobject jmsg; + size_t asking = *size; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + jobject jbuffer = buff ? env->NewDirectByteBuffer(buff, asking) : NULL; + *size = env->CallIntMethod(lcData->listener, + lcData->fileTransferSendId, + lcData->core, + (jmsg = getChatMessage(env, message)), + jcontent, + jbuffer, + asking); + if (jcontent) { + env->DeleteLocalRef(jcontent); + } + if (jbuffer) { + env->DeleteLocalRef(jbuffer); + } + handle_possible_java_exception(env, lcData->listener); + } + + static void fileTransferRecv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) { + JNIEnv *env = 0; + jobject jmsg; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + + jbyteArray jbytes = env->NewByteArray(size); + env->SetByteArrayRegion(jbytes, 0, size, (jbyte*)buff); + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + + env->CallVoidMethod(lcData->listener, + lcData->fileTransferRecvId, + lcData->core, + (jmsg = getChatMessage(env, message)), + jcontent, + jbytes, + size); + if (jcontent) { + env->DeleteLocalRef(jcontent); + } + handle_possible_java_exception(env, lcData->listener); + } + static void logCollectionUploadProgressIndication(LinphoneCore *lc, size_t offset, size_t total) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + env->CallVoidMethod(lcData->listener + ,lcData->logCollectionUploadProgressId + ,lcData->core + ,(jlong)offset + ,(jlong)total); + handle_possible_java_exception(env, lcData->listener); + } + static void logCollectionUploadStateChange(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table); + jstring msg = info ? env->NewStringUTF(info) : NULL; + env->CallVoidMethod(lcData->listener + ,lcData->logCollectionUploadStateId + ,lcData->core + ,env->CallStaticObjectMethod(lcData->logCollectionUploadStateClass,lcData->logCollectionUploadStateFromIntId,(jint)state), + msg); + handle_possible_java_exception(env, lcData->listener); + if (msg) { + env->DeleteLocalRef(msg); + } + } + +private: + static inline void handle_possible_java_exception(JNIEnv *env, jobject listener) + { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + ms_error("Listener %p raised an exception",listener); + } + } }; + extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env - ,jobject thiz + ,jobject thiz ,jobject jlistener ,jstring juserConfig ,jstring jfactoryConfig - ,jobject juserdata){ + ,jobject juserdata){ const char* userConfig = juserConfig?env->GetStringUTFChars(juserConfig, NULL):NULL; const char* factoryConfig = jfactoryConfig?env->GetStringUTFChars(jfactoryConfig, NULL):NULL; - LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata); + + LinphoneCoreVTable *vTable = linphone_core_v_table_new(); + LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener); + linphone_core_v_table_set_user_data(vTable, ldata); + + ms_init(); // Initialize mediastreamer2 before loading the plugins #ifdef HAVE_ILBC libmsilbc_init(); // requires an fpu @@ -519,6 +1130,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* #ifdef HAVE_X264 libmsx264_init(); #endif +#ifdef HAVE_OPENH264 + libmsopenh264_init(); +#endif #ifdef HAVE_AMR libmsamr_init(); #endif @@ -528,37 +1142,145 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* #ifdef HAVE_G729 libmsbcg729_init(); #endif - jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable - ,userConfig - ,factoryConfig - ,ldata); +#ifdef HAVE_WEBRTC + libmswebrtc_init(); +#endif +#ifdef HAVE_CODEC2 + libmscodec2_init(); +#endif + + jobject core = env->NewGlobalRef(thiz); + jlong nativePtr = (jlong)linphone_core_new(vTable, userConfig, factoryConfig, core); if (userConfig) env->ReleaseStringUTFChars(juserConfig, userConfig); if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig); return nativePtr; } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env - ,jobject thiz - ,jlong lc) { - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); - linphone_core_destroy((LinphoneCore*)lc); - delete lcData; +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env, jobject thiz, jlong native_ptr) { + LinphoneCore *lc=(LinphoneCore*)native_ptr; + jobject core = (jobject)linphone_core_get_user_data(lc); + + jobject multicast_lock = lc->multicast_lock; + jobject multicast_lock_class = lc->multicast_lock_class; + jobject wifi_lock = lc->wifi_lock; + jobject wifi_lock_class = lc->wifi_lock_class; + + linphone_core_destroy(lc); + ms_exit(); + + if (wifi_lock) env->DeleteGlobalRef(wifi_lock); + if (wifi_lock_class) env->DeleteGlobalRef(wifi_lock_class); + if (multicast_lock) env->DeleteGlobalRef(multicast_lock); + if (multicast_lock_class) env->DeleteGlobalRef(multicast_lock_class); + + if (core) { + env->DeleteGlobalRef(core); + } } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addListener(JNIEnv* env, jobject thiz, jlong lc, jobject jlistener) { + LinphoneCoreVTable *vTable = linphone_core_v_table_new(); + LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener); + linphone_core_v_table_set_user_data(vTable, ldata); + linphone_core_add_listener((LinphoneCore*)lc, vTable); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeListener(JNIEnv* env, jobject thiz, jlong lc, jobject jlistener) { + MSList* iterator; + LinphoneCore *core = (LinphoneCore*)lc; + //jobject listener = env->NewGlobalRef(jlistener); + for (iterator = core->vtable_refs; iterator != NULL; ) { + VTableReference *ref=(VTableReference*)(iterator->data); + LinphoneCoreVTable *vTable = ref->valid ? ref->vtable : NULL; + iterator = iterator->next; //Because linphone_core_remove_listener may change the list + if (vTable) { + LinphoneCoreData *data = (LinphoneCoreData*) linphone_core_v_table_get_user_data(vTable); + if (data && env->IsSameObject(data->listener, jlistener)) { + linphone_core_remove_listener(core, vTable); + delete data; + linphone_core_v_table_destroy(vTable); + } + } + } + //env->DeleteGlobalRef(listener); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_uploadLogCollection(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneCore *core = (LinphoneCore*)lc; + linphone_core_upload_log_collection(core); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_resetLogCollection(JNIEnv* env, jobject thiz) { + linphone_core_reset_log_collection(); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_migrateToMultiTransport(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return (jint) linphone_core_migrate_to_multi_transport((LinphoneCore *)lc); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: createInfoMessage + * 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_stopRinging(JNIEnv* env, jobject thiz, jlong lc) { + linphone_core_stop_ringing((LinphoneCore*)lc); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIEnv* env, jobject thiz, jlong lc, jstring jpath) { + const char* path = env->GetStringUTFChars(jpath, NULL); + linphone_core_set_chat_database_path((LinphoneCore*)lc, path); + env->ReleaseStringUTFChars(jpath, path); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact2(JNIEnv* env, jobject thiz, jlong lc, jstring jcontact) { + const char* contact = env->GetStringUTFChars(jcontact, NULL); + linphone_core_set_primary_contact((LinphoneCore*)lc, contact); + env->ReleaseStringUTFChars(jcontact, contact); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContact(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneAddress* identity = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + return identity ? env->NewStringUTF(linphone_address_as_string(identity)) : NULL; +} + + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) { - const char* displayname = env->GetStringUTFChars(jdisplayname, NULL); - const char* username = env->GetStringUTFChars(jusername, NULL); + const char* displayname = jdisplayname ? env->GetStringUTFChars(jdisplayname, NULL) : NULL; + const char* username = jusername ? env->GetStringUTFChars(jusername, NULL) : NULL; LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); - if (parsed != NULL) { - linphone_address_set_display_name(parsed, displayname); - linphone_address_set_username(parsed, username); - char *contact = linphone_address_as_string(parsed); + if (parsed != NULL) { + linphone_address_set_display_name(parsed, displayname); + linphone_address_set_username(parsed, username); + char *contact = linphone_address_as_string(parsed); linphone_core_set_primary_contact((LinphoneCore*)lc, contact); } - env->ReleaseStringUTFChars(jdisplayname, displayname); - env->ReleaseStringUTFChars(jusername, username); + if (jdisplayname) env->ReleaseStringUTFChars(jdisplayname, displayname); + if (jusername) env->ReleaseStringUTFChars(jusername, username); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) { + 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) { @@ -571,27 +1293,35 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDefaultProxyConfig( J ,jlong pc) { linphone_core_set_default_proxy((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig( JNIEnv* env + +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig(JNIEnv* env ,jobject thiz ,jlong lc) { LinphoneProxyConfig *config=0; linphone_core_get_default_proxy((LinphoneCore*)lc,&config); - return (jlong)config; + if(config != 0) { + jobject jproxy = getProxy(env,config,thiz); + return jproxy; + } else { + return NULL; + } } -extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigList(JNIEnv* env, jobject thiz, jlong lc) { +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigList(JNIEnv* env, jobject thiz, jlong 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); + jclass cls = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); + jobjectArray jProxies = env->NewObjectArray(proxyCount,cls,NULL); for (int i = 0; i < proxyCount; i++ ) { - jInternalArray[i] = (unsigned long) (proxies->data); + LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)proxies->data; + jobject jproxy = getProxy(env,proxy,thiz); + if(jproxy != NULL){ + env->SetObjectArrayElement(jProxies, i, jproxy); + } proxies = proxies->next; } - - env->ReleaseLongArrayElements(jProxies, jInternalArray, 0); - + env->DeleteGlobalRef(cls); return jProxies; } @@ -601,9 +1331,46 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* ,jlong lc ,jlong pc) { LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc; - linphone_proxy_config_set_user_data(proxy, env->NewGlobalRef(jproxyCfg)); + return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,proxy); +} - 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) { @@ -614,67 +1381,65 @@ 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) { const char* uri = env->GetStringUTFChars(juri, NULL); - LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); LinphoneCall* lCall = linphone_core_invite((LinphoneCore*)lc,uri); env->ReleaseStringUTFChars(juri, uri); - return lcd->getCall(env,lCall); + return 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) { - LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); - return lcd->getCall(env, linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to)); + return 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) { @@ -705,6 +1470,21 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_deferCallUpdate(JNIEnv * linphone_core_defer_call_update((LinphoneCore*)lc,(LinphoneCall*)call); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMedia(JNIEnv *env, jobject thiz, jlong lc, jlong c) { + LinphoneCore *core = (LinphoneCore *)lc; + LinphoneCall *call = (LinphoneCall *)c; + int ret = linphone_core_accept_early_media(core, call); + return (jboolean) ret == 0; +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMediaWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong c, jlong params) { + LinphoneCore *core = (LinphoneCore *)lc; + LinphoneCall *call = (LinphoneCall *)c; + const LinphoneCallParams *call_params = (LinphoneCallParams *) params; + int ret = linphone_core_accept_early_media_with_params(core, call, call_params); + return (jboolean) ret == 0; +} + extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCallLog( JNIEnv* env ,jobject thiz ,jlong lc @@ -716,6 +1496,20 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getNumberOfCallLogs( JNI ,jlong lc) { return (jint)ms_list_size(linphone_core_get_call_logs((LinphoneCore*)lc)); } + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMtu(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jint mtu) { + linphone_core_set_mtu((LinphoneCore*)lc,mtu); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMtu(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return linphone_core_get_mtu((LinphoneCore*)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable( JNIEnv* env ,jobject thiz ,jlong lc @@ -823,6 +1617,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_findPayloadType(JNIEnv* env->ReleaseStringUTFChars(jmime, mime); return result; } + extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTypes(JNIEnv* env ,jobject thiz ,jlong lc) { @@ -841,6 +1636,18 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTy return jCodecs; } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoCodecs(JNIEnv *env, jobject thiz, jlong lc, jlongArray jCodecs) { + MSList *pts = NULL; + int codecsCount = env->GetArrayLength(jCodecs); + jlong *codecs = env->GetLongArrayElements(jCodecs, NULL); + for (int i = 0; i < codecsCount; i++) { + PayloadType *pt = (PayloadType *)codecs[i]; + ms_list_append(pts, pt); + } + linphone_core_set_video_codecs((LinphoneCore *)lc, pts); + env->ReleaseLongArrayElements(jCodecs, codecs, 0); +} + extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listAudioPayloadTypes(JNIEnv* env ,jobject thiz ,jlong lc) { @@ -859,6 +1666,18 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listAudioPayloadTy return jCodecs; } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setAudioCodecs(JNIEnv *env, jobject thiz, jlong lc, jlongArray jCodecs) { + MSList *pts = NULL; + int codecsCount = env->GetArrayLength(jCodecs); + jlong *codecs = env->GetLongArrayElements(jCodecs, NULL); + for (int i = 0; i < codecsCount; i++) { + PayloadType *pt = (PayloadType *)codecs[i]; + pts = ms_list_append(pts, pt); + } + linphone_core_set_audio_codecs((LinphoneCore *)lc, pts); + env->ReleaseLongArrayElements(jCodecs, codecs, 0); +} + extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv* env ,jobject thiz ,jlong lc @@ -866,6 +1685,86 @@ 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" jboolean Java_org_linphone_core_LinphoneCoreImpl_payloadTypeIsVbr(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt) { + return (jboolean) linphone_core_payload_type_is_vbr((LinphoneCore*)lc, (PayloadType*)pt); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPayloadTypeBitrate(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt + ,jint bitrate) { + linphone_core_set_payload_type_bitrate((LinphoneCore*)lc,(PayloadType*)pt,bitrate); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPayloadTypeBitrate(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt) { + return (jint)linphone_core_get_payload_type_bitrate((LinphoneCore*)lc,(PayloadType*)pt); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPayloadTypeNumber(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt + ,jint number) { + linphone_core_set_payload_type_number((LinphoneCore*)lc,(PayloadType*)pt,number); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPayloadTypeNumber(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt) { + return (jint)linphone_core_get_payload_type_number((LinphoneCore*)lc,(PayloadType*)pt); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableAdaptiveRateControl(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jboolean enable) { + linphone_core_enable_adaptive_rate_control((LinphoneCore*)lc, enable); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isAdaptiveRateControlEnabled(JNIEnv* env + ,jobject thiz + ,jlong lc + ) { + return (jboolean)linphone_core_adaptive_rate_control_enabled((LinphoneCore*)lc); +} +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getAdaptiveRateAlgorithm(JNIEnv* env + ,jobject thiz + ,jlong lc + ) { + const char* alg = linphone_core_get_adaptive_rate_algorithm((LinphoneCore*)lc); + if (alg) { + return env->NewStringUTF(alg); + } else { + return NULL; + } +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAdaptiveRateAlgorithm(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jalg) { + const char* alg = jalg?env->GetStringUTFChars(jalg, NULL):NULL; + linphone_core_set_adaptive_rate_algorithm((LinphoneCore*)lc,alg); + if (alg) env->ReleaseStringUTFChars(jalg, alg); + +} + + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableEchoCancellation(JNIEnv* env ,jobject thiz ,jlong lc @@ -896,9 +1795,7 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getCurrentCall(JNIEnv ,jobject thiz ,jlong lc ) { - LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); - - return lcdata->getCall(env,linphone_core_get_current_call((LinphoneCore*)lc)); + return getCall(env,linphone_core_get_current_call((LinphoneCore*)lc)); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env ,jobject thiz @@ -907,24 +1804,70 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env ) { linphone_core_add_friend((LinphoneCore*)lc,(LinphoneFriend*)aFriend); } +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getFriendList(JNIEnv* env + ,jobject thiz + ,jlong lc) { + const MSList* friends = linphone_core_get_friend_list((LinphoneCore*)lc); + int friendsSize = ms_list_size(friends); + jclass cls = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneFriendImpl")); + jobjectArray jFriends = env->NewObjectArray(friendsSize,cls,NULL); + + for (int i = 0; i < friendsSize; i++) { + LinphoneFriend* lfriend = (LinphoneFriend*)friends->data; + jobject jfriend = getFriend(env,lfriend); + if(jfriend != NULL){ + env->SetObjectArrayElement(jFriends, i, jfriend); + } + friends = friends->next; + } + + env->DeleteGlobalRef(cls); + return jFriends; +} 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 +1885,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 @@ -969,6 +1920,25 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getRing(JNIEnv* env return NULL; } } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setTone(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jint toneid + ,jstring jpath) { + const char* path = jpath ? env->GetStringUTFChars(jpath, NULL) : NULL; + linphone_core_set_tone((LinphoneCore *)lc, (LinphoneToneID)toneid, path); + if (path) env->ReleaseStringUTFChars(jpath, path); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setCallErrorTone(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jint reason + ,jstring jpath) { + const char* path = jpath ? env->GetStringUTFChars(jpath, NULL) : NULL; + linphone_core_set_call_error_tone((LinphoneCore *)lc, (LinphoneReason)reason, path); + if (path) env->ReleaseStringUTFChars(jpath, path); +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRootCA(JNIEnv* env ,jobject thiz ,jlong lc @@ -977,6 +1947,16 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRootCA(JNIEnv* env linphone_core_set_root_ca((LinphoneCore*)lc,path); if (path) env->ReleaseStringUTFChars(jpath, path); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRingback(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jpath) { + const char* path = jpath?env->GetStringUTFChars(jpath, NULL):NULL; + linphone_core_set_ringback((LinphoneCore*)lc,path); + if (path) env->ReleaseStringUTFChars(jpath, path); + +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableKeepAlive(JNIEnv* env ,jobject thiz ,jlong lc @@ -994,22 +1974,46 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI ,jobject thiz ,jlong lc ,jobject data) { - return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc - , LinphoneCoreData::ecCalibrationStatus - , data?env->NewGlobalRef(data):NULL); + LinphoneCoreVTable *vTable = linphone_core_v_table_new(); + LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, data); + linphone_core_v_table_set_user_data(vTable, ldata); + + return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc, ldata->ecCalibrationStatus, NULL, NULL, vTable); } -extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration(JNIEnv *env, jobject thiz, jlong lc){ +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration(JNIEnv *env, jobject thiz, jlong lc) { MSSndCard *sndcard; - MSSndCardManager *m=ms_snd_card_manager_get(); - const char *card=linphone_core_get_capture_device((LinphoneCore*)lc); - sndcard=ms_snd_card_manager_get_card(m,card); - if (sndcard == NULL){ - ms_error("Could not get soundcard."); + MSSndCardManager *m = ms_snd_card_manager_get(); + const char *card = linphone_core_get_capture_device((LinphoneCore*)lc); + sndcard = ms_snd_card_manager_get_card(m, card); + if (sndcard == NULL) { + ms_error("Could not get soundcard %s", card); return TRUE; } - return (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) || (ms_snd_card_get_minimal_latency(sndcard)>0); + + SoundDeviceDescription *sound_description = sound_device_description_get(); + if(sound_description != NULL && sound_description == &genericSoundDeviceDescriptor){ + return TRUE; + } + + 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 FALSE; + return TRUE; +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_hasBuiltInEchoCanceler(JNIEnv *env, jobject thiz, jlong lc) { + MSSndCard *sndcard; + MSSndCardManager *m = ms_snd_card_manager_get(); + const char *card = linphone_core_get_capture_device((LinphoneCore*)lc); + sndcard = ms_snd_card_manager_get_card(m, card); + if (sndcard == NULL) { + ms_error("Could not get soundcard %s", card); + return FALSE; + } + + if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return TRUE; + return FALSE; } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env @@ -1048,16 +2052,50 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandat linphone_core_set_media_encryption_mandatory((LinphoneCore*)lc, yesno); } +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: disableChat + * Signature: (JI)V + */ +extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_disableChat(JNIEnv *env, jobject jobj, jlong ptr, jint reason){ + linphone_core_disable_chat((LinphoneCore*)ptr,(LinphoneReason)reason); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: enableChat + * Signature: (J)V + */ +extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableChat(JNIEnv *env, jobject jobj, jlong ptr){ + linphone_core_enable_chat((LinphoneCore*)ptr); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: chatEnabled + * Signature: (J)Z + */ +extern "C" JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_chatEnabled(JNIEnv *env, jobject jobj, jlong ptr){ + return (jboolean) linphone_core_chat_enabled((LinphoneCore*)ptr); +} + + //ProxyConfig -extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { - LinphoneProxyConfig* proxy = linphone_proxy_config_new(); - return (jlong) proxy; +extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_createProxyConfig(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneProxyConfig* proxy = linphone_core_create_proxy_config((LinphoneCore *)lc); + linphone_proxy_config_set_user_data(proxy,env->NewWeakGlobalRef(thiz)); + return (jlong) proxy; } -extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_delete(JNIEnv* env,jobject thiz,jlong ptr) { - linphone_proxy_config_destroy((LinphoneProxyConfig*)ptr); +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_finalize(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneProxyConfig *proxy=(LinphoneProxyConfig*)ptr; + linphone_proxy_config_set_user_data(proxy,NULL); + linphone_proxy_config_unref(proxy); } + extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setIdentity(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jidentity) { const char* identity = env->GetStringUTFChars(jidentity, NULL); linphone_proxy_config_set_identity((LinphoneProxyConfig*)proxyCfg,identity); @@ -1086,10 +2124,25 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn } } extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) { - const char* params = env->GetStringUTFChars(jparams, NULL); + const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL; linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params); - env->ReleaseStringUTFChars(jparams, params); + if (jparams) env->ReleaseStringUTFChars(jparams, params); } +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) { + const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL; + linphone_proxy_config_set_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg, params); + if (jparams) env->ReleaseStringUTFChars(jparams, params); +} +extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) { + const char* params = linphone_proxy_config_get_contact_parameters((LinphoneProxyConfig*)proxyCfg); + return params ? env->NewStringUTF(params) : NULL; +} +extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) { + const char* params = linphone_proxy_config_get_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg); + return params ? env->NewStringUTF(params) : NULL; +} + + extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) { if (jroute != NULL) { const char* route = env->GetStringUTFChars(jroute, NULL); @@ -1124,6 +2177,7 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_edit(JNIEnv* env, extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_done(JNIEnv* env,jobject thiz,jlong proxyCfg) { linphone_proxy_config_done((LinphoneProxyConfig*)proxyCfg); } + extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_normalizePhoneNumber(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jnumber) { if (jnumber == 0) { ms_error("cannot normalized null number"); @@ -1162,10 +2216,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 @@ -1174,6 +2233,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 @@ -1184,36 +2249,197 @@ 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); +} + +extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_getErrorInfo(JNIEnv* env,jobject thiz,jlong ptr) { + return (jlong)linphone_proxy_config_get_error_info((LinphoneProxyConfig *) ptr); +} + +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPublishExpires(JNIEnv* env,jobject thiz,jlong ptr) { + return (jint)linphone_proxy_config_get_publish_expires((LinphoneProxyConfig *) ptr); +} +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setPublishExpires(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jint jval) { + linphone_proxy_config_set_publish_expires((LinphoneProxyConfig *) ptr, jval); +} //Auth Info extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env - , jobject thiz - , jstring jusername - , jstring juserid - , jstring jpassword - , jstring jha1 - , jstring jrealm) { - - const char* username = env->GetStringUTFChars(jusername, NULL); - const char* userid = env->GetStringUTFChars(juserid, NULL); - const char* password = env->GetStringUTFChars(jpassword, NULL); - const char* ha1 = env->GetStringUTFChars(jha1, NULL); - const char* realm = env->GetStringUTFChars(jrealm, NULL); - jlong auth = (jlong)linphone_auth_info_new(username,userid,password,ha1,realm); - - env->ReleaseStringUTFChars(jusername, username); - env->ReleaseStringUTFChars(juserid, userid); - env->ReleaseStringUTFChars(jpassword, password); - env->ReleaseStringUTFChars(jha1, ha1); - env->ReleaseStringUTFChars(jrealm, realm); - return auth; - + , jobject thiz ) { + 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 , jlong ptr) { linphone_auth_info_destroy((LinphoneAuthInfo*)ptr); } +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getPassword + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getPassword +(JNIEnv *env , jobject, jlong auth_info) { + const char* passwd = linphone_auth_info_get_passwd((LinphoneAuthInfo*)auth_info); + if (passwd) { + return env->NewStringUTF(passwd); + } else { + return NULL; + } +} +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getRealm + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getRealm +(JNIEnv *env , jobject, jlong auth_info) { + const char* realm = linphone_auth_info_get_realm((LinphoneAuthInfo*)auth_info); + if (realm) { + return env->NewStringUTF(realm); + } 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; + } +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getUsername + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getUsername +(JNIEnv *env , jobject, jlong auth_info) { + const char* username = linphone_auth_info_get_username((LinphoneAuthInfo*)auth_info); + if (username) { + return env->NewStringUTF(username); + } else { + return NULL; + } +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setPassword + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setPassword +(JNIEnv *env, jobject, jlong auth_info, jstring jpassword) { + const char* password = jpassword?env->GetStringUTFChars(jpassword, NULL):NULL; + linphone_auth_info_set_passwd((LinphoneAuthInfo*)auth_info,password); + if (password) env->ReleaseStringUTFChars(jpassword, password); +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setRealm + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setRealm +(JNIEnv *env, jobject, jlong auth_info, jstring jrealm) { + const char* realm = jrealm?env->GetStringUTFChars(jrealm, NULL):NULL; + 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 + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setUsername +(JNIEnv *env, jobject, jlong auth_info, jstring jusername) { + const char* username = jusername?env->GetStringUTFChars(jusername, NULL):NULL; + linphone_auth_info_set_username((LinphoneAuthInfo*)auth_info,username); + if (username) env->ReleaseStringUTFChars(jusername, username); +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setAuthUserId + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setUserId +(JNIEnv *env, jobject, jlong auth_info, jstring juserid) { + const char* userid = juserid?env->GetStringUTFChars(juserid, NULL):NULL; + linphone_auth_info_set_userid((LinphoneAuthInfo*)auth_info,userid); + if (userid) env->ReleaseStringUTFChars(juserid, userid); +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getAuthUserId + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getUserId +(JNIEnv *env , jobject, jlong auth_info) { + const char* userid = linphone_auth_info_get_userid((LinphoneAuthInfo*)auth_info); + if (userid) { + return env->NewStringUTF(userid); + } else { + return NULL; + } +} + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setHa1 + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setHa1 +(JNIEnv *env, jobject, jlong auth_info, jstring jha1) { + const char* ha1 = jha1?env->GetStringUTFChars(jha1, NULL):NULL; + linphone_auth_info_set_ha1((LinphoneAuthInfo*)auth_info,ha1); + if (ha1) env->ReleaseStringUTFChars(jha1, ha1); +} + + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getHa1 + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getHa1 +(JNIEnv *env , jobject, jlong auth_info) { + const char* ha1 = linphone_auth_info_get_ha1((LinphoneAuthInfo*)auth_info); + if (ha1) { + return env->NewStringUTF(ha1); + } else { + return NULL; + } +} + //LinphoneAddress @@ -1221,21 +2447,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 @@ -1268,7 +2507,18 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* return NULL; } } - +extern "C" jint Java_org_linphone_core_LinphoneAddressImpl_getTransport(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneTransportType transporttype = linphone_address_get_transport((LinphoneAddress*)ptr); + return (jint)transporttype; +} +extern "C" jint Java_org_linphone_core_LinphoneAddressImpl_getPort(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + int port = linphone_address_get_port((LinphoneAddress*)ptr); + return (jint)port; +} extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1293,7 +2543,34 @@ 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); +} +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setTransport(JNIEnv* env + ,jobject thiz + ,jlong address + ,jint jtransport) { + linphone_address_set_transport((LinphoneAddress*)address, (LinphoneTransportType) jtransport); +} +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setPort(JNIEnv* env + ,jobject thiz + ,jlong address + ,jint jport) { + linphone_address_set_port((LinphoneAddress*)address, (LinphoneTransportType) jport); +} //CallLog extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv* env @@ -1348,95 +2625,21 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getUploadBandwidt } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) { const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; - const report_block_t *srb = NULL; - - if (!stats || !stats->sent_rtcp) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (!srb) - return (jfloat)0.0; - return (jfloat)(100.0 * report_block_get_fraction_lost(srb) / 256.0); + return (jfloat) linphone_call_stats_get_sender_loss_rate(stats); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) { const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; - const report_block_t *rrb = NULL; - - if (!stats || !stats->received_rtcp) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - if (!rrb) - return (jfloat)0.0; - return (jfloat)(100.0 * report_block_get_fraction_lost(rrb) / 256.0); + return (jfloat) linphone_call_stats_get_receiver_loss_rate(stats); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - const LinphoneCallParams *params; - const PayloadType *pt; - const report_block_t *srb = NULL; - - if (!stats || !call || !stats->sent_rtcp) - return (jfloat)0.0; - params = linphone_call_get_current_params(call); - if (!params) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (!srb) - return (jfloat)0.0; - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - pt = linphone_call_params_get_used_audio_codec(params); - else - pt = linphone_call_params_get_used_video_codec(params); - if (!pt || (pt->clock_rate == 0)) - return (jfloat)0.0; - return (jfloat)((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate); + return (jfloat) linphone_call_stats_get_sender_interarrival_jitter(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - const LinphoneCallParams *params; - const PayloadType *pt; - const report_block_t *rrb = NULL; - - if (!stats || !call || !stats->received_rtcp) - return (jfloat)0.0; - params = linphone_call_get_current_params(call); - if (!params) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - if (!rrb) - return (jfloat)0.0; - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - pt = linphone_call_params_get_used_audio_codec(params); - else - pt = linphone_call_params_get_used_video_codec(params); - if (!pt || (pt->clock_rate == 0)) - return (jfloat)0.0; - return (jfloat)((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate); + return (jfloat) linphone_call_stats_get_receiver_interarrival_jitter(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay(JNIEnv *env, jobject thiz, jlong stats_ptr) { return (jfloat)((LinphoneCallStats *)stats_ptr)->round_trip_delay; @@ -1444,23 +2647,29 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay extern "C" jlong Java_org_linphone_core_LinphoneCallStatsImpl_getLatePacketsCumulativeNumber(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - rtp_stats_t rtp_stats; - - if (!stats || !call) - return (jlong)0; - memset(&rtp_stats, 0, sizeof(rtp_stats)); - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats); -#ifdef VIDEO_ENABLED - else - video_stream_get_local_rtp_stats(call->videostream, &rtp_stats); -#endif - return (jlong)rtp_stats.outoftime; + return (jlong) linphone_call_stats_get_late_packets_cumulative_number(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getJitterBufferSize(JNIEnv *env, jobject thiz, jlong stats_ptr) { return (jfloat)((LinphoneCallStats *)stats_ptr)->jitter_stats.jitter_buffer_size_ms; } +extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getLocalLossRate(JNIEnv *env, jobject thiz,jlong stats_ptr) { + const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; + return stats->local_loss_rate; +} + +extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getLocalLateRate(JNIEnv *env, jobject thiz, jlong stats_ptr) { + const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; + return stats->local_late_rate; +} + +extern "C" void Java_org_linphone_core_LinphoneCallStatsImpl_updateStats(JNIEnv *env, jobject thiz, jlong call_ptr, jint mediatype) { + if (mediatype==LINPHONE_CALL_STATS_AUDIO) + linphone_call_get_audio_stats((LinphoneCall*)call_ptr); + else + linphone_call_get_video_stats((LinphoneCall*)call_ptr); +} + /*payloadType*/ extern "C" jstring Java_org_linphone_core_PayloadTypeImpl_toString(JNIEnv* env,jobject thiz,jlong ptr) { PayloadType* pt = (PayloadType*)ptr; @@ -1521,6 +2730,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getErrorInfo( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong)linphone_call_get_error_info((LinphoneCall*)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getReason( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint)linphone_call_get_reason((LinphoneCall*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) { LinphoneCall *call = (LinphoneCall *)ptr; const char *value=linphone_call_get_remote_user_agent(call); @@ -1542,6 +2763,39 @@ 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; + LinphoneCall *ret=linphone_call_get_transferer_call(call); + return 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; + LinphoneCall *ret=linphone_call_get_transfer_target_call(call); + return getCall(env,ret); +} + extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoCancellation( JNIEnv* env ,jobject thiz ,jlong ptr @@ -1569,8 +2823,7 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isEchoLimiterEnabled extern "C" jobject Java_org_linphone_core_LinphoneCallImpl_getReplacedCall( JNIEnv* env ,jobject thiz ,jlong ptr) { - LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data(linphone_call_get_core((LinphoneCall*)ptr)); - return lcd->getCall(env,linphone_call_get_replaced_call((LinphoneCall*)ptr)); + return getCall(env,linphone_call_get_replaced_call((LinphoneCall*)ptr)); } extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getCurrentQuality( JNIEnv* env @@ -1585,6 +2838,15 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getAverageQuality( JNI return (jfloat)linphone_call_get_average_quality((LinphoneCall*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getPlayer(JNIEnv *env, jobject thiz, jlong callPtr) { + return (jlong)linphone_call_get_player((LinphoneCall *)callPtr); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_mediaInProgress( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jboolean) linphone_call_media_in_progress((LinphoneCall*)ptr); +} //LinphoneFriend extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env @@ -1594,10 +2856,12 @@ 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); + linphone_friend_set_user_data(lResult,env->NewWeakGlobalRef(thiz)); env->ReleaseStringUTFChars(jFriendUri, friendUri); } else { lResult = linphone_friend_new(); + linphone_friend_set_user_data(lResult,env->NewWeakGlobalRef(thiz)); } return (jlong)lResult; } @@ -1605,7 +2869,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 @@ -1639,6 +2903,52 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env ,jlong ptr) { return (jint)linphone_friend_get_status((LinphoneFriend*)ptr); } +extern "C" jobject Java_org_linphone_core_LinphoneFriendImpl_getCore(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneCore *lc=linphone_friend_get_core((LinphoneFriend*)ptr); + if (lc!=NULL){ + jobject core = (jobject)linphone_core_get_user_data(lc); + return core; + } + return NULL; +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setRefKey(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jkey) { + const char* key = env->GetStringUTFChars(jkey, NULL); + linphone_friend_set_ref_key((LinphoneFriend*)ptr,key); + env->ReleaseStringUTFChars(jkey, key); +} +extern "C" jstring Java_org_linphone_core_LinphoneFriendImpl_getRefKey(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + const char * key = linphone_friend_get_ref_key((LinphoneFriend *)ptr); + return key ? env->NewStringUTF(key) : NULL; +} + + +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_finalize(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneFriend *lfriend=(LinphoneFriend*)ptr; + linphone_friend_set_user_data(lfriend,NULL); + linphone_friend_unref(lfriend); +} + +/* + * 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) { @@ -1655,16 +2965,55 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeFriend(JNIEnv* en ,jlong lf) { linphone_core_remove_friend((LinphoneCore*)ptr, (LinphoneFriend*)lf); } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIEnv* env +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIEnv* env ,jobject thiz ,jlong ptr ,jstring jaddress) { const char* address = env->GetStringUTFChars(jaddress, NULL); LinphoneFriend *lf = linphone_core_get_friend_by_address((LinphoneCore*)ptr, address); env->ReleaseStringUTFChars(jaddress, address); - return (jlong) lf; + if(lf != NULL) { + jobject jfriend = getFriend(env,lf); + return jfriend; + } else { + return NULL; + } +} + +extern "C" jlongArray _LinphoneChatRoomImpl_getHistory(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,MSList* history) { + 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; + } + + ms_list_free(history); + + env->ReleaseLongArrayElements(jHistory, jInternalArray, 0); + + return jHistory; +} +extern "C" jlongArray Java_org_linphone_core_LinphoneChatRoomImpl_getHistoryRange(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jint start + ,jint end) { + MSList* history = linphone_chat_room_get_history_range((LinphoneChatRoom*)ptr, start, end); + return _LinphoneChatRoomImpl_getHistory(env, thiz, ptr, history); +} +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); + return _LinphoneChatRoomImpl_getHistory(env, thiz, ptr, history); } -//LinphoneChatRoom extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1680,17 +3029,150 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM return (jlong) chatMessage; } -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" 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" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv* env +extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getHistorySize (JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_room_get_history_size((LinphoneChatRoom*)ptr); +} +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); +} +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_compose(JNIEnv *env, jobject thiz, jlong ptr) { + linphone_chat_room_compose((LinphoneChatRoom *)ptr); +} +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_isRemoteComposing(JNIEnv *env, jobject thiz, jlong ptr) { + return (jboolean)linphone_chat_room_is_remote_composing((LinphoneChatRoom *)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env + ,jobject thiz + ,jlong room + ,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_destroy(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_room_destroy((LinphoneChatRoom*)ptr); +} + +extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createFileTransferMessage(JNIEnv* env, jobject thiz, jlong ptr, jstring jname, jstring jtype, jstring jsubtype, jint data_size) { + LinphoneContentPrivate content = {0}; + LinphoneChatMessage *message = NULL; + + content.type = (char*)env->GetStringUTFChars(jtype, NULL); + content.subtype = (char*)env->GetStringUTFChars(jsubtype, NULL); + content.name = (char*)env->GetStringUTFChars(jname, NULL); + content.size = data_size; + message = linphone_chat_room_create_file_transfer_message((LinphoneChatRoom *)ptr, LINPHONE_CONTENT(&content)); + env->ReleaseStringUTFChars(jtype, content.type); + env->ReleaseStringUTFChars(jsubtype, content.subtype); + env->ReleaseStringUTFChars(jname, content.name); + + return (jlong) message; +} + + + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_cancelFileTransfer(JNIEnv* env, jobject thiz, jlong ptr) { + linphone_chat_message_cancel_file_transfer((LinphoneChatMessage *)ptr); +} + +extern "C" jobject Java_org_linphone_core_LinphoneChatMessageImpl_getFileTransferInformation(JNIEnv* env, jobject thiz, jlong ptr) { + const LinphoneContent *content = linphone_chat_message_get_file_transfer_information((LinphoneChatMessage *)ptr); + if (content) + return create_java_linphone_content(env, content); + return NULL; +} + +extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getAppData(JNIEnv* env, jobject thiz, jlong ptr) { + const char * app_data = linphone_chat_message_get_appdata((LinphoneChatMessage *)ptr); + return app_data ? env->NewStringUTF(app_data) : NULL; +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setAppData(JNIEnv* env, jobject thiz, jlong ptr, jstring appdata) { + const char * data = appdata ? env->GetStringUTFChars(appdata, NULL) : NULL; + linphone_chat_message_set_appdata((LinphoneChatMessage *)ptr, data); + if (appdata) + env->ReleaseStringUTFChars(appdata, data); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFileTransferServer(JNIEnv* env, jobject thiz, jlong ptr, jstring server_url) { + const char * url = server_url ? env->GetStringUTFChars(server_url, NULL) : NULL; + linphone_core_set_file_transfer_server((LinphoneCore *)ptr, url); + if (server_url) + env->ReleaseStringUTFChars(server_url, url); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getFileTransferServer(JNIEnv* env, jobject thiz, jlong ptr) { + const char * server_url = linphone_core_get_file_transfer_server((LinphoneCore *)ptr); + return server_url ? env->NewStringUTF(server_url) : NULL; +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_store(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_store((LinphoneChatMessage*)ptr); +} + +extern "C" jbyteArray Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv* env ,jobject thiz ,jlong ptr) { - jstring jvalue =env->NewStringUTF(linphone_chat_message_get_text((LinphoneChatMessage*)ptr)); - return jvalue; + const char *message = linphone_chat_message_get_text((LinphoneChatMessage*)ptr); + if (message){ + size_t length = strlen(message); + jbyteArray array = env->NewByteArray(length); + env->SetByteArrayRegion(array, 0, length, (const jbyte*)message); + return array; + } + return NULL; +} + +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_chat_message_get_reason((LinphoneChatMessage*)ptr); +} + +extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getErrorInfo(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong)linphone_chat_message_get_error_info((LinphoneChatMessage*)ptr); } extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env @@ -1732,12 +3214,195 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getFrom(JNIEnv* return (jlong) linphone_chat_message_get_from((LinphoneChatMessage*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getTo(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong) linphone_chat_message_get_to((LinphoneChatMessage*)ptr); +} + extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv* env ,jobject thiz ,jlong ptr) { return (jlong) linphone_chat_message_get_peer_address((LinphoneChatMessage*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getTime(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + 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" void Java_org_linphone_core_LinphoneChatMessageImpl_setFileTransferFilepath(JNIEnv* env + ,jobject thiz + ,jlong ptr, jstring jpath) { + const char* path = env->GetStringUTFChars(jpath, NULL); + linphone_chat_message_set_file_transfer_filepath((LinphoneChatMessage*)ptr, path); + env->ReleaseStringUTFChars(jpath, path); +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_downloadFile(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_download_file((LinphoneChatMessage*)ptr); +} + +static void message_state_changed(LinphoneChatMessage* msg, LinphoneChatMessageState state) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V"); + jobject jmessage = getChatMessage(env, msg); + env->DeleteLocalRef(clazz); + + jclass chatMessageStateClass = (jclass)env->FindClass("org/linphone/core/LinphoneChatMessage$State"); + jmethodID chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass, "fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;"); + env->CallVoidMethod(listener, method, jmessage, env->CallStaticObjectMethod(chatMessageStateClass, chatMessageStateFromIntId, (jint)state)); + + if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { + env->DeleteGlobalRef(listener); + } + env->DeleteLocalRef(chatMessageStateClass); +} + +static void file_transfer_progress_indication(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t total) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferProgressChanged", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;II)V"); + env->DeleteLocalRef(clazz); + jobject jmessage = getChatMessage(env, msg); + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + env->CallVoidMethod(listener, method, jmessage, jcontent, offset, total); + if (jcontent) { + env->DeleteLocalRef(jcontent); + } +} + +static void file_transfer_recv(LinphoneChatMessage *msg, const LinphoneContent* content, const LinphoneBuffer *buffer) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferReceived", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Lorg/linphone/core/LinphoneBuffer;)V"); + env->DeleteLocalRef(clazz); + + jobject jmessage = getChatMessage(env, msg); + jobject jbuffer = buffer ? create_java_linphone_buffer(env, buffer) : NULL; + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + env->CallVoidMethod(listener, method, jmessage, jcontent, jbuffer); + if (jbuffer) { + env->DeleteLocalRef(jbuffer); + } + if (jcontent) { + env->DeleteLocalRef(jcontent); + } +} + +static LinphoneBuffer* file_transfer_send(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t size) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + LinphoneBuffer *buffer = NULL; + if (result != 0) { + ms_error("cannot attach VM\n"); + return buffer; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferSent","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;IILorg/linphone/core/LinphoneBuffer;)V"); + env->DeleteLocalRef(clazz); + + jobject jmessage = getChatMessage(env, msg); + jobject jbuffer = create_java_linphone_buffer(env, NULL); + jobject jcontent = content ? create_java_linphone_content(env, content) : NULL; + env->CallVoidMethod(listener, method, jmessage, jcontent, offset, size, jbuffer); + if (jcontent) { + env->DeleteLocalRef(jcontent); + } + + buffer = create_c_linphone_buffer_from_java_linphone_buffer(env, jbuffer); + env->DeleteLocalRef(jbuffer); + return buffer; +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { + jobject listener = env->NewGlobalRef(jlistener); + LinphoneChatMessage *message = (LinphoneChatMessage *)ptr; + LinphoneChatMessageCbs *cbs; + + message->cb_ud = listener; + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, message_state_changed); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_recv); + linphone_chat_message_cbs_set_file_transfer_send(cbs, file_transfer_send); +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_unref(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_unref((LinphoneChatMessage*)ptr); +} + +extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + 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 @@ -1758,39 +3423,70 @@ static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessag jobject listener = (jobject) ud; jclass clazz = (jclass) env->GetObjectClass(listener); jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V"); + jobject jmessage=(jobject)linphone_chat_message_get_user_data(msg); - LinphoneCore *lc = linphone_chat_room_get_lc(linphone_chat_message_get_chat_room(msg)); - LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jclass chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State")); + jmethodID chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;"); env->CallVoidMethod( listener, method, - (jobject)linphone_chat_message_get_user_data(msg), - env->CallStaticObjectMethod(lcData->chatMessageStateClass,lcData->chatMessageStateFromIntId,(jint)state)); + jmessage, + env->CallStaticObjectMethod(chatMessageStateClass,chatMessageStateFromIntId,(jint)state)); if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { env->DeleteGlobalRef(listener); + env->DeleteGlobalRef(jmessage); + env->DeleteGlobalRef(chatMessageStateClass); + linphone_chat_message_set_user_data(msg,NULL); } } + +extern "C" jobject Java_org_linphone_core_LinphoneChatRoomImpl_getCore(JNIEnv* env + ,jobject thiz + ,jlong chatroom_ptr){ + LinphoneCore *lc=linphone_chat_room_get_core((LinphoneChatRoom*)chatroom_ptr); + jobject core = (jobject)linphone_core_get_user_data(lc); + return core; +} + extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env ,jobject thiz - ,jlong ptr - ,jlong jmessage + ,jlong chatroom_ptr + ,jobject message + ,jlong messagePtr ,jobject jlistener) { jobject listener = env->NewGlobalRef(jlistener); - linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener); + message = env->NewGlobalRef(message); + linphone_chat_message_ref((LinphoneChatMessage*)messagePtr); + linphone_chat_message_set_user_data((LinphoneChatMessage*)messagePtr, message); + linphone_chat_room_send_message2((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr, chat_room_impl_callback, (void*)listener); } + +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendChatMessage(JNIEnv* env + ,jobject thiz + ,jlong chatroom_ptr + ,jobject message + ,jlong messagePtr) { + message = env->NewGlobalRef(message); + linphone_chat_message_ref((LinphoneChatMessage*)messagePtr); + linphone_chat_message_set_user_data((LinphoneChatMessage*)messagePtr, message); + linphone_chat_room_send_chat_message((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env ,jobject thiz ,jlong lc ,jobject obj) { jobject oldWindow = (jobject) linphone_core_get_native_video_window_id((LinphoneCore*)lc); - if (oldWindow != NULL) { - env->DeleteGlobalRef(oldWindow); - } 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,(void *)obj); + if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): DeleteGlobalRef(%p)",oldWindow); + env->DeleteGlobalRef(oldWindow); } - linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(JNIEnv* env @@ -1798,13 +3494,15 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(JNIEn ,jlong lc ,jobject obj) { jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id((LinphoneCore*)lc); - if (oldWindow != NULL) { - env->DeleteGlobalRef(oldWindow); - } 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,(void *)obj); + if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): DeleteGlobalRef(%p)",oldWindow); + env->DeleteGlobalRef(oldWindow); } - linphone_core_set_native_preview_window_id((LinphoneCore*)lc,(unsigned long)obj); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDeviceRotation(JNIEnv* env @@ -1814,6 +3512,19 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDeviceRotation(JNIEnv linphone_core_set_device_rotation((LinphoneCore*)lc,rotation); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRemoteRingbackTone(JNIEnv *env, jobject thiz, jlong lc, jstring jtone){ + const char* tone = NULL; + if (jtone) tone=env->GetStringUTFChars(jtone, NULL); + linphone_core_set_remote_ringback_tone((LinphoneCore*)lc,tone); + if (tone) env->ReleaseStringUTFChars(jtone,tone); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getRemoteRingbackTone(JNIEnv *env, jobject thiz, jlong lc){ + const char *ret= linphone_core_get_remote_ringback_tone((LinphoneCore*)lc); + if (ret==NULL) return NULL; + jstring jvalue =env->NewStringUTF(ret); + return jvalue; +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc, jint enum_value){ linphone_core_set_firewall_policy((LinphoneCore*)lc,(LinphoneFirewallPolicy)enum_value); @@ -1868,6 +3579,37 @@ 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" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getSessionName(JNIEnv* env + ,jobject thiz + ,jlong cp + ) { + const char* name = linphone_call_params_get_session_name((LinphoneCallParams*)cp); + return name ? env->NewStringUTF(name) : NULL; +} + +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setSessionName(JNIEnv* env + ,jobject thiz + ,jlong cp + ,jstring jname) { + const char *name = jname ? env->GetStringUTFChars(jname,NULL) : NULL; + linphone_call_params_set_session_name((LinphoneCallParams*)cp,name); + if (name) env->ReleaseStringUTFChars(jname,name); +} + extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_audioBandwidth(JNIEnv *env, jobject thiz, jlong lcp, jint bw){ linphone_call_params_set_audio_bandwidth_limit((LinphoneCallParams*)lcp, bw); } @@ -1880,8 +3622,21 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnable return (jboolean)linphone_call_params_video_enabled((LinphoneCallParams*)lcp); } +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableVideoMulticast(JNIEnv *env, jobject thiz, jlong lcp, jboolean b){ + linphone_call_params_enable_video_multicast((LinphoneCallParams*)lcp, b); +} +extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_videoMulticastEnabled(JNIEnv *env, jobject thiz, jlong lcp){ + return (jboolean)linphone_call_params_video_multicast_enabled((LinphoneCallParams*)lcp); +} +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableAudioMulticast(JNIEnv *env, jobject thiz, jlong lcp, jboolean b){ + linphone_call_params_enable_audio_multicast((LinphoneCallParams*)lcp, b); +} +extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_audioMulticastEnabled(JNIEnv *env, jobject thiz, jlong lcp){ + return (jboolean)linphone_call_params_audio_multicast_enabled((LinphoneCallParams*)lcp); +} + extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_localConferenceMode(JNIEnv *env, jobject thiz, jlong lcp){ - return (jboolean)linphone_call_params_local_conference_mode((LinphoneCallParams*)lcp); + return (jboolean)linphone_call_params_get_local_conference_mode((LinphoneCallParams*)lcp); } extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong lcp, jstring jheader_name){ @@ -1907,6 +3662,24 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setRecordFile(JNIE }else linphone_call_params_set_record_file((LinphoneCallParams*)lcp,NULL); } +extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getSentVideoSize(JNIEnv *env, jobject thiz, jlong lcp) { + const LinphoneCallParams *params = (LinphoneCallParams *) lcp; + MSVideoSize vsize = linphone_call_params_get_sent_video_size(params); + jintArray arr = env->NewIntArray(2); + int tVsize [2]= {vsize.width,vsize.height}; + env->SetIntArrayRegion(arr, 0, 2, tVsize); + return arr; +} + +extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getReceivedVideoSize(JNIEnv *env, jobject thiz, jlong lcp) { + const LinphoneCallParams *params = (LinphoneCallParams *) lcp; + MSVideoSize vsize = linphone_call_params_get_received_video_size(params); + jintArray arr = env->NewIntArray(2); + int tVsize [2]= {vsize.width,vsize.height}; + env->SetIntArrayRegion(arr, 0, 2, tVsize); + return arr; +} + extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_destroy(JNIEnv *env, jobject thiz, jlong lc){ return linphone_call_params_destroy((LinphoneCallParams*)lc); } @@ -1942,8 +3715,7 @@ extern "C" void Java_org_linphone_core_LinphoneCallImpl_stopRecording(JNIEnv *en } extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddressWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong addr, jlong params){ - LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); - return lcd->getCall(env,linphone_core_invite_address_with_params((LinphoneCore *)lc, (const LinphoneAddress *)addr, (const LinphoneCallParams *)params)); + return getCall(env,linphone_core_invite_address_with_params((LinphoneCore *)lc, (const LinphoneAddress *)addr, (const LinphoneCallParams *)params)); } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_updateAddressWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong call, jlong params){ @@ -1961,18 +3733,40 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JN linphone_core_set_preferred_video_size((LinphoneCore *)lc, vsize); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredFramerate(JNIEnv *env, jobject thiz, jlong lc, jfloat framerate){ + linphone_core_set_preferred_framerate((LinphoneCore *)lc, framerate); +} + +extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getPreferredFramerate(JNIEnv *env, jobject thiz, jlong lc){ + return linphone_core_get_preferred_framerate((LinphoneCore *)lc); +} + +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); + jintArray arr = env->NewIntArray(2); int tVsize [2]= {vsize.width,vsize.height}; - env->SetIntArrayRegion(arr, 0, 2, tVsize); - return arr; + env->SetIntArrayRegion(arr, 0, 2, tVsize); + return arr; +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getDownloadBandwidth(JNIEnv *env, jobject thiz, jlong lc) { + return (jint) linphone_core_get_download_bandwidth((LinphoneCore *)lc); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadBandwidth(JNIEnv *env, jobject thiz, jlong lc, jint bw){ linphone_core_set_download_bandwidth((LinphoneCore *)lc, (int) bw); } +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getUploadBandwidth(JNIEnv *env, jobject thiz, jlong lc) { + return (jint) linphone_core_get_upload_bandwidth((LinphoneCore *)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadBandwidth(JNIEnv *env, jobject thiz, jlong lc, jint bw){ linphone_core_set_upload_bandwidth((LinphoneCore *)lc, (int) bw); } @@ -1981,10 +3775,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); } @@ -1996,14 +3798,106 @@ 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); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableAvpf(JNIEnv *env, jobject thiz, jlong ptr, jboolean enable) { + linphone_proxy_config_enable_avpf((LinphoneProxyConfig *)ptr, (bool)enable); +} + +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_avpfEnabled(JNIEnv *env, jobject thiz, jlong ptr) { + return linphone_proxy_config_avpf_enabled((LinphoneProxyConfig *)ptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr, jint interval) { + linphone_proxy_config_set_avpf_rr_interval((LinphoneProxyConfig *)ptr, (uint8_t)interval); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr) { + return (jint)linphone_proxy_config_get_avpf_rr_interval((LinphoneProxyConfig *)ptr); +} + + + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableQualityReporting(JNIEnv *env, jobject thiz, jlong ptr, jboolean enable) { + linphone_proxy_config_enable_quality_reporting((LinphoneProxyConfig *)ptr, (bool)enable); +} + +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_quality_reportingEnabled(JNIEnv *env, jobject thiz, jlong ptr) { + return linphone_proxy_config_quality_reporting_enabled((LinphoneProxyConfig *)ptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setQualityReportingInterval(JNIEnv *env, jobject thiz, jlong ptr, jint interval) { + linphone_proxy_config_set_quality_reporting_interval((LinphoneProxyConfig *)ptr, (uint8_t)interval); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getQualityReportingInterval(JNIEnv *env, jobject thiz, jlong ptr) { + return (jint)linphone_proxy_config_get_quality_reporting_interval((LinphoneProxyConfig *)ptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setQualityReportingCollector(JNIEnv *env, jobject thiz, jlong ptr, jstring jcollector) { + if (jcollector){ + const char *collector=env->GetStringUTFChars(jcollector, NULL); + linphone_proxy_config_set_quality_reporting_collector((LinphoneProxyConfig *)ptr, collector); + env->ReleaseStringUTFChars(jcollector,collector); + } +} + +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getQualityReportingCollector(JNIEnv *env, jobject thiz, jlong ptr) { + jstring jvalue = env->NewStringUTF(linphone_proxy_config_get_quality_reporting_collector((LinphoneProxyConfig *)ptr)); + return jvalue; +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setRealm(JNIEnv *env, jobject thiz, jlong ptr, jstring jrealm) { + if (jrealm){ + const char *realm=env->GetStringUTFChars(jrealm, NULL); + linphone_proxy_config_set_realm((LinphoneProxyConfig *)ptr, realm); + env->ReleaseStringUTFChars(jrealm,realm); + } +} + +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getRealm(JNIEnv *env, jobject thiz, jlong ptr) { + jstring jvalue = env->NewStringUTF(linphone_proxy_config_get_realm((LinphoneProxyConfig *)ptr)); + return jvalue; +} + +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_isPhoneNumber(JNIEnv *env, jobject thiz, jlong ptr, jstring jusername) { + if(jusername){ + const char *username=env->GetStringUTFChars(jusername, NULL); + bool_t res = linphone_proxy_config_is_phone_number((LinphoneProxyConfig *)ptr, username); + env->ReleaseStringUTFChars(jusername,username); + return (jboolean) res; + } else { + return JNI_FALSE; + } } extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { return (jint)linphone_call_get_duration((LinphoneCall *) ptr); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setSipDscp(JNIEnv* env,jobject thiz,jlong ptr, jint dscp){ + linphone_core_set_sip_dscp((LinphoneCore*)ptr,dscp); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getSipDscp(JNIEnv* env,jobject thiz,jlong ptr){ + return linphone_core_get_sip_dscp((LinphoneCore*)ptr); +} + extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getSignalingTransportPort(JNIEnv* env,jobject thiz,jlong ptr, jint code) { LCSipTransports tr; linphone_core_get_sip_transports((LinphoneCore *) ptr, &tr); @@ -2030,12 +3924,16 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setSignalingTransportPor } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableIpv6(JNIEnv* env,jobject thiz - ,jlong lc, jboolean enable) { - linphone_core_enable_ipv6((LinphoneCore*)lc,enable); + ,jlong lc, jboolean enable) { + 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) { + ,jlong ptr, jint db) { linphone_core_set_playback_gain_db((LinphoneCore *) ptr, db); } @@ -2095,9 +3993,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateAllCalls(JNIEnv linphone_core_terminate_all_calls((LinphoneCore *) pCore); } extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getCall(JNIEnv *env,jobject thiz,jlong pCore,jint position) { - LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)pCore); LinphoneCall* lCall = (LinphoneCall*) ms_list_nth_data(linphone_core_get_calls((LinphoneCore *) pCore),position); - return lcd->getCall(env,lCall); + return getCall(env,lCall); } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getCallsNb(JNIEnv *env,jobject thiz,jlong pCore) { return (jint)ms_list_size(linphone_core_get_calls((LinphoneCore *) pCore)); @@ -2113,6 +4010,10 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_transferCallToAnother(JN return (jint)linphone_core_transfer_call_to_another((LinphoneCore *) pCore, (LinphoneCall *) pCall, (LinphoneCall *) pDestCall); } +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_startReferedCall(JNIEnv *env, jobject thiz, jlong lc, jlong callptr, jlong params){ + return getCall(env,linphone_core_start_refered_call((LinphoneCore *)lc, (LinphoneCall *)callptr, (const LinphoneCallParams *)params)); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIEnv *env,jobject thiz,jlong pCore, jstring jFile) { if (jFile) { const char* cFile=env->GetStringUTFChars(jFile, NULL); @@ -2125,10 +4026,9 @@ 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= (LinphoneCall *) 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) getCall(env,(LinphoneCall*)call); } @@ -2173,6 +4073,26 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getVideoDevice(JNIEnv *e return 0; } +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_listSupportedVideoResolutions(JNIEnv *env, jobject thiz, jlong lc) { + const MSVideoSizeDef *pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc); + int count = 0; + int i = 0; + for (; pdef->name!=NULL; pdef++) { + i++; + } + count = i; + + jobjectArray resolutions = (jobjectArray) env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF("")); + pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc); + i = 0; + for (; pdef->name!=NULL; pdef++) { + env->SetObjectArrayElement(resolutions, i, env->NewStringUTF(pdef->name)); + i++; + } + + return resolutions; +} + extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getAuthenticationToken(JNIEnv* env,jobject thiz,jlong ptr) { LinphoneCall *call = (LinphoneCall *) ptr; const char* token = linphone_call_get_authentication_token(call); @@ -2232,6 +4152,62 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelAddServerAndMirror env->ReleaseStringUTFChars(jHost, cHost); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelAddServer(JNIEnv *env, jobject thiz, jlong pCore, jobject config) { + LinphoneTunnel *tunnel = linphone_core_get_tunnel((LinphoneCore *)pCore); + if(tunnel != NULL) { + jclass TunnelConfigClass = env->FindClass("org/linphone/core/TunnelConfig"); + jmethodID getHostMethod = env->GetMethodID(TunnelConfigClass, "getHost", "()Ljava/lang/String;"); + jmethodID getPortMethod = env->GetMethodID(TunnelConfigClass, "getPort", "()I"); + jmethodID getRemoteUdpMirrorPortMethod = env->GetMethodID(TunnelConfigClass, "getRemoteUdpMirrorPort", "()I"); + jmethodID getDelayMethod = env->GetMethodID(TunnelConfigClass, "getDelay", "()I"); + jstring hostString = (jstring)env->CallObjectMethod(config, getHostMethod); + const char *host = env->GetStringUTFChars(hostString, NULL); + if(host == NULL || strlen(host)==0) { + ms_error("LinphoneCore.tunnelAddServer(): no tunnel host defined"); + } + LinphoneTunnelConfig *tunnelConfig = linphone_tunnel_config_new(); + linphone_tunnel_config_set_host(tunnelConfig, host); + linphone_tunnel_config_set_port(tunnelConfig, env->CallIntMethod(config, getPortMethod)); + linphone_tunnel_config_set_remote_udp_mirror_port(tunnelConfig, env->CallIntMethod(config, getRemoteUdpMirrorPortMethod)); + linphone_tunnel_config_set_delay(tunnelConfig, env->CallIntMethod(config, getDelayMethod)); + linphone_tunnel_add_server(tunnel, tunnelConfig); + env->ReleaseStringUTFChars(hostString, host); + env->DeleteLocalRef(TunnelConfigClass); + } else { + ms_error("LinphoneCore.tunnelAddServer(): tunnel feature is not enabled"); + } +} + +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_tunnelGetServers(JNIEnv *env, jobject thiz, jlong pCore) { + LinphoneTunnel *tunnel = linphone_core_get_tunnel((LinphoneCore *)pCore); + jclass TunnelConfigClass = env->FindClass("org/linphone/core/TunnelConfig"); + jmethodID setHostMethod = env->GetMethodID(TunnelConfigClass, "setHost", "(Ljava/lang/String;)V"); + jmethodID setPortMethod = env->GetMethodID(TunnelConfigClass, "setPort", "(I)V"); + jmethodID setRemoteUdpMirrorPortMethod = env->GetMethodID(TunnelConfigClass, "setRemoteUdpMirrorPort", "(I)V"); + jmethodID setDelayMethod = env->GetMethodID(TunnelConfigClass, "setDelay", "(I)V"); + jobjectArray tunnelConfigArray = NULL; + + if(tunnel != NULL) { + const MSList *servers = linphone_tunnel_get_servers(tunnel); + const MSList *it; + int i; + ms_message("servers=%p", (void *)servers); + ms_message("taille=%i", ms_list_size(servers)); + tunnelConfigArray = env->NewObjectArray(ms_list_size(servers), TunnelConfigClass, NULL); + for(it = servers, i=0; it != NULL; it = it->next, i++) { + const LinphoneTunnelConfig *conf = (const LinphoneTunnelConfig *)it->data; + jobject elt = env->AllocObject(TunnelConfigClass); + env->CallVoidMethod(elt, setHostMethod, env->NewStringUTF(linphone_tunnel_config_get_host(conf))); + env->CallVoidMethod(elt, setPortMethod, linphone_tunnel_config_get_port(conf)); + env->CallVoidMethod(elt, setRemoteUdpMirrorPortMethod, linphone_tunnel_config_get_remote_udp_mirror_port(conf)); + env->CallVoidMethod(elt, setDelayMethod, linphone_tunnel_config_get_delay(conf)); + env->SetObjectArrayElement(tunnelConfigArray, i, elt); + env->DeleteLocalRef(TunnelConfigClass); + } + } + return tunnelConfigArray; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelSetHttpProxy(JNIEnv *env,jobject thiz,jlong pCore, jstring jHost, jint port, jstring username, jstring password) { @@ -2262,6 +4238,37 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelEnable(JNIEnv *env linphone_tunnel_enable(tunnel, enable); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelSetMode(JNIEnv *env, jobject thiz, jlong pCore, jint mode) { + LinphoneTunnel *tunnel = ((LinphoneCore *)pCore)->tunnel; + if(tunnel != NULL) { + linphone_tunnel_set_mode(tunnel, (LinphoneTunnelMode)mode); + } +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_tunnelGetMode(JNIEnv *env, jobject thiz, jlong pCore) { + LinphoneTunnel *tunnel = ((LinphoneCore *)pCore)->tunnel; + if(tunnel != NULL) { + return (jint)linphone_tunnel_get_mode(tunnel); + } else { + return 0; + } +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_tunnelEnableSip(JNIEnv *env, jobject thiz, jlong pCore, jboolean enable) { + LinphoneTunnel *tunnel = ((LinphoneCore *)pCore)->tunnel; + if(tunnel != NULL) { + linphone_tunnel_enable_sip(tunnel, (bool_t)enable); + } +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_tunnelSipEnabled(JNIEnv *env, jobject thiz, jlong pCore) { + LinphoneTunnel *tunnel = ((LinphoneCore *)pCore)->tunnel; + if(tunnel != NULL) { + return (jboolean)linphone_tunnel_sip_enabled(tunnel); + } else { + return JNI_FALSE; + } +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUserAgent(JNIEnv *env,jobject thiz,jlong pCore, jstring name, jstring version){ const char* cname=env->GetStringUTFChars(name, NULL); @@ -2282,6 +4289,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); @@ -2292,6 +4309,14 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setCpuCountNative(JNIEnv ms_set_cpu_count(count); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioJittcomp(JNIEnv *env, jobject thiz, jlong lc, jint value) { + linphone_core_set_audio_jittcomp((LinphoneCore *)lc, value); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoJittcomp(JNIEnv *env, jobject thiz, jlong lc, jint value) { + linphone_core_set_video_jittcomp((LinphoneCore *)lc, value); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioPort(JNIEnv *env, jobject thiz, jlong lc, jint port) { linphone_core_set_audio_port((LinphoneCore *)lc, port); } @@ -2308,6 +4333,70 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoPortRange(JNIEnv linphone_core_set_video_port_range((LinphoneCore *)lc, min_port, max_port); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioDscp(JNIEnv* env,jobject thiz,jlong ptr, jint dscp){ + linphone_core_set_audio_dscp((LinphoneCore*)ptr,dscp); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidPowerManager(JNIEnv *env, jclass cls, jobject pm) { +#ifdef ANDROID + if(pm != NULL) bellesip_wake_lock_init(env, pm); + else bellesip_wake_lock_uninit(env); +#endif +} + +/*released in Java_org_linphone_core_LinphoneCoreImpl_delete*/ +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidWifiLock(JNIEnv *env, jobject thiz, jlong ptr, jobject wifi_lock) { +#ifdef ANDROID + LinphoneCore *lc=(LinphoneCore*)ptr; + if (lc->wifi_lock) { + env->DeleteGlobalRef(lc->wifi_lock); + env->DeleteGlobalRef(lc->wifi_lock_class); + } + if (wifi_lock != NULL) { + lc->wifi_lock=env->NewGlobalRef(wifi_lock); + lc->wifi_lock_class = env->FindClass("android/net/wifi/WifiManager$WifiLock"); + lc->wifi_lock_class = (jclass)env->NewGlobalRef(lc->wifi_lock_class); /*to make sure methodid are preserved*/ + lc->wifi_lock_acquire_id = env->GetMethodID(lc->wifi_lock_class, "acquire", "()V"); + lc->wifi_lock_release_id = env->GetMethodID(lc->wifi_lock_class, "release", "()V"); + } else { + lc->wifi_lock=NULL; + lc->wifi_lock_class=NULL; + } +#endif +} +/*released in Java_org_linphone_core_LinphoneCoreImpl_delete*/ +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidMulticastLock(JNIEnv *env, jobject thiz, jlong ptr, jobject multicast_lock) { +#ifdef ANDROID + LinphoneCore *lc=(LinphoneCore*)ptr; + if (lc->multicast_lock) { + env->DeleteGlobalRef(lc->multicast_lock); + env->DeleteGlobalRef(lc->multicast_lock_class); + } + if (multicast_lock != NULL) { + lc->multicast_lock=env->NewGlobalRef(multicast_lock); + lc->multicast_lock_class = env->FindClass("android/net/wifi/WifiManager$MulticastLock"); + lc->multicast_lock_class = (jclass)env->NewGlobalRef(lc->multicast_lock_class);/*to make sure methodid are preserved*/ + lc->multicast_lock_acquire_id = env->GetMethodID(lc->multicast_lock_class, "acquire", "()V"); + lc->multicast_lock_release_id = env->GetMethodID(lc->multicast_lock_class, "release", "()V"); + } else { + lc->multicast_lock=NULL; + lc->multicast_lock_class=NULL; + } +#endif +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getAudioDscp(JNIEnv* env,jobject thiz,jlong ptr){ + return linphone_core_get_audio_dscp((LinphoneCore*)ptr); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoDscp(JNIEnv* env,jobject thiz,jlong ptr, jint dscp){ + linphone_core_set_video_dscp((LinphoneCore*)ptr,dscp); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getVideoDscp(JNIEnv* env,jobject thiz,jlong ptr){ + return linphone_core_get_video_dscp((LinphoneCore*)ptr); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setIncomingTimeout(JNIEnv *env, jobject thiz, jlong lc, jint timeout) { linphone_core_set_inc_timeout((LinphoneCore *)lc, timeout); } @@ -2326,7 +4415,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getConfig(JNIEnv *env, } extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_upnpAvailable(JNIEnv *env, jobject thiz, jlong lc) { - return (jboolean) linphone_core_upnp_available((LinphoneCore *)lc); + return (jboolean) linphone_core_upnp_available(); } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getUpnpState(JNIEnv *env, jobject thiz, jlong lc) { @@ -2338,9 +4427,81 @@ 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; + LinphoneContentPrivate content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + ev=linphone_core_subscribe(lc,addr,evname,expires,content.type ? LINPHONE_CONTENT(&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=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; + LinphoneContentPrivate content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + ev=linphone_core_publish(lc,addr,evname,expires,content.type ? LINPHONE_CONTENT(&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=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); + const char *cfile = env->GetStringUTFChars(file, NULL); + LpConfig *lp = lp_config_new(cfile); env->ReleaseStringUTFChars(file, cfile); return (jlong) lp; } @@ -2357,10 +4518,1669 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_delete(JNIEnv *env, jobject extern "C" void Java_org_linphone_core_LpConfigImpl_setInt(JNIEnv *env, jobject thiz, jlong lpc, jstring section, jstring key, jint value) { - const char *csection = env->GetStringUTFChars(section, NULL); - const char *ckey = env->GetStringUTFChars(key, NULL); - lp_config_set_int((LpConfig *)lpc, csection, ckey, (int) value); - env->ReleaseStringUTFChars(section, csection); - env->ReleaseStringUTFChars(key, ckey); + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_int((LpConfig *)lpc, csection, ckey, (int) value); + env->ReleaseStringUTFChars(section, csection); + 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 = value ? env->GetStringUTFChars(value, NULL) : NULL; + lp_config_set_string((LpConfig *)lpc, csection, ckey, cvalue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + if (value) 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 *icontent){ + jclass contentClass; + jmethodID ctor; + jstring jtype, jsubtype, jencoding, jname; + jbyteArray jdata = NULL; + jint jsize = 0; + const LinphoneContentPrivate *content = LINPHONE_CONTENT_PRIVATE(icontent); + + contentClass = (jclass)env->FindClass("org/linphone/core/LinphoneContentImpl"); + ctor = env->GetMethodID(contentClass,"", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;I)V"); + + jtype = env->NewStringUTF(content->type); + jsubtype = env->NewStringUTF(content->subtype); + jencoding = content->encoding ? env->NewStringUTF(content->encoding) : NULL; + jname = content->name ? env->NewStringUTF(content->name) : NULL; + jsize = (jint) content->size; + + if (content->data){ + jdata = env->NewByteArray(content->size); + env->SetByteArrayRegion(jdata, 0, content->size, (jbyte*)content->data); + } + + jobject jobj = env->NewObject(contentClass, ctor, jname, jtype, jsubtype, jdata, jencoding, jsize); + + env->DeleteLocalRef(contentClass); + env->DeleteLocalRef(jtype); + env->DeleteLocalRef(jsubtype); + if (jencoding) { + env->DeleteLocalRef(jencoding); + } + if (jname) { + env->DeleteLocalRef(jname); + } + + return jobj; +} + +static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *buffer) { + jclass bufferClass; + jmethodID ctor; + jbyteArray jdata = NULL; + jint jsize = 0; + + bufferClass = (jclass)env->FindClass("org/linphone/core/LinphoneBufferImpl"); + ctor = env->GetMethodID(bufferClass,"", "([BI)V"); + jsize = buffer ? (jint) buffer->size : 0; + + if (buffer && buffer->content) { + jdata = env->NewByteArray(buffer->size); + env->SetByteArrayRegion(jdata, 0, buffer->size, (jbyte*)buffer->content); + } + + jobject jobj = env->NewObject(bufferClass, ctor, jdata, jsize); + env->DeleteLocalRef(bufferClass); + return jobj; +} + +static LinphoneBuffer* create_c_linphone_buffer_from_java_linphone_buffer(JNIEnv *env, jobject jbuffer) { + jclass bufferClass; + jmethodID getSizeMethod, getDataMethod; + LinphoneBuffer *buffer = NULL; + jint jsize; + jobject jdata; + jbyteArray jcontent; + uint8_t *content; + + bufferClass = (jclass)env->FindClass("org/linphone/core/LinphoneBufferImpl"); + getSizeMethod = env->GetMethodID(bufferClass, "getSize", "()I"); + getDataMethod = env->GetMethodID(bufferClass, "getContent", "()[B"); + + jsize = env->CallIntMethod(jbuffer, getSizeMethod); + jdata = env->CallObjectMethod(jbuffer, getDataMethod); + jcontent = reinterpret_cast(jdata); + if (jcontent != NULL) { + content = (uint8_t*)env->GetByteArrayElements(jcontent, NULL); + buffer = linphone_buffer_new_from_data(content, (size_t)jsize); + env->ReleaseByteArrayElements(jcontent, (jbyte*)content, JNI_ABORT); + } + env->DeleteLocalRef(bufferClass); + + return buffer; +} + +/* + * 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){ + LinphoneContentPrivate 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,LINPHONE_CONTENT(&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=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); + } +} + +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneEventImpl_getCore(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneCore *lc=linphone_event_get_core((LinphoneEvent*)evptr); + jobject core = (jobject)linphone_core_get_user_data(lc); + return core; +} + +/* + * 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){ + LinphoneContentPrivate 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 ? LINPHONE_CONTENT(&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){ + LinphoneContentPrivate 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 ? LINPHONE_CONTENT(&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){ + LinphoneContentPrivate 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 ? LINPHONE_CONTENT(&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); +} + +JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneEventImpl_getErrorInfo(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return (jlong)linphone_event_get_error_info(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getSubscriptionDir + * 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); +} + +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createSubscribe(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) { + LinphoneCore *lc = (LinphoneCore*) jcore; + LinphoneAddress *addr = (LinphoneAddress*) jaddr; + LinphoneEvent *event; + jobject jevent = NULL; + const char *event_name = env->GetStringUTFChars(jeventname, NULL); + + event = linphone_core_create_subscribe(lc, addr, event_name, expires); + env->ReleaseStringUTFChars(jeventname, event_name); + if (event) { + jevent = getEvent(env, event); + } + return jevent; +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendSubscribe(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) { + LinphoneContentPrivate content = {0}; + if (jtype) { + content.type = (char*) env->GetStringUTFChars(jtype, NULL); + content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL); + content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL; + content.data = (void*) env->GetByteArrayElements(jdata, NULL); + content.size = env->GetArrayLength(jdata); + } + linphone_event_send_subscribe((LinphoneEvent*) jevent, content.type ? LINPHONE_CONTENT(&content) : NULL); + if (jtype) { + env->ReleaseStringUTFChars(jtype, content.type); + env->ReleaseStringUTFChars(jsubtype, content.subtype); + if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding); + env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT); + } +} + +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createPublish(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) { + LinphoneCore *lc = (LinphoneCore*) jcore; + LinphoneAddress *addr = (LinphoneAddress*) jaddr; + LinphoneEvent *event; + jobject jevent = NULL; + const char *event_name = env->GetStringUTFChars(jeventname, NULL); + + event = linphone_core_create_publish(lc, addr, event_name, expires); + env->ReleaseStringUTFChars(jeventname, event_name); + if (event) { + jevent = getEvent(env, event); + } + return jevent; +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendPublish(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) { + LinphoneContentPrivate content = {0}; + if (jtype) { + content.type = (char*) env->GetStringUTFChars(jtype, NULL); + content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL); + content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL; + content.data = (void*) env->GetByteArrayElements(jdata, NULL); + content.size = env->GetArrayLength(jdata); + } + linphone_event_send_publish((LinphoneEvent*) jevent, content.type ? LINPHONE_CONTENT(&content) : NULL); + if (jtype) { + env->ReleaseStringUTFChars(jtype, content.type); + env->ReleaseStringUTFChars(jsubtype, content.subtype); + if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding); + env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT); + } +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname, jstring jvalue) { + const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL; + const char *value = jvalue ? env->GetStringUTFChars(jvalue, NULL) : NULL; + linphone_event_add_custom_header((LinphoneEvent*) jevent, name, value); + if (jname) env->ReleaseStringUTFChars(jname, name); + if (jvalue) env->ReleaseStringUTFChars(jvalue, value); +} + +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneEventImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname) { + const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL; + const char *header = linphone_event_get_custom_header((LinphoneEvent*) jevent, name); + jstring jheader = header ? env->NewStringUTF(header) : NULL; + if (jname) env->ReleaseStringUTFChars(jname, name); + return jheader; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: unref + * 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) { + LinphonePresenceModel *model = linphone_presence_model_new(); + model = linphone_presence_model_ref(model); + return (jlong)model; +} + +/* + * 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); + model = linphone_presence_model_ref(model); + 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); + model = linphone_presence_model_ref(model); + 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); + activity = linphone_presence_activity_ref(activity); + 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); + return (jint)0; +} + +/* + * 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); + service = linphone_presence_service_ref(service); + 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); + return (jint)0; +} + +/* + * 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); + return (jint)0; +} + +/* + * 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); + person = linphone_presence_person_ref(person); + 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); + return (jint)0; +} + +/* + * 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); + note = linphone_presence_note_ref(note); + 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); + return (jint)0; +} + +/* + * 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); + return (jint)0; +} + +/* + * 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; +} + + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableSdp200Ack(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jboolean enable) { + linphone_core_enable_sdp_200_ack((LinphoneCore*)lc,enable); +} + +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_isSdp200AckEnabled(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return (jboolean)linphone_core_sdp_200_ack_enabled((const LinphoneCore*)lc); +} + +/* Header for class org_linphone_core_ErrorInfoImpl */ +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getReason + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getReason(JNIEnv *env, jobject jobj, jlong ei){ + return linphone_error_info_get_reason((const LinphoneErrorInfo*)ei); +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getProtocolCode + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getProtocolCode(JNIEnv *env, jobject jobj, jlong ei){ + return linphone_error_info_get_protocol_code((const LinphoneErrorInfo*)ei); +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getPhrase + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getPhrase(JNIEnv *env, jobject jobj, jlong ei){ + const char *tmp=linphone_error_info_get_phrase((const LinphoneErrorInfo*)ei); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getDetails + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv *env, jobject jobj, jlong ei){ + const char *tmp=linphone_error_info_get_details((const LinphoneErrorInfo*)ei); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +#ifdef __cplusplus +} +#endif + +/* Linphone Player */ +struct LinphonePlayerData { + LinphonePlayerData(JNIEnv *env, jobject listener, jobject jLinphonePlayer) : + mListener(env->NewGlobalRef(listener)), + mJLinphonePlayer(env->NewGlobalRef(jLinphonePlayer)) + { + mListenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass(listener)); + mEndOfFileMethodID = env->GetMethodID(mListenerClass, "endOfFile", "(Lorg/linphone/core/LinphonePlayer;)V"); + if(mEndOfFileMethodID == NULL) { + ms_error("Could not get endOfFile method ID"); + env->ExceptionClear(); + } + } + + ~LinphonePlayerData() { + JNIEnv *env; + jvm->AttachCurrentThread(&env, NULL); + env->DeleteGlobalRef(mListener); + env->DeleteGlobalRef(mListenerClass); + env->DeleteGlobalRef(mJLinphonePlayer); + } + + jobject mListener; + jclass mListenerClass; + jobject mJLinphonePlayer; + jmethodID mEndOfFileMethodID; +}; + +static void _eof_callback(LinphonePlayer *player, void *user_data) { + JNIEnv *env; + LinphonePlayerData *player_data = (LinphonePlayerData *)user_data; + jvm->AttachCurrentThread(&env, NULL); + env->CallVoidMethod(player_data->mListener, player_data->mEndOfFileMethodID, player_data->mJLinphonePlayer); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_open(JNIEnv *env, jobject jPlayer, jlong ptr, jstring filename, jobject listener) { + LinphonePlayerData *data = NULL; + LinphonePlayerEofCallback cb = NULL; + if(listener) { + data = new LinphonePlayerData(env, listener, jPlayer); + cb = _eof_callback; + } + if(linphone_player_open((LinphonePlayer *)ptr, env->GetStringUTFChars(filename, NULL), cb, data) == -1) { + if(data) delete data; + return -1; + } + return 0; +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_start(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_start((LinphonePlayer *)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_pause(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_pause((LinphonePlayer *)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_seek(JNIEnv *env, jobject jobj, jlong ptr, jint timeMs) { + return (jint)linphone_player_seek((LinphonePlayer *)ptr, timeMs); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getState(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_get_state((LinphonePlayer *)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getDuration(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_get_duration((LinphonePlayer *)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getCurrentPosition(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_get_current_position((LinphonePlayer *)ptr); +} + +extern "C" void Java_org_linphone_core_LinphonePlayerImpl_close(JNIEnv *env, jobject playerPtr, jlong ptr) { + LinphonePlayer *player = (LinphonePlayer *)ptr; + if(player->user_data) { + LinphonePlayerData *data = (LinphonePlayerData *)player->user_data; + if(data) delete data; + player->user_data = NULL; + } + linphone_player_close(player); +} + +extern "C" void Java_org_linphone_core_LinphonePlayerImpl_destroy(JNIEnv *env, jobject jobj, jlong playerPtr) { + LinphonePlayer *player = (LinphonePlayer *)playerPtr; + if(player == NULL) { + ms_error("Cannot destroy the LinphonePlayerImpl object. Native pointer is NULL"); + return; + } + if(player->user_data) { + delete (LinphonePlayerData *)player->user_data; + } + jobject window_id = (jobject)ms_media_player_get_window_id((MSMediaPlayer *)player->impl); + if(window_id) env->DeleteGlobalRef(window_id); + linphone_player_destroy(player); +} + +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createLocalPlayer(JNIEnv *env, jobject jobj, jlong ptr, jobject window) { + jobject window_ref = NULL; + window_ref = env->NewGlobalRef(window); + LinphonePlayer *player = linphone_core_create_local_player((LinphoneCore *)ptr, NULL, "MSAndroidDisplay", (void *)window_ref); + if(player == NULL) { + ms_error("Fails to create a player"); + if(window_ref) env->DeleteGlobalRef(window_ref); + return 0; + } else { + return (jlong)player; + } +} + + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: setAudioMulticastAddr + * Signature: (JLjava/lang/String;)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setAudioMulticastAddr + (JNIEnv * env , jobject, jlong ptr, jstring value) { + const char *char_value = value ? env->GetStringUTFChars(value, NULL) : NULL; + LinphoneCore *lc=(LinphoneCore*)ptr; + int result = linphone_core_set_audio_multicast_addr(lc,char_value); + if (char_value) env->ReleaseStringUTFChars(value, char_value); + return result; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: setVideoMulticastAddr + * Signature: (JLjava/lang/String;)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoMulticastAddr + (JNIEnv * env, jobject, jlong ptr, jstring value) { + const char *char_value = value ? env->GetStringUTFChars(value, NULL) : NULL; + LinphoneCore *lc=(LinphoneCore*)ptr; + int result = linphone_core_set_video_multicast_addr(lc,char_value); + if (char_value) env->ReleaseStringUTFChars(value, char_value); + return result; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: getAudioMulticastAddr + * Signature: (J)Ljava/lang/String; + */ +extern "C" jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastAddr + (JNIEnv *env , jobject, jlong ptr) { + const char *tmp=linphone_core_get_audio_multicast_addr((LinphoneCore*)ptr); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: getVideoMulticastAddr + * Signature: (J)Ljava/lang/String; + */ +extern "C" jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastAddr + (JNIEnv * env, jobject, jlong ptr) { + const char *tmp=linphone_core_get_video_multicast_addr((LinphoneCore*)ptr); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: setAudioMulticastTtl + * Signature: (JI)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setAudioMulticastTtl + (JNIEnv *, jobject, jlong ptr, jint value) { + return linphone_core_set_audio_multicast_ttl((LinphoneCore*)ptr,value); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: setVideoMulticastTtl + * Signature: (JI)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoMulticastTtl + (JNIEnv *, jobject, jlong ptr, jint value) { + return linphone_core_set_video_multicast_ttl((LinphoneCore*)ptr,value); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: getAudioMulticastTtl + * Signature: (J)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastTtl + (JNIEnv *, jobject, jlong ptr) { + return linphone_core_get_audio_multicast_ttl((LinphoneCore*)ptr); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: getVideoMulticastTtl + * Signature: (J)I + */ +extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastTtl + (JNIEnv *, jobject, jlong ptr) { + return linphone_core_get_video_multicast_ttl((LinphoneCore*)ptr); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: enableAudioMulticast + * Signature: (JZ)V + */ +extern "C" void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableAudioMulticast + (JNIEnv *, jobject, jlong ptr, jboolean yesno) { + return linphone_core_enable_audio_multicast((LinphoneCore*)ptr,yesno); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: audioMulticastEnabled + * Signature: (J)Z + */ +extern "C" jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_audioMulticastEnabled + (JNIEnv *, jobject, jlong ptr) { + return linphone_core_audio_multicast_enabled((LinphoneCore*)ptr); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: enableVideoMulticast + * Signature: (JZ)V + */ +extern "C" void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableVideoMulticast + (JNIEnv *, jobject, jlong ptr, jboolean yesno) { + return linphone_core_enable_video_multicast((LinphoneCore*)ptr,yesno); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: videoMulticastEnabled + * Signature: (J)Z + */ +extern "C" jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_videoMulticastEnabled + (JNIEnv *, jobject, jlong ptr) { + return linphone_core_video_multicast_enabled((LinphoneCore*)ptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableDnsSrv(JNIEnv *env, jobject thiz, jlong lc, jboolean yesno) { + linphone_core_enable_dns_srv((LinphoneCore *)lc, yesno); +} + +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_dnsSrvEnabled(JNIEnv *env, jobject thiz, jlong lc) { + return linphone_core_dns_srv_enabled((LinphoneCore *)lc); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoPreset(JNIEnv *env, jobject thiz, jlong lc, jstring preset) { + const char *char_preset = preset ? env->GetStringUTFChars(preset, NULL) : NULL; + linphone_core_set_video_preset((LinphoneCore *)lc, char_preset); + if (char_preset) env->ReleaseStringUTFChars(preset, char_preset); +} + +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoPreset(JNIEnv *env, jobject thiz, jlong lc) { + const char *tmp = linphone_core_get_video_preset((LinphoneCore *)lc); + return tmp ? env->NewStringUTF(tmp) : NULL; +} diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index cc0a6f692..04069e504 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -64,12 +64,15 @@ typedef enum { typedef void (*LinphoneEcCalibrationCallback)(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data); +typedef void (*LinphoneEcCalibrationAudioInit)(void *data); +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, void *cb_data); +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 * Special function to warm up dtmf feeback stream. #linphone_core_stop_dtmf_stream must() be called before entering FG mode @@ -93,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 90491df5b..1a6535fed 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,40 +119,69 @@ typedef struct _LinphoneFriend LinphoneFriend; * Contructor * @return a new empty #LinphoneFriend */ -LinphoneFriend * linphone_friend_new(); +LINPHONE_PUBLIC LinphoneFriend * linphone_friend_new(void); + /** - * 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 */ -LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_addr(const char *addr); +LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_address(const char *addr); /** - * Destructor - * @param lf #LinphoneFriend object + * Contructor same as linphone_friend_new() + linphone_friend_set_address() + * @deprecated Use #linphone_friend_new_with_address instead */ -void linphone_friend_destroy(LinphoneFriend *lf); +#define linphone_friend_new_with_addr linphone_friend_new_with_address /** - * set #LinphoneAddress for this friend + * Destroy a LinphoneFriend. + * @param lf LinphoneFriend object + * @deprecated Use linphone_friend_unref() instead. + */ +LINPHONE_PUBLIC void linphone_friend_destroy(LinphoneFriend *lf); + +/** + * 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); /** - * get address of this friend + * Set #LinphoneAddress for this friend + * @deprecated Use #linphone_friend_set_address instead + */ +#define linphone_friend_set_addr linphone_friend_set_address + +/** + * Get address of this friend * @param lf #LinphoneFriend object * @return #LinphoneAddress */ 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 /** @@ -154,108 +191,226 @@ bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf); */ 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. **/ LINPHONE_PUBLIC void linphone_friend_edit(LinphoneFriend *fr); + /** * Commits modification made to the friend configuration. * @param fr #LinphoneFriend object **/ 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. + * @return 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. + * @return 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 */ 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); -/** - * get Buddy list of LinphoneFriend - * @param lc #LinphoneCore object - * */ -LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); -/** - * 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); +LINPHONE_PUBLIC void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); +/** + * Get Buddy list of LinphoneFriend + * @param[in] lc #LinphoneCore object + * @return \mslist{LinphoneFriend} + */ +LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); + +/** + * Notify all friends that have subscribed + * @param lc #LinphoneCore object + * @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. + * @return 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. + * @return 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. + * @return 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); + +/** + * Acquire a reference to the linphone friend. + * @param[in] lf LinphoneFriend object + * @return The same LinphoneFriend object +**/ +LINPHONE_PUBLIC LinphoneFriend * linphone_friend_ref(LinphoneFriend *lf); + +/** + * Release a reference to the linphone friend. + * @param[in] lf LinohoneFriend object +**/ +LINPHONE_PUBLIC void linphone_friend_unref(LinphoneFriend *lf); + +/** + * Returns the LinphoneCore object managing this friend, if any. + */ +LINPHONE_PUBLIC LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr); /** * @} */ diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h new file mode 100644 index 000000000..c0168cb8b --- /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. + * @return 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. + * @return 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. + * @return 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. + * @return 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 basic_status, 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. + * @return 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. + * @return 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. + * @return 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. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); + +/** + * Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0. + * @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased. + * @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); + +/** + * Sets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +LINPHONE_PUBLIC void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to get the user data. + * @return A pointer to the user data. + */ +LINPHONE_PUBLIC void * linphone_presence_model_get_user_data(const 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. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service); + +/** + * Decrease the reference count of the #LinphonePresenceService object and destroy it if it reaches 0. + * @param[in] service The #LinphonePresenceService object for which the reference count is to be decreased. + * @return The #LinphonePresenceService object if the reference count is still positive, NULL if the object has been destroyed. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service); + +/** + * Sets the user data of a #LinphonePresenceService object. + * @param[in] service The #LinphonePresenceService object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +LINPHONE_PUBLIC void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceService object. + * @param[in] service The #LinphonePresenceService object for which to get the user data. + * @return A pointer to the user data. + */ +LINPHONE_PUBLIC void * linphone_presence_service_get_user_data(const 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. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person); + +/** + * Decrease the reference count of the #LinphonePresencePerson object and destroy it if it reaches 0. + * @param[in] person The #LinphonePresencePerson object for which the reference count is to be decreased. + * @return The #LinphonePresencePerson object if the reference count is still positive, NULL if the object has been destroyed. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person); + +/** + * Sets the user data of a #LinphonePresencePerson object. + * @param[in] person The #LinphonePresencePerson object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +LINPHONE_PUBLIC void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data); + +/** + * Gets the user data of a #LinphonePresencePerson object. + * @param[in] person The #LinphonePresencePerson object for which to get the user data. + * @return A pointer to the user data. + */ +LINPHONE_PUBLIC void * linphone_presence_person_get_user_data(const 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. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity); + +/** + * Decrease the reference count of the #LinphonePresenceActivity object and destroy it if it reaches 0. + * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be decreased. + * @return The #LinphonePresenceActivity object if the reference count is still positive, NULL if the object has been destroyed. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity); + +/** + * Sets the user data of a #LinphonePresenceActivity object. + * @param[in] activity The #LinphonePresenceActivity object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +LINPHONE_PUBLIC void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceActivity object. + * @param[in] activity The #LinphonePresenceActivity object for which to get the user data. + * @return A pointer to the user data. + */ +LINPHONE_PUBLIC void * linphone_presence_activity_get_user_data(const 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. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note); + +/** + * Decrease the reference count of the #LinphonePresenceNote object and destroy it if it reaches 0. + * @param[in] note The #LinphonePresenceNote object for which the reference count is to be decreased. + * @return The #LinphonePresenceNote object if the reference count is still positive, NULL if the object has been destroyed. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note); + +/** + * Sets the user data of a #LinphonePresenceNote object. + * @param[in] note The #LinphonePresenceNote object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +LINPHONE_PUBLIC void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceNote object. + * @param[in] note The #LinphonePresenceNote object for which to get the user data. + * @return A pointer to the user data. + */ +LINPHONE_PUBLIC void * linphone_presence_note_get_user_data(const 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. + * @return 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. + * @return 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. + * @return 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. + * @return 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. + * @return 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. + * @return 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. + * @return 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/localplayer.c b/coreapi/localplayer.c new file mode 100644 index 000000000..eb53eb640 --- /dev/null +++ b/coreapi/localplayer.c @@ -0,0 +1,98 @@ +/* +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 +#include + +static int _local_player_open(LinphonePlayer *obj, const char *filename); +static int _local_player_start(LinphonePlayer *obj); +static int _local_player_pause(LinphonePlayer *obj); +static int _local_player_seek(LinphonePlayer *obj, int time_ms); +static MSPlayerState _local_player_get_state(LinphonePlayer *obj); +static int _local_player_get_duration(LinphonePlayer *obj); +static int _local_player_get_current_position(LinphonePlayer *obj); +static void _local_player_close(LinphonePlayer *obj); +static void _local_player_destroy(LinphonePlayer *obj); +static void _local_player_eof_callback(void *user_data); + +LinphonePlayer *linphone_core_create_local_player(LinphoneCore *lc, MSSndCard *snd_card, const char *video_out, void *window_id) { + LinphonePlayer *obj = ms_new0(LinphonePlayer, 1); + if(snd_card == NULL) snd_card = lc->sound_conf.ring_sndcard; + if(video_out == NULL) video_out = linphone_core_get_video_display_filter(lc); + obj->impl = ms_media_player_new(snd_card, video_out, window_id); + obj->open = _local_player_open; + obj->start = _local_player_start; + obj->pause = _local_player_pause; + obj->seek = _local_player_seek; + obj->get_state = _local_player_get_state; + obj->get_duration = _local_player_get_duration; + obj->get_position = _local_player_get_current_position; + obj->close = _local_player_close; + obj->destroy = _local_player_destroy; + ms_media_player_set_eof_callback((MSMediaPlayer *)obj->impl, _local_player_eof_callback, obj); + return obj; +} + +bool_t linphone_local_player_matroska_supported(void) { + return ms_media_player_matroska_supported(); +} + +static int _local_player_open(LinphonePlayer *obj, const char *filename) { + return ms_media_player_open((MSMediaPlayer *)obj->impl, filename) ? 0 : -1; +} + +static int _local_player_start(LinphonePlayer *obj) { + return ms_media_player_start((MSMediaPlayer *)obj->impl) ? 0 : -1; +} + +static int _local_player_pause(LinphonePlayer *obj) { + ms_media_player_pause((MSMediaPlayer *)obj->impl); + return 0; +} + +static int _local_player_seek(LinphonePlayer *obj, int time_ms) { + return ms_media_player_seek((MSMediaPlayer *)obj->impl, time_ms) ? 0 : -1; +} + +static MSPlayerState _local_player_get_state(LinphonePlayer *obj) { + return ms_media_player_get_state((MSMediaPlayer *)obj->impl); +} + +static int _local_player_get_duration(LinphonePlayer *obj) { + return ms_media_player_get_duration((MSMediaPlayer *)obj->impl); +} + +static int _local_player_get_current_position(LinphonePlayer *obj) { + return ms_media_player_get_current_position((MSMediaPlayer *)obj->impl); +} + +static void _local_player_destroy(LinphonePlayer *obj) { + ms_media_player_free((MSMediaPlayer *)obj->impl); + _linphone_player_destroy(obj); +} + +static void _local_player_close(LinphonePlayer *obj) { + ms_media_player_close((MSMediaPlayer *)obj->impl); +} + +static void _local_player_eof_callback(void *user_data) { + LinphonePlayer *obj = (LinphonePlayer *)user_data; + obj->cb(obj, obj->user_data); +} diff --git a/tools/lpc2xml.c b/coreapi/lpc2xml.c similarity index 84% rename from tools/lpc2xml.c rename to coreapi/lpc2xml.c index 39fd62b0e..1446a94cc 100644 --- a/tools/lpc2xml.c +++ b/coreapi/lpc2xml.c @@ -29,7 +29,7 @@ struct _lpc2xml_context { const LpConfig *lpc; lpc2xml_function cbf; void *ctx; - + xmlDoc *doc; char errorBuffer[LPC2XML_BZ]; char warningBuffer[LPC2XML_BZ]; @@ -42,7 +42,7 @@ lpc2xml_context* lpc2xml_context_new(lpc2xml_function cbf, void *ctx) { xmlCtx->lpc = NULL; xmlCtx->cbf = cbf; xmlCtx->ctx = ctx; - + xmlCtx->doc = NULL; xmlCtx->errorBuffer[0]='\0'; xmlCtx->warningBuffer[0]='\0'; @@ -64,8 +64,8 @@ static void lpc2xml_context_clear_logs(lpc2xml_context *ctx) { } static void lpc2xml_log(lpc2xml_context *xmlCtx, int level, const char *fmt, ...) { - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); if(xmlCtx->cbf != NULL) { xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args); } @@ -75,8 +75,8 @@ static void lpc2xml_log(lpc2xml_context *xmlCtx, int level, const char *fmt, ... static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) { lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; int sl = strlen(xmlCtx->errorBuffer); - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); vsnprintf(xmlCtx->errorBuffer + sl, LPC2XML_BZ-sl, fmt, args); va_end(args); } @@ -85,8 +85,8 @@ static void lpc2xml_genericxml_error(void *ctx, const char *fmt, ...) { static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) { lpc2xml_context *xmlCtx = (lpc2xml_context *)ctx; int sl = strlen(xmlCtx->warningBuffer); - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); vsnprintf(xmlCtx->warningBuffer + sl, LPC2XML_BZ-sl, fmt, args); va_end(args); } @@ -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,19 +113,28 @@ struct __processSectionCtx { static void processSection_cb(const char *entry, struct __processSectionCtx *ctx) { if(ctx->ret == 0) { - xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL); + const char *comment = "#"; + xmlNode *node; + xmlAttr *name_attr; + if (strncmp(comment, entry, strlen(comment)) == 0) { + lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry); + ctx->ret = 0; + return; + } + + node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL); if(node == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"entry\" element"); ctx->ret = -1; return; } - xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)entry); + name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)entry); if(name_attr == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"entry\" element"); ctx->ret = -1; return; } - + ctx->ret = processEntry(ctx->section, entry, node, ctx->ctx); } } @@ -147,12 +156,13 @@ struct __processConfigCtx { static void processConfig_cb(const char *section, struct __processConfigCtx *ctx) { if(ctx->ret == 0) { xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"section", NULL); + xmlAttr *name_attr; if(node == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element"); ctx->ret = -1; return; } - xmlAttr *name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)section); + name_attr = xmlSetProp(node, (const xmlChar *)"name", (const xmlChar *)section); if(name_attr == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create name attribute for \"section\" element"); ctx->ret = -1; @@ -170,22 +180,25 @@ static int processConfig(xmlNode *node, lpc2xml_context *ctx) { static int processDoc(xmlDoc *doc, lpc2xml_context *ctx) { int ret = 0; + xmlNs *xsi_ns; + xmlNs *lpc_ns; + xmlAttr *schemaLocation; xmlNode *root_node = xmlNewNode(NULL, (const xmlChar *)"config"); if(root_node == NULL) { lpc2xml_log(ctx, LPC2XML_ERROR, "Can't create \"config\" element"); return -1; } - xmlNs *lpc_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd", NULL); + lpc_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd", NULL); if(lpc_ns == NULL) { lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create lpc namespace"); } else { xmlSetNs(root_node, lpc_ns); } - xmlNs *xsi_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance", (const xmlChar *)"xsi"); + xsi_ns = xmlNewNs(root_node, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance", (const xmlChar *)"xsi"); if(lpc_ns == NULL) { lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create xsi namespace"); } - xmlAttr *schemaLocation = xmlNewNsProp(root_node, xsi_ns, (const xmlChar *)"schemaLocation", (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd lpconfig.xsd"); + schemaLocation = xmlNewNsProp(root_node, xsi_ns, (const xmlChar *)"schemaLocation", (const xmlChar *)"http://www.linphone.org/xsds/lpconfig.xsd lpconfig.xsd"); if(schemaLocation == NULL) { lpc2xml_log(ctx, LPC2XML_WARNING, "Can't create schemaLocation"); } @@ -196,12 +209,13 @@ static int processDoc(xmlDoc *doc, lpc2xml_context *ctx) { static int internal_convert_lpc2xml(lpc2xml_context *ctx) { int ret = 0; + xmlDoc *doc; lpc2xml_log(ctx, LPC2XML_DEBUG, "Generation started"); if(ctx->doc != NULL) { xmlFreeDoc(ctx->doc); ctx->doc = NULL; } - xmlDoc *doc = xmlNewDoc((const xmlChar *)"1.0"); + doc = xmlNewDoc((const xmlChar *)"1.0"); ret = processDoc(doc, ctx); if(ret == 0) { ctx->doc = doc; @@ -219,9 +233,10 @@ int lpc2xml_set_lpc(lpc2xml_context* context, const LpConfig *lpc) { int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) { int ret = -1; + xmlSaveCtxtPtr save_ctx; lpc2xml_context_clear_logs(context); xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); - xmlSaveCtxtPtr save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT); + save_ctx = xmlSaveToFilename(filename, "UTF-8", XML_SAVE_FORMAT); if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { @@ -241,9 +256,10 @@ int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) { int lpc2xml_convert_fd(lpc2xml_context* context, int fd) { int ret = -1; + xmlSaveCtxtPtr save_ctx; lpc2xml_context_clear_logs(context); xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); - xmlSaveCtxtPtr save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT); + save_ctx = xmlSaveToFd(fd, "UTF-8", XML_SAVE_FORMAT); if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { @@ -264,9 +280,10 @@ int lpc2xml_convert_fd(lpc2xml_context* context, int fd) { int lpc2xml_convert_string(lpc2xml_context* context, char **content) { int ret = -1; xmlBufferPtr buffer = xmlBufferCreate(); + xmlSaveCtxtPtr save_ctx; lpc2xml_context_clear_logs(context); xmlSetGenericErrorFunc(context, lpc2xml_genericxml_error); - xmlSaveCtxtPtr save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT); + save_ctx = xmlSaveToBuffer(buffer, "UTF-8", XML_SAVE_FORMAT); if(save_ctx != NULL) { ret = internal_convert_lpc2xml(context); if(ret == 0) { diff --git a/tools/lpc2xml.h b/coreapi/lpc2xml.h similarity index 100% rename from tools/lpc2xml.h rename to coreapi/lpc2xml.h diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 5f90855f5..ba15adbe0 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -39,7 +39,19 @@ #endif #endif /*_WIN32_WCE*/ +#ifdef _MSC_VER +#ifdef LINPHONE_WINDOWS_DESKTOP +#include +#else +#include +#endif +#else +#include +#endif +#ifdef _WIN32 +#define RENAME_REQUIRES_NONEXISTENT_NEW_PATH 1 +#endif #define lp_new0(type,n) (type*)calloc(sizeof(type),n) @@ -49,21 +61,41 @@ typedef struct _LpItem{ char *key; char *value; + int is_comment; } LpItem; +typedef struct _LpSectionParam{ + char *key; + char *value; +} LpSectionParam; + typedef struct _LpSection{ char *name; MSList *items; + MSList *params; } LpSection; struct _LpConfig{ + int refcnt; FILE *file; char *filename; + char *tmpfilename; MSList *sections; int modified; int readonly; }; +char* lp_realpath(const char* file, char* name) { +#if defined(_WIN32) || defined(__QNX__) || defined(ANDROID) + return ms_strdup(file); +#else + char * output = realpath(file, name); + char * msoutput = ms_strdup(output); + free(output); + return msoutput; +#endif +} + LpItem * lp_item_new(const char *key, const char *value){ LpItem *item=lp_new0(LpItem,1); item->key=ortp_strdup(key); @@ -71,6 +103,29 @@ LpItem * lp_item_new(const char *key, const char *value){ return item; } +LpItem * lp_comment_new(const char *comment){ + LpItem *item=lp_new0(LpItem,1); + char* pos = NULL; + item->value=ortp_strdup(comment); + + pos=strchr(item->value,'\r'); + if (pos==NULL) + pos=strchr(item->value,'\n'); + + if(pos) { + *pos='\0'; /*replace the '\n' */ + } + item->is_comment=TRUE; + return item; +} + +LpSectionParam *lp_section_param_new(const char *key, const char *value){ + LpSectionParam *param = lp_new0(LpSectionParam, 1); + param->key = ortp_strdup(key); + param->value = ortp_strdup(value); + return param; +} + LpSection *lp_section_new(const char *name){ LpSection *sec=lp_new0(LpSection,1); sec->name=ortp_strdup(name); @@ -79,14 +134,22 @@ LpSection *lp_section_new(const char *name){ void lp_item_destroy(void *pitem){ LpItem *item=(LpItem*)pitem; - free(item->key); - free(item->value); + if (item->key) ortp_free(item->key); + ortp_free(item->value); free(item); } +void lp_section_param_destroy(void *section_param){ + LpSectionParam *param = (LpSectionParam*)section_param; + ortp_free(param->key); + ortp_free(param->value); + free(param); +} + void lp_section_destroy(LpSection *sec){ - free(sec->name); + ortp_free(sec->name); ms_list_for_each(sec->items,lp_item_destroy); + ms_list_for_each(sec->params,lp_section_param_destroy); ms_list_free(sec->items); free(sec); } @@ -99,6 +162,10 @@ void lp_config_add_section(LpConfig *lpconfig, LpSection *section){ lpconfig->sections=ms_list_append(lpconfig->sections,(void *)section); } +void lp_config_add_section_param(LpSection *section, LpSectionParam *param){ + section->params = ms_list_append(section->params, (void *)param); +} + void lp_config_remove_section(LpConfig *lpconfig, LpSection *section){ lpconfig->sections=ms_list_remove(lpconfig->sections,(void *)section); lp_section_destroy(section); @@ -112,6 +179,14 @@ static bool_t is_first_char(const char *start, const char *pos){ return TRUE; } +static int is_a_comment(const char *str){ + while (*str==' '){ + str++; + } + if (*str=='#') return 1; + return 0; +} + LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){ LpSection *sec; MSList *elem; @@ -126,13 +201,25 @@ LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){ return NULL; } +LpSectionParam *lp_section_find_param(const LpSection *sec, const char *key){ + MSList *elem; + LpSectionParam *param; + for (elem = sec->params; elem != NULL; elem = ms_list_next(elem)){ + param = (LpSectionParam*)elem->data; + if (strcmp(param->key, key) == 0) { + return param; + } + } + return NULL; +} + LpItem *lp_section_find_item(const LpSection *sec, const char *name){ MSList *elem; LpItem *item; /*printf("Looking for item %s\n",name);*/ for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){ item=(LpItem*)elem->data; - if (strcmp(item->key,name)==0) { + if (!item->is_comment && strcmp(item->key,name)==0) { /*printf("Item %s found\n",name);*/ return item; } @@ -140,46 +227,71 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){ return NULL; } -void lp_config_parse(LpConfig *lpconfig, FILE *file){ - char tmp[MAX_LEN]= {'\0'}; - LpSection *cur=NULL; +static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpSection* cur) { + LpSectionParam *params = NULL; char *pos1,*pos2; int nbs; - char secname[MAX_LEN]; - char key[MAX_LEN]; + int size=strlen(line)+1; + char *secname=ms_malloc(size); + char *key=ms_malloc(size); + char *value=ms_malloc(size); LpItem *item; - if (file==NULL) return; + pos1=strchr(line,'['); + if (pos1!=NULL && is_first_char(line,pos1) ){ + pos2=strchr(pos1,']'); + if (pos2!=NULL){ + secname[0]='\0'; + /* found section */ + *pos2='\0'; + nbs = sscanf(pos1+1, "%s", secname); + if (nbs >= 1) { + if (strlen(secname) > 0) { + cur = lp_config_find_section (lpconfig,secname); + if (cur == NULL) { + cur = lp_section_new(secname); + lp_config_add_section(lpconfig, cur); + } - while(fgets(tmp,MAX_LEN,file)!=NULL){ - tmp[sizeof(tmp) -1] = '\0'; - pos1=strchr(tmp,'['); - if (pos1!=NULL && is_first_char(tmp,pos1) ){ - pos2=strchr(pos1,']'); - if (pos2!=NULL){ - secname[0]='\0'; - /* found section */ - *pos2='\0'; - nbs = sscanf(pos1+1,"%s",secname); - if (nbs == 1 ){ - if (strlen(secname)>0){ - cur=lp_config_find_section (lpconfig,secname); - if (cur==NULL){ - cur=lp_section_new(secname); - lp_config_add_section(lpconfig,cur); + if (pos2 > pos1 + 1 + strlen(secname)) { + /* found at least one section param */ + pos2 = pos1 + 1 + strlen(secname) + 1; // Remove the white space after the secname + pos1 = strchr(pos2, '='); + while (pos1 != NULL) { + /* for each section param */ + key[0] = '\0'; + value[0] = '\0'; + *pos1 = ' '; + if (sscanf(pos2, "%s %s", key, value) == 2) { + params = lp_section_param_new(key, value); + lp_config_add_section_param(cur, params); + + pos2 += strlen(key) + strlen(value) + 2; // Remove the = sign + the white space after each param + pos1 = strchr(pos2, '='); + } else { + ms_warning("parse section params error !"); + pos1 = NULL; + } } } - }else{ - ms_warning("parse error!"); } + } else { + ms_warning("parse error!"); } - }else { - pos1=strchr(tmp,'='); + } + }else { + if (is_a_comment(line)){ + if (cur){ + LpItem *comment=lp_comment_new(line); + lp_section_add_item(cur,comment); + } + }else{ + pos1=strchr(line,'='); if (pos1!=NULL){ key[0]='\0'; *pos1='\0'; - if (sscanf(tmp,"%s",key)>0){ + if (sscanf(line,"%s",key)>0){ pos1++; pos2=strchr(pos1,'\r'); @@ -192,17 +304,18 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ /* remove ending white spaces */ for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0'; - if (pos2-pos1>=0){ + if (pos2-pos1>0){ /* found a pair key,value */ + if (cur!=NULL){ item=lp_section_find_item(cur,key); if (item==NULL){ lp_section_add_item(cur,lp_item_new(key,pos1)); }else{ - ms_free(item->value); - item->value=strdup(pos1); + ortp_free(item->value); + item->value=ortp_strdup(pos1); } - /*printf("Found %s %s={%s}\n",cur->name,key,pos1);*/ + /*ms_message("Found %s=%s",key,pos1);*/ }else{ ms_warning("found key,item but no sections"); } @@ -211,65 +324,164 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ } } } + ms_free(key); + ms_free(value); + ms_free(secname); + return cur; +} + +void lp_config_parse(LpConfig *lpconfig, FILE *file){ + char tmp[MAX_LEN]= {'\0'}; + LpSection* current_section = NULL; + + if (file==NULL) return; + + while(fgets(tmp,MAX_LEN,file)!=NULL){ + tmp[sizeof(tmp) -1] = '\0'; + current_section = lp_config_parse_line(lpconfig, tmp, current_section); + } } LpConfig * lp_config_new(const char *filename){ + return lp_config_new_with_factory(filename, NULL); +} + +LpConfig * lp_config_new_from_buffer(const char *buffer){ + LpConfig* conf = lp_new0(LpConfig,1); + LpSection* current_section = NULL; + + char* ptr = ms_strdup(buffer); + char* strtok_storage = NULL; + char* line = strtok_r(ptr, "\n", &strtok_storage); + + conf->refcnt=1; + + while( line != NULL ){ + current_section = lp_config_parse_line(conf,line,current_section); + line = strtok_r(NULL, "\n", &strtok_storage); + } + + ms_free(ptr); + + return conf; +} + +LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); - struct stat fileStat; - if (filename!=NULL){ - lpconfig->filename=ortp_strdup(filename); - lpconfig->file=fopen(filename,"rw"); + lpconfig->refcnt=1; + if (config_filename!=NULL){ + if(ortp_file_exist(config_filename) == 0) { + lpconfig->filename=lp_realpath(config_filename, NULL); + if(lpconfig->filename == NULL) { + ms_error("Could not find the real path of %s: %s", config_filename, strerror(errno)); + goto fail; + } + } else { + lpconfig->filename = ms_strdup(config_filename); + } + lpconfig->tmpfilename=ortp_strdup_printf("%s.tmp",lpconfig->filename); + ms_message("Using (r/w) config information from %s", lpconfig->filename); + +#if !defined(_WIN32) + { + struct stat fileStat; + if ((stat(lpconfig->filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { + /* make existing configuration files non-group/world-accessible */ + if (chmod(lpconfig->filename, S_IRUSR | S_IWUSR) == -1) { + ms_warning("unable to correct permissions on " + "configuration file: %s", strerror(errno)); + } + } + } +#endif /*_WIN32*/ + /*open with r+ to check if we can write on it later*/ + lpconfig->file=fopen(lpconfig->filename,"r+"); +#ifdef RENAME_REQUIRES_NONEXISTENT_NEW_PATH + if (lpconfig->file==NULL){ + lpconfig->file=fopen(lpconfig->tmpfilename,"r+"); + if (lpconfig->file){ + ms_warning("Could not open %s but %s works, app may have crashed during last sync.",lpconfig->filename,lpconfig->tmpfilename); + } + } +#endif if (lpconfig->file!=NULL){ lp_config_parse(lpconfig,lpconfig->file); fclose(lpconfig->file); -#if !defined(_WIN32_WCE) -#ifndef S_ISREG -#define S_ISREG(mode) ((mode & S_IFMT) == S_IFREG) -#endif - if ((stat(filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { - /* make existing configuration files non-group/world-accessible */ - if (_chmod(filename, _S_IREAD | _S_IWRITE) == -1) { - ms_warning("unable to correct permissions on " - "configuration file: %s", strerror(errno)); - } - } -#endif /*_WIN32_WCE*/ + lpconfig->file=NULL; lpconfig->modified=0; } } + if (factory_config_filename != NULL) { + lp_config_read_file(lpconfig, factory_config_filename); + } return lpconfig; + +fail: + ms_free(lpconfig); + return NULL; } int lp_config_read_file(LpConfig *lpconfig, const char *filename){ - FILE* f=fopen(filename,"r"); + char* path = lp_realpath(filename, NULL); + FILE* f=fopen(path,"r"); if (f!=NULL){ + ms_message("Reading config information from %s", path); lp_config_parse(lpconfig,f); fclose(f); return 0; } - ms_warning("Fail to open file %s",filename); + ms_warning("Fail to open file %s",path); + ms_free(path); return -1; } void lp_item_set_value(LpItem *item, const char *value){ - free(item->value); + char *prev_value=item->value; item->value=ortp_strdup(value); + ortp_free(prev_value); } -void lp_config_destroy(LpConfig *lpconfig){ - if (lpconfig->filename!=NULL) free(lpconfig->filename); +static void _lp_config_destroy(LpConfig *lpconfig){ + if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename); + if (lpconfig->tmpfilename) ortp_free(lpconfig->tmpfilename); ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy); ms_list_free(lpconfig->sections); free(lpconfig); } +LpConfig *lp_config_ref(LpConfig *lpconfig){ + lpconfig->refcnt++; + return lpconfig; +} + +void lp_config_unref(LpConfig *lpconfig){ + lpconfig->refcnt--; + if (lpconfig->refcnt==0) + _lp_config_destroy(lpconfig); +} + +void lp_config_destroy(LpConfig *lpconfig){ + lp_config_unref(lpconfig); +} + void lp_section_remove_item(LpSection *sec, LpItem *item){ sec->items=ms_list_remove(sec->items,(void *)item); lp_item_destroy(item); } +const char *lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value){ + LpSection *sec; + LpSectionParam *param; + sec = lp_config_find_section(lpconfig, section); + if (sec != NULL) { + param = lp_section_find_param(sec, key); + if (param != NULL) return param->value; + } + return default_value; +} + const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){ LpSection *sec; LpItem *item; @@ -300,13 +512,16 @@ bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const } } + int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){ const char *str=lp_config_get_string(lpconfig,section,key,NULL); if (str!=NULL) { int ret=0; + if (strstr(str,"0x")==str){ sscanf(str,"%x",&ret); - }else ret=atoi(str); + }else + sscanf(str,"%i",&ret); return ret; } else return default_value; @@ -315,7 +530,7 @@ int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char * int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){ const char *str=lp_config_get_string(lpconfig,section,key,NULL); if (str!=NULL) { -#ifdef WIN32 +#ifdef _WIN32 return (int64_t)_atoi64(str); #else return atoll(str); @@ -338,14 +553,14 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke if (sec!=NULL){ item=lp_section_find_item(sec,key); if (item!=NULL){ - if (value!=NULL) + if (value!=NULL && value[0] != '\0') lp_item_set_value(item,value); else lp_section_remove_item(sec,item); }else{ - if (value!=NULL) + if (value!=NULL && value[0] != '\0') lp_section_add_item(sec,lp_item_new(key,value)); } - }else if (value!=NULL){ + }else if (value!=NULL && value[0] != '\0'){ sec=lp_section_new(section); lp_config_add_section(lpconfig,sec); lp_section_add_item(sec,lp_item_new(key,value)); @@ -385,24 +600,40 @@ void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key } void lp_item_write(LpItem *item, FILE *file){ - fprintf(file,"%s=%s\n",item->key,item->value); + if (item->is_comment) + fprintf(file,"%s\n",item->value); + else if (item->value && item->value[0] != '\0' ) + fprintf(file,"%s=%s\n",item->key,item->value); + else { + ms_warning("Not writing item %s to file, it is empty", item->key); + } +} + +void lp_section_param_write(LpSectionParam *param, FILE *file){ + if( param->value && param->value[0] != '\0') { + fprintf(file, " %s=%s", param->key, param->value); + } else { + ms_warning("Not writing param %s to file, it is empty", param->key); + } } void lp_section_write(LpSection *sec, FILE *file){ - fprintf(file,"[%s]\n",sec->name); - ms_list_for_each2(sec->items,(void (*)(void*, void*))lp_item_write,(void *)file); - fprintf(file,"\n"); + fprintf(file, "[%s",sec->name); + ms_list_for_each2(sec->params, (void (*)(void*, void*))lp_section_param_write, (void *)file); + fprintf(file, "]\n"); + ms_list_for_each2(sec->items, (void (*)(void*, void*))lp_item_write, (void *)file); + fprintf(file, "\n"); } int lp_config_sync(LpConfig *lpconfig){ FILE *file; if (lpconfig->filename==NULL) return -1; if (lpconfig->readonly) return 0; -#ifndef WIN32 +#ifndef _WIN32 /* don't create group/world-accessible files */ (void) umask(S_IRWXG | S_IRWXO); #endif - file=fopen(lpconfig->filename,"w"); + file=fopen(lpconfig->tmpfilename,"w"); if (file==NULL){ ms_warning("Could not write %s ! Maybe it is read-only. Configuration will not be saved.",lpconfig->filename); lpconfig->readonly=1; @@ -410,6 +641,16 @@ int lp_config_sync(LpConfig *lpconfig){ } ms_list_for_each2(lpconfig->sections,(void (*)(void *,void*))lp_section_write,(void *)file); fclose(file); +#ifdef RENAME_REQUIRES_NONEXISTENT_NEW_PATH + /* On windows, rename() does not accept that the newpath is an existing file, while it is accepted on Unix. + * As a result, we are forced to first delete the linphonerc file, and then rename.*/ + if (remove(lpconfig->filename)!=0){ + ms_error("Cannot remove %s: %s",lpconfig->filename, strerror(errno)); + } +#endif + if (rename(lpconfig->tmpfilename,lpconfig->filename)!=0){ + ms_error("Cannot rename %s into %s: %s",lpconfig->tmpfilename,lpconfig->filename,strerror(errno)); + } lpconfig->modified=0; return 0; } @@ -435,7 +676,8 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi if (sec!=NULL){ for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){ item=(LpItem*)elem->data; - callback(item->key, ctx); + if (!item->is_comment) + callback(item->key, ctx); } } } @@ -451,3 +693,168 @@ void lp_config_clean_section(LpConfig *lpconfig, const char *section){ int lp_config_needs_commit(const LpConfig *lpconfig){ return lpconfig->modified>0; } + +static const char *DEFAULT_VALUES_SUFFIX = "_default_values"; + +int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_int(lpconfig, default_section, key, default_value); +} + +int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_int64(lpconfig, default_section, key, default_value); +} + +float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_float(lpconfig, default_section, key, default_value); +} + +const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_string(lpconfig, default_section, key, default_value); +} + +/* + * WARNING: this function is very dangerous. + * Read carefuly the folowing notices: + * 1. The 'path' parameter may be modify by + * the function. Be care to keep a copy of + * the original string. + * 2. The return pointer may points on a part of + * 'path'. So, be care to not free the string + * pointed by 'path' before the last used of + * the returned pointer. + * 3. Do not feed it after midnight + */ +static const char *_lp_config_dirname(char *path) { +#ifdef _MSC_VER + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + static char dirname[_MAX_DRIVE + _MAX_DIR]; + _splitpath(path, drive, dir, fname, ext); + snprintf(dirname, sizeof(dirname), "%s%s", drive, dir); + return dirname; +#else + return dirname(path); +#endif +} + +bool_t lp_config_relative_file_exists(const LpConfig *lpconfig, const char *filename) { + if (lpconfig->filename == NULL) { + return FALSE; + } else { + char *filename = ms_strdup(lpconfig->filename); + const char *dir = _lp_config_dirname(filename); + char *filepath = ms_strdup_printf("%s/%s", dir, filename); + char *realfilepath = lp_realpath(filepath, NULL); + FILE *file; + + ms_free(filename); + ms_free(filepath); + + if(realfilepath == NULL) return FALSE; + + file = fopen(realfilepath, "r"); + ms_free(realfilepath); + if (file) { + fclose(file); + } + return file != NULL; + } +} + +void lp_config_write_relative_file(const LpConfig *lpconfig, const char *filename, const char *data) { + char *dup_config_file = NULL; + const char *dir = NULL; + char *filepath = NULL; + char *realfilepath = NULL; + FILE *file; + + if (lpconfig->filename == NULL) return; + + if(strlen(data) == 0) { + ms_warning("%s has not been created because there is no data to write", filename); + return; + } + + dup_config_file = ms_strdup(lpconfig->filename); + dir = _lp_config_dirname(dup_config_file); + filepath = ms_strdup_printf("%s/%s", dir, filename); + realfilepath = lp_realpath(filepath, NULL); + if(realfilepath == NULL) { + ms_error("Could not resolv %s: %s", filepath, strerror(errno)); + goto end; + } + + file = fopen(realfilepath, "w"); + if(file == NULL) { + ms_error("Could not open %s for write", realfilepath); + goto end; + } + + fprintf(file, "%s", data); + fclose(file); + +end: + ms_free(dup_config_file); + ms_free(filepath); + if(realfilepath) ms_free(realfilepath); +} + +int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length) { + char *dup_config_file = NULL; + const char *dir = NULL; + char *filepath = NULL; + FILE *file = NULL; + char* realfilepath = NULL; + + if (lpconfig->filename == NULL) return -1; + + dup_config_file = ms_strdup(lpconfig->filename); + dir = _lp_config_dirname(dup_config_file); + filepath = ms_strdup_printf("%s/%s", dir, filename); + realfilepath = lp_realpath(filepath, NULL); + if(realfilepath == NULL) { + ms_error("Could not resolv %s: %s", filepath, strerror(errno)); + goto err; + } + + file = fopen(realfilepath, "r"); + if(file == NULL) { + ms_error("Could not open %s for read. %s", realfilepath, strerror(errno)); + goto err; + } + + if(fread(data, 1, max_length, file)<=0) { + ms_error("%s could not be loaded. %s", realfilepath, strerror(errno)); + goto err; + } + fclose(file); + + ms_free(dup_config_file); + ms_free(filepath); + ms_free(realfilepath); + return 0; + +err: + ms_free(filepath); + ms_free(filepath); + if(realfilepath) ms_free(realfilepath); + return -1; +} diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 310baaff3..b03bfa57f 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -21,15 +21,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #ifndef LPCONFIG_H #define LPCONFIG_H - +#include #include +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC +#endif + /** * The LpConfig object is used to manipulate a configuration file. - * + * * @ingroup misc * The format of the configuration file is a .ini like format: * - sections are defined in [] @@ -51,30 +55,55 @@ typedef struct _LpConfig LpConfig; extern "C" { #endif +/** + * Instantiates a LpConfig object from a user config file. + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. + * @ingroup misc + * @param filename the filename of the config file to read to fill the instantiated LpConfig + * @see lp_config_new_with_factory + */ +LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); -#define LP_CONFIG_DEFAULT_STRING(config, name, default) \ - (config) ? (lp_config_get_string(config, "default_values", name, default)) : (default) +/** + * Instantiates a LpConfig object from a user provided buffer. + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. + * @ingroup misc + * @param buffer the buffer from which the lpconfig will be retrieved. We expect the buffer to be null-terminated. + * @see lp_config_new_with_factory + * @see lp_config_new + */ +LINPHONE_PUBLIC LpConfig * lp_config_new_from_buffer(const char *buffer); -#define LP_CONFIG_DEFAULT_INT(config, name, default) \ - (config) ? (lp_config_get_int(config, "default_values", name, default)) : (default) +/** + * Instantiates a LpConfig object from a user config file and a factory config file. + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. + * @ingroup misc + * @param config_filename the filename of the user config file to read to fill the instantiated LpConfig + * @param factory_config_filename the filename of the factory config file to read to fill the instantiated LpConfig + * @see lp_config_new + * + * The user config file is read first to fill the LpConfig and then the factory config file is read. + * Therefore the configuration parameters defined in the user config file will be overwritten by the parameters + * defined in the factory config file. + */ +LINPHONE_PUBLIC LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); -#define LP_CONFIG_DEFAULT_INT64(config, name, default) \ - (config) ? (lp_config_get_int64(config, "default_values", name, default)) : (default) +/** + * 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); -#define LP_CONFIG_DEFAULT_FLOAT(config, name, default) \ - (config) ? (lp_config_get_float(config, "default_values", name, default)) : (default) - - -LpConfig * lp_config_new(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. * @@ -82,95 +111,102 @@ 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. - * + * * @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 + * 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 * * @ingroup misc **/ -void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value); +LINPHONE_PUBLIC void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value); /** * Sets a 64 bits integer config item * * @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. * @@ -180,8 +216,85 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi /*tells whether uncommited (with lp_config_sync()) modifications exist*/ int lp_config_needs_commit(const LpConfig *lpconfig); -void lp_config_destroy(LpConfig *cfg); - + +LINPHONE_PUBLIC void lp_config_destroy(LpConfig *cfg); + +/** + * Retrieves a default configuration item as an integer, given its section, key, and default value. + * + * @ingroup misc + * The default integer value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value); + +/** + * Retrieves a default configuration item as a 64 bit integer, given its section, key, and default value. + * + * @ingroup misc + * The default integer value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value); + +/** + * Retrieves a default configuration item as a float, given its section, key, and default value. + * + * @ingroup misc + * The default float value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value); + +/** + * Retrieves a default configuration item as a string, given its section, key, and default value. + * + * @ingroup misc + * The default value string is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value); + +/** + * Retrieves a section parameter item as a string, given its section and key. + * + * @ingroup misc + * The default value string is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC const char* lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value); + + +/** + * increment reference count + * @ingroup misc +**/ +LINPHONE_PUBLIC LpConfig *lp_config_ref(LpConfig *lpconfig); + +/** + * Decrement reference count, which will eventually free the object. + * @ingroup misc +**/ +LINPHONE_PUBLIC void lp_config_unref(LpConfig *lpconfig); + +/** + * @brief Write a string in a file placed relatively with the Linphone configuration file. + * @param lpconfig LpConfig instance used as a reference + * @param filename Name of the file where to write data. The name is relative to the place of the config file + * @param data String to write + */ +LINPHONE_PUBLIC void lp_config_write_relative_file(const LpConfig *lpconfig, const char *filename, const char *data); + +/** + * @brief Read a string from a file placed beside the Linphone configuration file + * @param lpconfig LpConfig instance used as a reference + * @param filename Name of the file where data will be read from. The name is relative to the place of the config file + * @param data Buffer where read string will be stored + * @param max_length Length of the buffer + * @return 0 on success, -1 on failure + */ +LINPHONE_PUBLIC int lp_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length); + +/** + * @return TRUE if file exists relative to the to the current location +**/ +LINPHONE_PUBLIC bool_t lp_config_relative_file_exists(const LpConfig *lpconfig, const char *filename); + #ifdef __cplusplus } #endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c index e47023f4f..6aa803a06 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -194,7 +194,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_warning("Could not play %s",filename); return -1; } - ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b); + ms_filter_add_notify_callback (b->player,lsd_player_on_eop,b,FALSE); lsd_player_configure(b); ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; @@ -249,7 +249,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); - ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]); + ms_filter_add_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0],FALSE); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c new file mode 100644 index 000000000..25d37a1b8 --- /dev/null +++ b/coreapi/message_storage.c @@ -0,0 +1,721 @@ +/* +message_storage.c +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" +#include "linphonecore.h" + +#ifdef MSG_STORAGE_ENABLED +#ifndef PRIu64 +#define PRIu64 "I64u" +#endif + +#ifndef _WIN32 +#if !defined(ANDROID) && !defined(__QNXNTO__) +# include +# include +# include +#endif +#else +#include +#endif + +#define MAX_PATH_SIZE 1024 + +#include "sqlite3.h" +#include + +static ORTP_INLINE LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){ + MSList* transients = cr->transient_messages; + LinphoneChatMessage* chat; + while( transients ){ + chat = (LinphoneChatMessage*)transients->data; + if(chat->storage_id == storage_id){ + return linphone_chat_message_ref(chat); + } + transients = transients->next; + } + return NULL; +} + +/* DB layout: + * | 0 | storage_id + * | 1 | type + * | 2 | subtype + * | 3 | name + * | 4 | encoding + * | 5 | size + * | 6 | data + */ +// Callback for sql request when getting linphone content +static int callback_content(void *data, int argc, char **argv, char **colName) { + LinphoneChatMessage *message = (LinphoneChatMessage *)data; + + if (message->file_transfer_information) { + linphone_content_unref(message->file_transfer_information); + message->file_transfer_information = NULL; + } + message->file_transfer_information = linphone_content_new(); + if (argv[1]) linphone_content_set_type(message->file_transfer_information, argv[1]); + if (argv[2]) linphone_content_set_subtype(message->file_transfer_information, argv[2]); + if (argv[3]) linphone_content_set_name(message->file_transfer_information, argv[3]); + if (argv[4]) linphone_content_set_encoding(message->file_transfer_information, argv[4]); + linphone_content_set_size(message->file_transfer_information, (size_t)atoi(argv[5])); + + return 0; +} + +static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id) { + char* errmsg = NULL; + int ret; + char * buf; + + buf = sqlite3_mprintf("SELECT * FROM content WHERE id = %i", content_id); + ret = sqlite3_exec(db, buf, callback_content, message, &errmsg); + if (ret != SQLITE_OK) { + ms_error("Error in creation: %s.", errmsg); + sqlite3_free(errmsg); + } + sqlite3_free(buf); +} + + + +// Called when fetching all conversations from database +static int callback_all(void *data, int argc, char **argv, char **colName){ + LinphoneCore* lc = (LinphoneCore*) data; + char* address = argv[0]; + LinphoneAddress *addr = linphone_address_new(address); + if (addr){ + linphone_core_get_chat_room(lc, addr); + linphone_address_destroy(addr); + } + return 0; +} + +/* DB layout: + * | 0 | storage_id + * | 1 | localContact + * | 2 | remoteContact + * | 3 | direction flag + * | 4 | message + * | 5 | time (unused now, used to be string-based timestamp) + * | 6 | read flag + * | 7 | status + * | 8 | external body url + * | 9 | utc timestamp + * | 10 | app data text + * | 11 | linphone content id + */ +static int create_chat_message(void *data, int argc, char **argv, char **colName){ + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + LinphoneAddress *from; + LinphoneAddress *to; + unsigned int storage_id = atoi(argv[0]); + + // check if the message exists in the transient list, in which case we should return that one. + LinphoneChatMessage* new_message = get_transient_message(cr, storage_id); + if( new_message == NULL ){ + new_message = linphone_chat_room_create_message(cr, argv[4]); + + if(atoi(argv[3])==LinphoneChatMessageIncoming){ + new_message->dir=LinphoneChatMessageIncoming; + from=linphone_address_new(argv[2]); + to=linphone_address_new(argv[1]); + } else { + new_message->dir=LinphoneChatMessageOutgoing; + from=linphone_address_new(argv[1]); + to=linphone_address_new(argv[2]); + } + linphone_chat_message_set_from(new_message,from); + linphone_address_destroy(from); + if (to){ + linphone_chat_message_set_to(new_message,to); + linphone_address_destroy(to); + } + + new_message->time = (time_t)atol(argv[9]); + new_message->is_read=atoi(argv[6]); + new_message->state=atoi(argv[7]); + new_message->storage_id=storage_id; + new_message->external_body_url= ms_strdup(argv[8]); + new_message->appdata = ms_strdup(argv[10]); + + if (argv[11] != NULL) { + int id = atoi(argv[11]); + if (id >= 0) { + fetch_content_from_database(cr->lc->db, new_message, id); + } + } + } + cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); + + return 0; +} + +void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,create_chat_message,cr,&errmsg); + if(ret != SQLITE_OK) { + ms_error("Error in creation: %s.", errmsg); + sqlite3_free(errmsg); + } +} + +int linphone_sql_request(sqlite3* db,const char *stmt){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg); + sqlite3_free(errmsg); + } + return ret; +} + +// Process the request to fetch all chat contacts +void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.", errmsg); + sqlite3_free(errmsg); + } +} + +static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { + LinphoneCore *lc = linphone_chat_room_get_lc(msg->chat_room); + int id = -1; + if (lc->db) { + LinphoneContent *content = msg->file_transfer_information; + char *buf = sqlite3_mprintf("INSERT INTO content VALUES(NULL,%Q,%Q,%Q,%Q,%i,%Q);", + linphone_content_get_type(content), + linphone_content_get_subtype(content), + linphone_content_get_name(content), + linphone_content_get_encoding(content), + linphone_content_get_size(content), + NULL + ); + linphone_sql_request(lc->db, buf); + sqlite3_free(buf); + id = (unsigned int) sqlite3_last_insert_rowid (lc->db); + } + return id; +} + +unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ + LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); + int id = 0; + + if (lc->db){ + int content_id = -1; + char *peer; + char *local_contact; + char *buf; + if (msg->file_transfer_information) { + content_id = linphone_chat_message_store_content(msg); + } + + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); + local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); + buf = sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%lld,%Q,%i);", + local_contact, + peer, + msg->dir, + msg->message, + "-1", /* use UTC field now */ + msg->is_read, + msg->state, + msg->external_body_url, + (int64_t)msg->time, + msg->appdata, + content_id + ); + 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){ + LinphoneCore *lc=msg->chat_room->lc; + if (lc->db){ + char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (id = %i);", + msg->state,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + } +} + +void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ + LinphoneCore *lc=msg->chat_room->lc; + if (lc->db){ + char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%i;", + msg->appdata,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + } +} + +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int read=1; + char *peer; + char *buf; + + if (lc->db==NULL) return ; + + // optimization: do not modify the database if no message is marked as unread + if(linphone_chat_room_get_unread_messages_count(cr) == 0) return; + + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + buf=sqlite3_mprintf("UPDATE history SET read=%i WHERE remoteContact = %Q;", + read,peer); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(peer); + + cr->unread_count = 0; +} + +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + char *buf; + + if (lc->db==NULL) return ; + + 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); +} + +static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t unread_only){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int numrows=0; + char *peer; + char *buf; + sqlite3_stmt *selectStatement; + int returnValue; + + if (lc->db==NULL) return 0; + + // optimization: do not read database if the count is already available in memory + if(unread_only && cr->unread_count >= 0) return cr->unread_count; + + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;",peer,unread_only?"AND read = 0":""); + returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL); + if (returnValue == SQLITE_OK){ + if(sqlite3_step(selectStatement) == SQLITE_ROW){ + numrows= sqlite3_column_int(selectStatement, 0); + } + } + sqlite3_finalize(selectStatement); + sqlite3_free(buf); + ms_free(peer); + + /* no need to test the sign of cr->unread_count here + * because it has been tested above */ + if(unread_only) cr->unread_count = numrows; + + return numrows; +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + return linphone_chat_room_get_messages_count(cr, TRUE); +} + +int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){ + return linphone_chat_room_get_messages_count(cr, FALSE); +} + +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=cr->lc; + char *buf; + + if (lc->db==NULL) return ; + + buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + + if(cr->unread_count >= 0 && !msg->is_read) { + assert(cr->unread_count > 0); + cr->unread_count--; + } +} + +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ + LinphoneCore *lc=cr->lc; + char *peer; + char *buf; + + if (lc->db==NULL) return ; + + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(peer); + + if(cr->unread_count > 0) cr->unread_count = 0; +} + +MSList *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + MSList *ret; + char *buf,*buf2; + char *peer; + uint64_t begin,end; + int buf_max_size = 512; + + if (lc->db==NULL) return NULL; + peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + + cr->messages_hist = NULL; + + /*since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf*/ + buf=ms_malloc(buf_max_size); + buf=sqlite3_snprintf(buf_max_size-1,buf,"SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC",peer); + + + if (startm<0) startm=0; + + if ((endm>0&&endm>=startm) || (startm == 0 && endm == 0) ){ + buf2=ms_strdup_printf("%s LIMIT %i ",buf,endm+1-startm); + ms_free(buf); + buf = buf2; + }else if(startm>0){ + ms_message("%s(): end is lower than start (%d < %d). Assuming no end limit.",__FUNCTION__,endm,startm); + buf2=ms_strdup_printf("%s LIMIT -1",buf); + ms_free(buf); + buf = buf2; + } + + if (startm>0){ + buf2=ms_strdup_printf("%s OFFSET %i ",buf,startm); + ms_free(buf); + buf = buf2; + } + + begin=ortp_get_cur_time_ms(); + linphone_sql_request_message(lc->db,buf,cr); + end=ortp_get_cur_time_ms(); + ms_message("%s(): completed in %i ms",__FUNCTION__, (int)(end-begin)); + ms_free(buf); + ret=cr->messages_hist; + cr->messages_hist=NULL; + ms_free(peer); + return ret; +} + +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ + return linphone_chat_room_get_history_range(cr, 0, nb_message-1); +} + + +void linphone_close_storage(sqlite3* db){ + sqlite3_close(db); +} + +void linphone_create_table(sqlite3* db){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "localContact TEXT NOT NULL," + "remoteContact TEXT NOT NULL," + "direction INTEGER," + "message TEXT," + "time TEXT NOT NULL," + "read INTEGER," + "status INTEGER" + ");", + 0,0,&errmsg); + if(ret != SQLITE_OK) { + ms_error("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + + +static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; +static time_t parse_time_from_db( const char* time ){ + /* messages used to be stored in the DB by using string-based time */ + struct tm ret={0}; + char tmp1[80]={0}; + char tmp2[80]={0}; + int i,j; + time_t parsed = 0; + + if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, + &ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){ + ret.tm_year-=1900; + for(i=0;i<7;i++) { + if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; + } + for(j=0;j<12;j++) { + if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; + } + ret.tm_isdst=-1; + parsed = mktime(&ret); + } + return parsed; +} + + +static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) { + time_t new_time = parse_time_from_db(argv[1]); + if( new_time ){ + /* replace 'time' by -1 and set 'utc' to the timestamp */ + char *buf = sqlite3_mprintf("UPDATE history SET utc=%lld,time='-1' WHERE id=%i;", (int64_t)new_time, atoi(argv[0])); + if( buf) { + linphone_sql_request((sqlite3*)data, buf); + sqlite3_free(buf); + } + } else { + ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); + } + return 0; +} + +static void linphone_migrate_timestamps(sqlite3* db){ + int ret; + char* errmsg = NULL; + uint64_t begin=ortp_get_cur_time_ms(); + + linphone_sql_request(db,"BEGIN TRANSACTION"); + + ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg); + if( ret != SQLITE_OK ){ + ms_warning("Error migrating outgoing messages: %s.\n", errmsg); + sqlite3_free(errmsg); + linphone_sql_request(db, "ROLLBACK"); + } else { + uint64_t end; + linphone_sql_request(db, "COMMIT"); + end=ortp_get_cur_time_ms(); + ms_message("Migrated message timestamps to UTC in %lu ms",(unsigned long)(end-begin)); + } +} + +void linphone_update_table(sqlite3* db) { + char* errmsg=NULL; + int ret; + + // for image url storage + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table history updated successfully for URL."); + } + + // for UTC timestamp storage + ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); + if( ret != SQLITE_OK ){ + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table history updated successfully for UTC."); + // migrate from old text-based timestamps to unix time-based timestamps + linphone_migrate_timestamps(db); + } + + // new field for app-specific storage + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table history updated successfully for app-specific data."); + } + + // new field for linphone content storage + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN content INTEGER;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table history updated successfully for content data."); + ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS content (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "type TEXT," + "subtype TEXT," + "name TEXT," + "encoding TEXT," + "size INTEGER," + "data BLOB" + ");", + 0,0,&errmsg); + if(ret != SQLITE_OK) { + ms_error("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table content successfully created."); + } + } +} + +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { + char *buf; + + if (lc->db==NULL) return; + buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;"); + linphone_sql_request_all(lc->db,buf,lc); + sqlite3_free(buf); +} + +static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ + ms_warning("SQL statement '%s' took %" PRIu64 " microseconds", statement, (uint64_t)(duration / 1000LL) ); +} + +static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ + if( debug ){ + sqlite3_profile(db, _linphone_message_storage_profile, NULL ); + } else { + sqlite3_profile(db, NULL, NULL ); + } +} + +void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){ + + lc->debug_storage = debug; + + if( lc->db ){ + linphone_message_storage_activate_debug(lc->db, debug); + } +} + +static int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { +#if defined(ANDROID) || defined(__QNXNTO__) + return sqlite3_open(db_file, db); +#elif defined(_WIN32) + int ret; + wchar_t db_file_utf16[MAX_PATH_SIZE]; + ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, db_file, -1, db_file_utf16, MAX_PATH_SIZE); + if(ret == 0) db_file_utf16[0] = '\0'; + return sqlite3_open16(db_file_utf16, db); +#else + char db_file_locale[MAX_PATH_SIZE] = {'\0'}; + char db_file_utf8[MAX_PATH_SIZE] = ""; + char *inbuf=db_file_locale, *outbuf=db_file_utf8; + size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE; + iconv_t cb; + + strncpy(db_file_locale, db_file, MAX_PATH_SIZE-1); + cb = iconv_open("UTF-8", nl_langinfo(CODESET)); + if(cb != (iconv_t)-1) { + int ret; + ret = iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); + if(ret == -1) db_file_utf8[0] = '\0'; + iconv_close(cb); + } + return sqlite3_open(db_file_utf8, db); +#endif +} + +void linphone_core_message_storage_init(LinphoneCore *lc){ + int ret; + const char *errmsg; + sqlite3 *db; + + linphone_core_message_storage_close(lc); + + ret=_linphone_sqlite3_open(lc->chat_db_file,&db); + if(ret != SQLITE_OK) { + errmsg=sqlite3_errmsg(db); + ms_error("Error in the opening: %s.\n", errmsg); + sqlite3_close(db); + return; + } + + linphone_message_storage_activate_debug(db, lc->debug_storage); + + linphone_create_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){ + if (lc->db){ + sqlite3_close(lc->db); + lc->db=NULL; + } +} + +#else + +unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ + return 0; +} + +void linphone_chat_message_store_state(LinphoneChatMessage *cr){ +} + +void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){ +} + +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ +} + +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ + return NULL; +} + +LINPHONE_PUBLIC MSList *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end){ + return NULL; +} + +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ +} + +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { +} + +void linphone_core_message_storage_init(LinphoneCore *lc){ +} + +void linphone_core_message_storage_close(LinphoneCore *lc){ +} + +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + return 0; +} + +int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){ + return 0; +} + +#endif diff --git a/coreapi/misc.c b/coreapi/misc.c index c2e1217e0..60465887d 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1,1164 +1,1836 @@ - -/* -linphone -Copyright (C) 2000 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" -#include "mediastreamer2/mediastream.h" -#include -#include -#ifdef HAVE_SIGHANDLER_T -#include -#endif /*HAVE_SIGHANDLER_T*/ - -#include -#if !defined(_WIN32_WCE) -#include -#include -#include -#if _MSC_VER -#include -#else -#include -#endif -#include -#endif /*_WIN32_WCE*/ - -#undef snprintf -#include - -#ifdef HAVE_GETIFADDRS -#include -#include -#endif -#include -#if _MSC_VER -#define snprintf _snprintf -#define popen _popen -#define pclose _pclose -#endif - -#if !defined(WIN32) - -static char lock_name[80]; -static char lock_set=0; -/* put a lock file in /tmp. this is called when linphone runs as a daemon*/ -int set_lock_file() -{ - FILE *lockfile; - - snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); - lockfile=fopen(lock_name,"w"); - if (lockfile==NULL) - { - printf("Failed to create lock file.\n"); - return(-1); - } - fprintf(lockfile,"%i",getpid()); - fclose(lockfile); - lock_set=1; - return(0); -} - -/* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/ -int get_lock_file() -{ - int pid; - FILE *lockfile; - - snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); - lockfile=fopen(lock_name,"r"); - if (lockfile==NULL) - return(-1); - if (fscanf(lockfile,"%i",&pid)!=1){ - ms_warning("Could not read pid in lock file."); - fclose(lockfile); - return -1; - } - fclose(lockfile); - return pid; -} - -/* remove the lock file if it was set*/ -int remove_lock_file() -{ - int err=0; - if (lock_set) - { - err=unlink(lock_name); - lock_set=0; - } - return(err); -} - -#endif - -char *int2str(int number) -{ - char *numstr=ms_malloc(10); - snprintf(numstr,10,"%i",number); - return numstr; -} - -void check_sound_device(LinphoneCore *lc) -{ -#ifdef _linux - int fd=0; - int len; - int a; - char *file=NULL; - char *i810_audio=NULL; - char *snd_pcm_oss=NULL; - char *snd_mixer_oss=NULL; - char *snd_pcm=NULL; - fd=open("/proc/modules",O_RDONLY); - - if (fd>0){ - /* read the entire /proc/modules file and check if sound conf seems correct */ - /*a=fstat(fd,&statbuf); - if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno)); - len=statbuf.st_size; - if (len==0) ms_warning("/proc/modules has zero size!"); - */ - /***** fstat does not work on /proc/modules for unknown reason *****/ - len=6000; - file=ms_malloc(len+1); - a=read(fd,file,len); - if (avtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/ - goto end; - } - snd_pcm=strstr(file,"snd-pcm"); - if (snd_pcm!=NULL){ - snd_pcm_oss=strstr(file,"snd-pcm-oss"); - snd_mixer_oss=strstr(file,"snd-mixer-oss"); - if (snd_pcm_oss==NULL){ - lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it.")); - } - if (snd_mixer_oss==NULL){ - lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it.")); - } - } - }else { - - ms_warning("Could not open /proc/modules."); - } - /* now check general volume. Some user forget to rise it and then complain that linphone is - not working */ - /* but some other users complain that linphone should not change levels... - if (lc->sound_conf.sndcard!=NULL){ - a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL); - if (a<50){ - ms_warning("General level is quite low (%i). Linphone rises it up for you.",a); - snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80); - } - } - */ - end: - if (file!=NULL) ms_free(file); - if (fd>0) close(fd); -#endif -} - -#define UDP_HDR_SZ 8 -#define RTP_HDR_SZ 12 -#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ - -static void payload_type_set_enable(PayloadType *pt,int value) -{ - if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ - else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); -} - -static bool_t payload_type_enabled(const PayloadType *pt) { - return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); -} - -bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt){ - if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ - return payload_type_enabled(pt); - } - ms_error("Getting enablement status of codec not in audio or video list of PayloadType !"); - return FALSE; -} - -int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){ - if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ - payload_type_set_enable(pt,enabled); - _linphone_core_codec_config_write(lc); - return 0; - } - ms_error("Enabling codec not in audio or video list of PayloadType !"); - return -1; -} - -int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){ - return payload_type_get_number(pt); -} - -const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){ - if (ms_filter_codec_supported(pt->mime_type)){ - MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type); -#ifdef ENABLE_NLS - return dgettext("mediastreamer",desc->text); -#else - return desc->text; -#endif - } - return NULL; -} - - -/*this function makes a special case for speex/8000. -This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality -is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/ -static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){ - int upload_bw=linphone_core_get_upload_bandwidth(lc); - if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) { - if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){ - return 15000; - } - } - return pt->normal_bitrate; -} - -static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){ - double npacket=50; - double packet_size; - int bitrate; - bitrate=get_codec_bitrate(lc,pt); - packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; - return packet_size*8.0*npacket; -} - -void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){ - call->audio_bw=(int)(ceil(get_audio_payload_bandwidth(call->core,pt)/1000.0)); /*rounding codec bandwidth should be avoid, specially for AMR*/ - ms_message("Audio bandwidth for this call is %i",call->audio_bw); -} - -void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ - const MSList *elem; - PayloadType *max=NULL; - for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - if (payload_type_enabled(pt)){ - int pt_bitrate=get_codec_bitrate(lc,pt); - if (max==NULL) max=pt; - else if (max->normal_bitrateaudio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0); - } -} - -bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit) -{ - double codec_band; - bool_t ret=FALSE; - - switch (pt->type){ - case PAYLOAD_AUDIO_CONTINUOUS: - case PAYLOAD_AUDIO_PACKETIZED: - codec_band=get_audio_payload_bandwidth(lc,pt); - ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band); - /*hack to avoid using uwb codecs when having low bitrate and video*/ - if (bandwidth_is_greater(199,bandwidth_limit)){ - if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){ - ret=FALSE; - } - } - //ms_message("Payload %s: %g",pt->mime_type,codec_band); - break; - case PAYLOAD_VIDEO: - if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/ - ret=TRUE; - } - else ret=FALSE; - break; - } - return ret; -} - -/* return TRUE if codec can be used with bandwidth, FALSE else*/ -bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt) -{ - double codec_band; - int allowed_bw,video_bw; - bool_t ret=FALSE; - - linphone_core_update_allocated_audio_bandwidth(lc); - allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), - linphone_core_get_upload_bandwidth(lc)); - if (allowed_bw==0) { - allowed_bw=-1; - video_bw=1500; /*around 1.5 Mbit/s*/ - }else - video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw); - - switch (pt->type){ - case PAYLOAD_AUDIO_CONTINUOUS: - case PAYLOAD_AUDIO_PACKETIZED: - codec_band=get_audio_payload_bandwidth(lc,pt); - ret=bandwidth_is_greater(allowed_bw*1000,codec_band); - /*hack to avoid using uwb codecs when having low bitrate and video*/ - if (bandwidth_is_greater(199,allowed_bw)){ - if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){ - ret=FALSE; - } - } - //ms_message("Payload %s: %g",pt->mime_type,codec_band); - break; - case PAYLOAD_VIDEO: - if (video_bw>0){ - pt->normal_bitrate=video_bw*1000; - ret=TRUE; - } - else ret=FALSE; - break; - } - return ret; -} - -bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){ -#if !defined(_WIN32_WCE) - FILE *f=popen(command,"r"); - if (f!=NULL){ - int err; - *result=ms_malloc(4096); - err=fread(*result,1,4096-1,f); - if (err<0){ - ms_warning("Error reading command output:%s",strerror(errno)); - ms_free(result); - return FALSE; - } - (*result)[err]=0; - err=pclose(f); - if (command_ret!=NULL) *command_ret=err; - return TRUE; - } -#endif /*_WIN32_WCE*/ - return FALSE; -} - -static ortp_socket_t create_socket(int local_port){ - struct sockaddr_in laddr; - ortp_socket_t sock; - int optval; - sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); - if (sock<0) { - ms_error("Fail to create socket"); - return -1; - } - memset (&laddr,0,sizeof(laddr)); - laddr.sin_family=AF_INET; - laddr.sin_addr.s_addr=INADDR_ANY; - laddr.sin_port=htons(local_port); - if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){ - ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError()); - close_socket(sock); - return -1; - } - optval=1; - if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, - (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){ - ms_warning("Fail to set SO_REUSEADDR"); - } - set_non_blocking_socket(sock); - return sock; -} - -static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){ - char buf[STUN_MAX_MESSAGE_SIZE]; - int len = STUN_MAX_MESSAGE_SIZE; - StunAtrString username; - StunAtrString password; - StunMessage req; - int err; - memset(&req, 0, sizeof(StunMessage)); - memset(&username,0,sizeof(username)); - memset(&password,0,sizeof(password)); - stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id); - len = stunEncodeMessage( &req, buf, len, &password); - if (len<=0){ - ms_error("Fail to encode stun message."); - return -1; - } - err=sendto(sock,buf,len,0,server,addrlen); - if (err<0){ - ms_error("sendto failed: %s",strerror(errno)); - return -1; - } - 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]; - char *p1, *p2; - if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) { - family = PF_INET6; - } 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); - } - } - snprintf(port, sizeof(port), "%d", port_int); - memset(&hints,0,sizeof(hints)); - hints.ai_family=family; - hints.ai_socktype=SOCK_DGRAM; - hints.ai_protocol=IPPROTO_UDP; - ret=getaddrinfo(host,port,&hints,&res); - if (ret!=0){ - ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret)); - return -1; - } - if (!res) return -1; - memcpy(ss,res->ai_addr,res->ai_addrlen); - *socklen=res->ai_addrlen; - freeaddrinfo(res); - return 0; -} - -static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){ - char buf[STUN_MAX_MESSAGE_SIZE]; - int len = STUN_MAX_MESSAGE_SIZE; - StunMessage resp; - len=recv(sock,buf,len,0); - if (len>0){ - struct in_addr ia; - stunParseMessage(buf,len, &resp ); - *id=resp.msgHdr.tr_id.octet[0]; - if (resp.hasXorMappedAddress){ - *port = resp.xorMappedAddress.ipv4.port; - ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr); - }else if (resp.hasMappedAddress){ - *port = resp.mappedAddress.ipv4.port; - ia.s_addr=htonl(resp.mappedAddress.ipv4.addr); - }else return -1; - strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE); - } - return len; -} - -/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ -int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ - const char *server=linphone_core_get_stun_server(lc); - StunCandidate *ac=&call->ac; - StunCandidate *vc=&call->vc; - - if (lc->sip_conf.ipv6_enabled){ - ms_warning("stun support is not implemented for ipv6"); - return -1; - } - if (server!=NULL){ - struct sockaddr_storage ss; - socklen_t ss_len; - ortp_socket_t sock1=-1, sock2=-1; - int loops=0; - bool_t video_enabled=linphone_core_video_enabled(lc); - bool_t got_audio,got_video; - bool_t cone_audio=FALSE,cone_video=FALSE; - struct timeval init,cur; - 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); - return -1; - } - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("Stun lookup in progress...")); - - /*create the two audio and video RTP sockets, and send STUN message to our stun server */ - sock1=create_socket(call->audio_port); - if (sock1==-1) return -1; - if (video_enabled){ - sock2=create_socket(call->video_port); - if (sock2==-1) return -1; - } - got_audio=FALSE; - got_video=FALSE; - 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); - if (sock2!=-1){ - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE); - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE); - } - } -#ifdef WIN32 - Sleep(10); -#else - usleep(10000); -#endif - - if (recvStunResponse(sock1,ac->addr, - &ac->port,&id)>0){ - ms_message("STUN test result: local audio port maps to %s:%i", - ac->addr, - ac->port); - if (id==11) - cone_audio=TRUE; - got_audio=TRUE; - } - if (recvStunResponse(sock2,vc->addr, - &vc->port,&id)>0){ - ms_message("STUN test result: local video port maps to %s:%i", - vc->addr, - vc->port); - if (id==22) - cone_video=TRUE; - got_video=TRUE; - } - 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."); - ret=-1; - break; - } - loops++; - }while(!(got_audio && (got_video||sock2==-1) ) ); - if (ret==0) ret=(int)elapsed; - if (!got_audio){ - ms_error("No stun server response for audio port."); - }else{ - if (!cone_audio) { - ms_message("NAT is symmetric for audio port"); - } - } - if (sock2!=-1){ - if (!got_video){ - ms_error("No stun server response for video port."); - }else{ - if (!cone_video) { - ms_message("NAT is symmetric for video port."); - } - } - } - close_socket(sock1); - if (sock2!=-1) close_socket(sock2); - return ret; - } - return -1; -} - -int linphone_core_get_edge_bw(LinphoneCore *lc){ - int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20); - return edge_bw; -} - -int linphone_core_get_edge_ptime(LinphoneCore *lc){ - int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100); - return edge_ptime; -} - -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); - threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); - - if (ping_time_ms>threshold){ - /* we might be in a 2G network*/ - params->low_bandwidth=TRUE; - }/*else use default settings */ - } - if (params->low_bandwidth){ - params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc); - params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc); - params->has_video=FALSE; - } -} - - - -int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) -{ - char local_addr[64]; - struct sockaddr_storage ss; - socklen_t ss_len; - IceCheckList *audio_check_list; - IceCheckList *video_check_list; - const char *server = linphone_core_get_stun_server(lc); - - if ((server == NULL) || (call->ice_session == NULL)) return -1; - audio_check_list = ice_session_check_list(call->ice_session, 0); - video_check_list = ice_session_check_list(call->ice_session, 1); - if (audio_check_list == NULL) return -1; - - if (lc->sip_conf.ipv6_enabled){ - ms_warning("stun support is not implemented for ipv6"); - return -1; - } - - if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) { - ms_error("Fail to parser stun server address: %s", server); - 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) { - ms_error("Fail to get local ip"); - return -1; - } - if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { - ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); - ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; - } - if (call->params.has_video && (video_check_list != NULL) - && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { - ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); - ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; - } - - ms_message("ICE: gathering candidate from [%s]",server); - /* Gather local srflx candidates. */ - ice_session_gather_candidates(call->ice_session, ss, ss_len); - return 0; -} - -void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) -{ - IceCheckList *audio_check_list; - IceCheckList *video_check_list; - IceSessionState session_state; - - if (call->ice_session == NULL) return; - audio_check_list = ice_session_check_list(call->ice_session, 0); - video_check_list = ice_session_check_list(call->ice_session, 1); - if (audio_check_list == NULL) return; - - session_state = ice_session_state(call->ice_session); - if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) { - if (ice_check_list_state(audio_check_list) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { - case ICT_HostCandidate: - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection; - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection; - break; - case ICT_RelayedCandidate: - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection; - break; - } - } else { - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; - } - if (call->params.has_video && (video_check_list != NULL)) { - if (ice_check_list_state(video_check_list) == ICL_Completed) { - switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { - case ICT_HostCandidate: - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection; - break; - case ICT_ServerReflexiveCandidate: - case ICT_PeerReflexiveCandidate: - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection; - break; - case ICT_RelayedCandidate: - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection; - break; - } - } else { - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; - } - } - } else if (session_state == IS_Running) { - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; - if (call->params.has_video && (video_check_list != NULL)) { - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; - } - } else { - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; - if (call->params.has_video && (video_check_list != NULL)) { - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; - } - } -} - -void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) -{ - const char *rtp_addr, *rtcp_addr; - IceSessionState session_state = ice_session_state(session); - int nb_candidates; - int i, j; - bool_t result; - - if (session_state == IS_Completed) { - desc->ice_completed = TRUE; - result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); - if (result == TRUE) { - strncpy(desc->addr, rtp_addr, sizeof(desc->addr)); - } else { - ms_warning("If ICE has completed successfully, rtp_addr should be set!"); - } - } - else { - desc->ice_completed = FALSE; - } - strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); - strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); - for (i = 0; i < desc->n_active_streams; i++) { - SalStreamDescription *stream = &desc->streams[i]; - IceCheckList *cl = ice_session_check_list(session, i); - nb_candidates = 0; - if (cl == NULL) continue; - if (ice_check_list_state(cl) == ICL_Completed) { - stream->ice_completed = TRUE; - result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); - } else { - stream->ice_completed = FALSE; - result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); - } - if (result == TRUE) { - strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr)); - strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr)); - } else { - memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); - memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); - } - if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) - strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); - else - memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); - if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag))) - strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); - else - memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); - stream->ice_mismatch = ice_check_list_is_mismatch(cl); - if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { - memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); - for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { - SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; - IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j); - const char *default_addr = NULL; - int default_port = 0; - if (ice_candidate->componentID == 1) { - default_addr = stream->rtp_addr; - default_port = stream->rtp_port; - } else if (ice_candidate->componentID == 2) { - default_addr = stream->rtcp_addr; - default_port = stream->rtcp_port; - } else continue; - if (default_addr[0] == '\0') default_addr = desc->addr; - /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ - if ((ice_check_list_state(cl) == ICL_Completed) - && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0))) - continue; - strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation)); - sal_candidate->componentID = ice_candidate->componentID; - sal_candidate->priority = ice_candidate->priority; - strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type)); - strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr)); - sal_candidate->port = ice_candidate->taddr.port; - if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) { - strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr)); - sal_candidate->rport = ice_candidate->base->taddr.port; - } - nb_candidates++; - } - } - if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { - int rtp_port, rtcp_port; - memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); - if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) { - strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr)); - stream->ice_remote_candidates[0].port = rtp_port; - strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr)); - stream->ice_remote_candidates[1].port = rtcp_port; - } else { - ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state"); - } - } else { - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { - stream->ice_remote_candidates[j].addr[0] = '\0'; - stream->ice_remote_candidates[j].port = 0; - } - } - } -} - -static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) -{ - if (componentID == 1) { - *addr = stream->rtp_addr; - *port = stream->rtp_port; - } else if (componentID == 2) { - *addr = stream->rtcp_addr; - *port = stream->rtcp_port; - } else return; - if ((*addr)[0] == '\0') *addr = md->addr; -} - -void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) -{ - bool_t ice_restarted = FALSE; - - if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { - int i, j; - - /* Check for ICE restart and set remote credentials. */ - if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) { - ice_session_restart(call->ice_session); - ice_restarted = TRUE; - } else { - for (i = 0; i < md->n_total_streams; i++) { - const SalStreamDescription *stream = &md->streams[i]; - IceCheckList *cl = ice_session_check_list(call->ice_session, i); - if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { - ice_session_restart(call->ice_session); - ice_restarted = TRUE; - break; - } - } - } - if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) { - ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); - } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) { - if (ice_restarted == FALSE) { - ice_session_restart(call->ice_session); - ice_restarted = TRUE; - } - ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); - } - for (i = 0; i < md->n_total_streams; i++) { - const SalStreamDescription *stream = &md->streams[i]; - IceCheckList *cl = ice_session_check_list(call->ice_session, i); - if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { - if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { - if (ice_restarted == FALSE) { - ice_session_restart(call->ice_session); - ice_restarted = TRUE; - } - ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); - break; - } - } - } - - /* Create ICE check lists if needed and parse ICE attributes. */ - for (i = 0; i < md->n_total_streams; i++) { - const SalStreamDescription *stream = &md->streams[i]; - IceCheckList *cl = ice_session_check_list(call->ice_session, i); - if (cl == NULL) { - cl = ice_check_list_new(); - ice_session_add_check_list(call->ice_session, cl); - switch (stream->type) { - case SalAudio: - if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = cl; - break; - case SalVideo: - if (call->videostream != NULL) call->videostream->ms.ice_check_list = cl; - break; - default: - break; - } - } - if (stream->ice_mismatch == TRUE) { - ice_check_list_set_state(cl, ICL_Failed); - } else if (stream->rtp_port == 0) { - ice_session_remove_check_list(call->ice_session, cl); - } 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); - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { - const SalIceCandidate *candidate = &stream->ice_candidates[j]; - bool_t default_candidate = FALSE; - const char *addr = NULL; - int port = 0; - if (candidate->addr[0] == '\0') break; - if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue; - get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port); - if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) - default_candidate = TRUE; - ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, - candidate->priority, candidate->foundation, default_candidate); - } - if (ice_restarted == FALSE) { - bool_t losing_pairs_added = FALSE; - for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { - const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j]; - const char *addr = NULL; - int port = 0; - int componentID = j + 1; - if (candidate->addr[0] == '\0') break; - get_default_addr_and_port(componentID, md, stream, &addr, &port); - if (j == 0) { - /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ - ice_check_list_unselect_valid_pairs(cl); - } - ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port); - losing_pairs_added = TRUE; - } - if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl); - } - } - } - for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { - ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); - } - ice_session_check_mismatch(call->ice_session); - } else { - /* Response from remote does not contain mandatory ICE attributes, delete the session. */ - linphone_call_delete_ice_session(call); - return; - } - if (ice_session_nb_check_lists(call->ice_session) == 0) { - linphone_call_delete_ice_session(call); - } -} - -bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md) -{ - int i; - - for (i = 0; i < md->n_active_streams; i++) { - if (md->streams[i].type == SalVideo) - return TRUE; - } - return FALSE; -} - -LinphoneCall * is_a_linphone_call(void *user_pointer){ - LinphoneCall *call=(LinphoneCall*)user_pointer; - if (call==NULL) return NULL; - return call->magic==linphone_call_magic ? call : NULL; -} - -LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer; - if (cfg==NULL) return NULL; - return cfg->magic==linphone_proxy_config_magic ? cfg : NULL; -} - -unsigned int linphone_core_get_audio_features(LinphoneCore *lc){ - unsigned int ret=0; - const char *features=lp_config_get_string(lc->config,"sound","features",NULL); - if (features){ - char tmp[256]={0}; - char name[256]; - char *p,*n; - strncpy(tmp,features,sizeof(tmp)-1); - for(p=tmp;*p!='\0';p++){ - if (*p==' ') continue; - n=strchr(p,'|'); - if (n) *n='\0'; - sscanf(p,"%s",name); - ms_message("Found audio feature %s",name); - if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC; - else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC; - else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER; - else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND; - else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV; - else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF; - else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO; - else if (strcasecmp(name,"MIXED_RECORDING")==0) ret|=AUDIO_STREAM_FEATURE_MIXED_RECORDING; - else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL; - else if (strcasecmp(name,"NONE")==0) ret=0; - else ms_error("Unsupported audio feature %s requested in config file.",name); - if (!n) break; - p=n; - } - }else ret=AUDIO_STREAM_FEATURE_ALL; - - if (ret==AUDIO_STREAM_FEATURE_ALL){ - /*since call recording is specified before creation of the stream in linphonecore, - * it will be requested on demand. It is not necessary to include it all the time*/ - ret&=~AUDIO_STREAM_FEATURE_MIXED_RECORDING; - } - return ret; -} - - -#ifdef HAVE_GETIFADDRS - -#include -static int get_local_ip_with_getifaddrs(int type, char *address, int size) -{ - struct ifaddrs *ifp; - struct ifaddrs *ifpstart; - int ret = 0; - - if (getifaddrs(&ifpstart) < 0) { - return -1; - } -#ifndef __linux - #define UP_FLAG IFF_UP /* interface is up */ -#else - #define UP_FLAG IFF_RUNNING /* resources allocated */ -#endif - - for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) { - if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type - && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK)) - { - if(getnameinfo(ifp->ifa_addr, - (type == AF_INET6) ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), - address, size, NULL, 0, NI_NUMERICHOST) == 0) { - if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */ - /*ms_message("getifaddrs() found %s",address);*/ - ret++; - break; - } - } - } - } - freeifaddrs(ifpstart); - return ret; -} -#endif - - -static int get_local_ip_for_with_connect(int type, const char *dest, char *result){ - int err,tmp; - struct addrinfo hints; - struct addrinfo *res=NULL; - struct sockaddr_storage addr; - struct sockaddr *p_addr=(struct sockaddr*)&addr; - ortp_socket_t sock; - socklen_t s; - - memset(&hints,0,sizeof(hints)); - hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET; - hints.ai_socktype=SOCK_DGRAM; - /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/ - err=getaddrinfo(dest,"5060",&hints,&res); - if (err!=0){ - ms_error("getaddrinfo() error: %s",gai_strerror(err)); - return -1; - } - if (res==NULL){ - ms_error("bug: getaddrinfo returned nothing."); - return -1; - } - sock=socket(res->ai_family,SOCK_DGRAM,0); - tmp=1; - err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int)); - if (err<0){ - ms_warning("Error in setsockopt: %s",strerror(errno)); - } - err=connect(sock,res->ai_addr,res->ai_addrlen); - if (err<0) { - ms_error("Error in connect: %s",strerror(errno)); - freeaddrinfo(res); - close_socket(sock); - return -1; - } - freeaddrinfo(res); - res=NULL; - s=sizeof(addr); - err=getsockname(sock,(struct sockaddr*)&addr,&s); - if (err!=0) { - ms_error("Error in getsockname: %s",strerror(errno)); - close_socket(sock); - return -1; - } - if (p_addr->sa_family==AF_INET){ - struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr; - if (p_sin->sin_addr.s_addr==0){ - close_socket(sock); - return -1; - } - } - err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST); - if (err!=0){ - ms_error("getnameinfo error: %s",strerror(errno)); - } - close_socket(sock); - ms_message("Local interface to reach %s is %s.",dest,result); - return 0; -} - -int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ - strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); -#ifdef HAVE_GETIFADDRS - if (dest==NULL) { - /*we use getifaddrs for lookup of default interface */ - int found_ifs; - - found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE); - if (found_ifs==1){ - return 0; - }else if (found_ifs<=0){ - /*absolutely no network on this machine */ - return -1; - } - } -#endif - /*else use connect to find the best local ip address */ - if (type==AF_INET) - dest="87.98.157.38"; /*a public IP address*/ - else dest="2a00:1450:8002::68"; - return get_local_ip_for_with_connect(type,dest,result); -} - -#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 + +/* +linphone +Copyright (C) 2000 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" +#include "mediastreamer2/mediastream.h" +#include +#include +#ifdef HAVE_SIGHANDLER_T +#include +#endif /*HAVE_SIGHANDLER_T*/ + +#include +#if !defined(_WIN32_WCE) +#include +#include +#include +#if _MSC_VER +#include +#else +#include +#endif +#include +#endif /*_WIN32_WCE*/ + +#undef snprintf +#include + +#ifdef HAVE_GETIFADDRS +#include +#include +#endif +#include +#if _MSC_VER +#define snprintf _snprintf +#define popen _popen +#define pclose _pclose +#endif + + +#define UDP_HDR_SZ 8 +#define RTP_HDR_SZ 12 +#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ + +static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed); + +bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const LinphonePayloadType *pt){ + if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ + return payload_type_enabled(pt); + } + ms_error("Getting enablement status of codec not in audio or video list of PayloadType !"); + return FALSE; +} + +bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayloadType *pt){ + if (pt->type==PAYLOAD_VIDEO) return TRUE; + return !!(pt->flags & PAYLOAD_TYPE_IS_VBR); +} + +int linphone_core_enable_payload_type(LinphoneCore *lc, LinphonePayloadType *pt, bool_t enabled){ + if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ + payload_type_set_enable(pt,enabled); + _linphone_core_codec_config_write(lc); + linphone_core_update_allocated_audio_bandwidth(lc); + return 0; + } + ms_error("Enabling codec not in audio or video list of PayloadType !"); + return -1; +} + +int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){ + return payload_type_get_number(pt); +} + +void linphone_core_set_payload_type_number(LinphoneCore *lc, PayloadType *pt, int number){ + payload_type_set_number(pt,number); +} + +const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){ + if (ms_filter_codec_supported(pt->mime_type)){ + MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type); +#ifdef ENABLE_NLS + return dgettext("mediastreamer",desc->text); +#else + return desc->text; +#endif + } + return NULL; +} + +void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, LinphonePayloadType *pt, int bitrate){ + if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ + if (pt->type==PAYLOAD_VIDEO || pt->flags & PAYLOAD_TYPE_IS_VBR){ + pt->normal_bitrate=bitrate*1000; + pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE; + linphone_core_update_allocated_audio_bandwidth(lc); + }else{ + ms_error("Cannot set an explicit bitrate for codec %s/%i, because it is not VBR.",pt->mime_type,pt->clock_rate); + return; + } + } else { + ms_error("linphone_core_set_payload_type_bitrate() payload type not in audio or video list !"); + } +} + + +/* + *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; + *ptime=1/npacket + */ + +static double get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType *pt){ + double npacket=50; + double packet_size; + int bitrate; + + if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) { + /*special case of aac 44K because ptime= 10ms*/ + npacket=100; + }else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt))==0) { + npacket=1000/30.0; + } + + bitrate=pt->normal_bitrate; + packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; + return packet_size*8.0*npacket; +} + +typedef struct vbr_codec_bitrate{ + int max_avail_bitrate; + int min_rate; + int recomended_bitrate; +}vbr_codec_bitrate_t; + +static vbr_codec_bitrate_t defauls_vbr[]={ + //{ 100, 44100, 100 }, + { 64, 44100, 50 }, + { 64, 16000, 40 }, + { 32, 16000, 32 }, + { 32, 8000, 32 }, + { 0 , 8000, 24 }, + { 0 , 0, 0 } +}; + +static int lookup_vbr_typical_bitrate(int maxbw, int clock_rate){ + vbr_codec_bitrate_t *it; + if (maxbw<=0) maxbw=defauls_vbr[0].max_avail_bitrate; + for(it=defauls_vbr;it->min_rate!=0;it++){ + if (maxbw>=it->max_avail_bitrate && clock_rate>=it->min_rate) + return it->recomended_bitrate; + } + ms_error("lookup_vbr_typical_bitrate(): should not happen."); + return 32; +} + +static int get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt, int maxbw){ + if (linphone_core_payload_type_is_vbr(lc,pt)){ + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ + ms_debug("PayloadType %s/%i has bitrate override",pt->mime_type,pt->clock_rate); + return pt->normal_bitrate/1000; + } + return lookup_vbr_typical_bitrate(maxbw,pt->clock_rate); + }else return (int)ceil(get_audio_payload_bandwidth_from_codec_bitrate(pt)/1000.0);/*rounding codec bandwidth should be avoid, specially for AMR*/ +} + +int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const LinphonePayloadType *pt){ + int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED){ + return get_audio_payload_bandwidth(lc,pt,maxbw); + }else if (pt->type==PAYLOAD_VIDEO){ + int video_bw; + if (maxbw<=0) { + video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/ + }else{ + video_bw=get_remaining_bandwidth_for_video(maxbw,lc->audio_bw); + } + return video_bw; + } + return 0; +} + +void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw){ + call->audio_bw=get_audio_payload_bandwidth(call->core,pt,maxbw); + ms_message("Audio bandwidth for this call is %i",call->audio_bw); +} + +void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ + const MSList *elem; + int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + int max_codec_bitrate=0; + + for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if (payload_type_enabled(pt)){ + int pt_bitrate=get_audio_payload_bandwidth(lc,pt,maxbw); + if (max_codec_bitrate==0) { + max_codec_bitrate=pt_bitrate; + }else if (max_codec_bitrateaudio_bw=max_codec_bitrate; + } +} + +bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit){ + double codec_band; + const int video_enablement_limit = 99; + bool_t ret=FALSE; + + switch (pt->type){ + case PAYLOAD_AUDIO_CONTINUOUS: + case PAYLOAD_AUDIO_PACKETIZED: + codec_band=get_audio_payload_bandwidth(lc,pt,bandwidth_limit); + ret=bandwidth_is_greater(bandwidth_limit,codec_band); + /*ms_message("Payload %s: codec_bandwidth=%g, bandwidth_limit=%i",pt->mime_type,codec_band,bandwidth_limit);*/ + break; + case PAYLOAD_VIDEO: + if (bandwidth_limit<=0 || bandwidth_limit >= video_enablement_limit) {/* infinite or greater than video_enablement_limit*/ + ret=TRUE; + } + else ret=FALSE; + break; + } + return ret; +} + +/* return TRUE if codec can be used with bandwidth, FALSE else*/ +bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt){ + int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + bool_t ret=linphone_core_is_payload_type_usable_for_bandwidth(lc, pt, maxbw); + if ((pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED) + && lc->sound_conf.capt_sndcard + && !(ms_snd_card_get_capabilities(lc->sound_conf.capt_sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) + && linphone_core_echo_cancellation_enabled(lc) + && (pt->clock_rate!=16000 && pt->clock_rate!=8000) + && strcasecmp(pt->mime_type,"opus")!=0 + && ms_filter_lookup_by_name("MSWebRTCAEC")!=NULL){ + ms_warning("Payload type %s/%i cannot be used because software echo cancellation is required but is unable to operate at this rate.", + pt->mime_type,pt->clock_rate); + ret=FALSE; + } + return ret; +} + +bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){ +#if !defined(_WIN32_WCE) && !defined(LINPHONE_WINDOWS_UNIVERSAL) + FILE *f=popen(command,"r"); + if (f!=NULL){ + int err; + *result=ms_malloc(4096); + err=fread(*result,1,4096-1,f); + if (err<0){ + ms_warning("Error reading command output:%s",strerror(errno)); + ms_free(result); + return FALSE; + } + (*result)[err]=0; + err=pclose(f); + if (command_ret!=NULL) *command_ret=err; + return TRUE; + } +#endif /*_WIN32_WCE*/ + return FALSE; +} + +static ortp_socket_t create_socket(int local_port){ + struct sockaddr_in laddr; + ortp_socket_t sock; + int optval; + sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); + if (sock<0) { + ms_error("Fail to create socket"); + return -1; + } + memset (&laddr,0,sizeof(laddr)); + laddr.sin_family=AF_INET; + laddr.sin_addr.s_addr=INADDR_ANY; + laddr.sin_port=htons(local_port); + if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){ + ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError()); + close_socket(sock); + return -1; + } + optval=1; + if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){ + ms_warning("Fail to set SO_REUSEADDR"); + } + set_non_blocking_socket(sock); + return sock; +} + +static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){ + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = STUN_MAX_MESSAGE_SIZE; + StunAtrString username; + StunAtrString password; + StunMessage req; + int err; + memset(&req, 0, sizeof(StunMessage)); + memset(&username,0,sizeof(username)); + memset(&password,0,sizeof(password)); + stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id); + len = stunEncodeMessage( &req, buf, len, &password); + if (len<=0){ + ms_error("Fail to encode stun message."); + return -1; + } + err=sendto(sock,buf,len,0,server,addrlen); + if (err<0){ + ms_error("sendto failed: %s",strerror(errno)); + return -1; + } + return 0; +} + +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(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) { + + } else { + 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=AF_UNSPEC; + hints.ai_socktype=SOCK_DGRAM; + hints.ai_protocol=IPPROTO_UDP; + ret=getaddrinfo(host,port,&hints,&res); + if (ret!=0){ + ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret)); + return -1; + } + if (!res) return -1; + memcpy(ss,res->ai_addr,res->ai_addrlen); + *socklen=res->ai_addrlen; + freeaddrinfo(res); + return 0; +} + +static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){ + char buf[STUN_MAX_MESSAGE_SIZE]; + int len = STUN_MAX_MESSAGE_SIZE; + StunMessage resp; + len=recv(sock,buf,len,0); + if (len>0){ + struct in_addr ia; + stunParseMessage(buf,len, &resp ); + *id=resp.msgHdr.tr_id.octet[0]; + if (resp.hasXorMappedAddress){ + *port = resp.xorMappedAddress.ipv4.port; + ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr); + }else if (resp.hasMappedAddress){ + *port = resp.mappedAddress.ipv4.port; + ia.s_addr=htonl(resp.mappedAddress.ipv4.addr); + }else return -1; + strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE); + } + return len; +} + +/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ +int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ + const char *server=linphone_core_get_stun_server(lc); + StunCandidate *ac=&call->ac; + StunCandidate *vc=&call->vc; + + if (lc->sip_conf.ipv6_enabled){ + ms_warning("stun support is not implemented for ipv6"); + return -1; + } + if (call->media_ports[0].rtp_port==-1){ + ms_warning("Stun-only support not available for system random port"); + return -1; + } + if (server!=NULL){ + const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); + ortp_socket_t sock1=-1, sock2=-1; + int loops=0; + bool_t video_enabled=linphone_core_video_enabled(lc); + bool_t got_audio,got_video; + bool_t cone_audio=FALSE,cone_video=FALSE; + struct timeval init,cur; + double elapsed; + int ret=0; + + if (ai==NULL){ + ms_error("Could not obtain stun server addrinfo."); + return -1; + } + linphone_core_notify_display_status(lc,_("Stun lookup in progress...")); + + /*create the two audio and video RTP sockets, and send STUN message to our stun server */ + sock1=create_socket(call->media_ports[0].rtp_port); + if (sock1==-1) return -1; + if (video_enabled){ + sock2=create_socket(call->media_ports[1].rtp_port); + if (sock2==-1) return -1; + } + got_audio=FALSE; + got_video=FALSE; + ortp_gettimeofday(&init,NULL); + do{ + + int id; + if (loops%20==0){ + ms_message("Sending stun requests..."); + 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,ai->ai_addr,ai->ai_addrlen,22,TRUE); + sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE); + } + } + ms_usleep(10000); + + if (recvStunResponse(sock1,ac->addr, + &ac->port,&id)>0){ + ms_message("STUN test result: local audio port maps to %s:%i", + ac->addr, + ac->port); + if (id==11) + cone_audio=TRUE; + got_audio=TRUE; + } + if (recvStunResponse(sock2,vc->addr, + &vc->port,&id)>0){ + ms_message("STUN test result: local video port maps to %s:%i", + vc->addr, + vc->port); + if (id==22) + cone_video=TRUE; + got_video=TRUE; + } + 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."); + ret=-1; + break; + } + loops++; + }while(!(got_audio && (got_video||sock2==-1) ) ); + if (ret==0) ret=(int)elapsed; + if (!got_audio){ + ms_error("No stun server response for audio port."); + }else{ + if (!cone_audio) { + ms_message("NAT is symmetric for audio port"); + } + } + if (sock2!=-1){ + if (!got_video){ + ms_error("No stun server response for video port."); + }else{ + if (!cone_video) { + ms_message("NAT is symmetric for video port."); + } + } + } + close_socket(sock1); + if (sock2!=-1) close_socket(sock2); + return ret; + } + return -1; +} + +int linphone_core_get_edge_bw(LinphoneCore *lc){ + int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20); + return edge_bw; +} + +int linphone_core_get_edge_ptime(LinphoneCore *lc){ + int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100); + return edge_ptime; +} + +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); + threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); + + if (ping_time_ms>threshold){ + /* we might be in a 2G network*/ + params->low_bandwidth=TRUE; + }/*else use default settings */ + } + if (params->low_bandwidth){ + params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc); + params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc); + params->has_video=FALSE; + } +} + +static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addrinfo *addrinfo){ + if (lc->net_conf.stun_addrinfo){ + belle_sip_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){ + /* + * WARNING: stun server resolution only done in IPv4. + * TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering. + */ + const char *server=lc->net_conf.stun_server; + if (lc->sal && server && !lc->net_conf.stun_res){ + 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_INET,(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]; + const struct addrinfo *ai; + IceCheckList *audio_check_list; + IceCheckList *video_check_list; + const char *server = linphone_core_get_stun_server(lc); + + if ((server == NULL) || (call->ice_session == NULL)) return -1; + audio_check_list = ice_session_check_list(call->ice_session, 0); + video_check_list = ice_session_check_list(call->ice_session, 1); + if (audio_check_list == NULL) return -1; + + if (call->af==AF_INET6){ + ms_warning("Ice gathering is not implemented for ipv6"); + return -1; + } + ai=linphone_core_get_stun_server_addrinfo(lc); + if (ai==NULL){ + ms_warning("Fail to resolve STUN server for ICE gathering."); + return -1; + } + linphone_core_notify_display_status(lc, _("ICE local candidates gathering in progress...")); + + /* Gather local host candidates. */ + if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { + ms_error("Fail to get local ip"); + return -1; + } + if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL); + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; + } + if (linphone_core_video_enabled(lc) && (video_check_list != NULL) + && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL); + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; + } + + ms_message("ICE: gathering candidate from [%s]",server); + /* Gather local srflx candidates. */ + ice_session_gather_candidates(call->ice_session, ai->ai_addr, ai->ai_addrlen); + return 0; +} + +const char *linphone_ice_state_to_string(LinphoneIceState state){ + switch(state){ + case LinphoneIceStateFailed: + return "IceStateFailed"; + case LinphoneIceStateHostConnection: + return "IceStateHostConnection"; + case LinphoneIceStateInProgress: + return "IceStateInProgress"; + case LinphoneIceStateNotActivated: + return "IceStateNotActivated"; + case LinphoneIceStateReflexiveConnection: + return "IceStateReflexiveConnection"; + case LinphoneIceStateRelayConnection: + return "IceStateRelayConnection"; + } + return "invalid"; +} + +void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) +{ + IceCheckList *audio_check_list; + IceCheckList *video_check_list; + IceSessionState session_state; + + if (call->ice_session == NULL) return; + audio_check_list = ice_session_check_list(call->ice_session, 0); + video_check_list = ice_session_check_list(call->ice_session, 1); + if (audio_check_list == NULL) return; + + session_state = ice_session_state(call->ice_session); + if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) { + if (ice_check_list_state(audio_check_list) == ICL_Completed) { + switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { + case ICT_HostCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection; + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection; + break; + case ICT_RelayedCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection; + break; + } + } else { + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; + } + if (call->params->has_video && (video_check_list != NULL)) { + if (ice_check_list_state(video_check_list) == ICL_Completed) { + switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { + case ICT_HostCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection; + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection; + break; + case ICT_RelayedCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection; + break; + } + } else { + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; + } + }else call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated; + } else if (session_state == IS_Running) { + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; + if (call->params->has_video && (video_check_list != NULL)) { + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; + } + } else { + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; + if (call->params->has_video && (video_check_list != NULL)) { + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; + } + } + ms_message("Call [%p] New ICE state: audio: [%s] video: [%s]", call, + linphone_ice_state_to_string(call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state), linphone_ice_state_to_string(call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state)); +} + +void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call) { + int i; + IceSession *session = call->ice_session; + SalMediaDescription *desc = call->localdesc; + + if (session == NULL) return; + if (ice_session_state(session) == IS_Completed) return; + + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + IceCheckList *cl = ice_session_check_list(session, i); + if (!sal_stream_description_active(&desc->streams[i]) && cl) { + ice_session_remove_check_list(session, cl); + clear_ice_check_list(call, cl); + } + } + + linphone_core_update_ice_state_in_call_stats(call); +} + +void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) { + const char *rtp_addr, *rtcp_addr; + IceSessionState session_state = ice_session_state(session); + int nb_candidates; + int i, j; + bool_t result; + + if (session_state == IS_Completed) { + desc->ice_completed = TRUE; + result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL); + if (result == TRUE) { + strncpy(desc->addr, rtp_addr, sizeof(desc->addr)); + } else { + ms_warning("If ICE has completed successfully, rtp_addr should be set!"); + } + } + else { + desc->ice_completed = FALSE; + } + strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); + strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); + for (i = 0; i < desc->nb_streams; i++) { + SalStreamDescription *stream = &desc->streams[i]; + IceCheckList *cl = ice_session_check_list(session, i); + nb_candidates = 0; + if (!sal_stream_description_active(stream) || (cl == NULL)) continue; + if (ice_check_list_state(cl) == ICL_Completed) { + stream->ice_completed = TRUE; + result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + } else { + stream->ice_completed = FALSE; + result = ice_check_list_default_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); + } + if (result == TRUE) { + strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr)); + strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr)); + } else { + memset(stream->rtp_addr, 0, sizeof(stream->rtp_addr)); + memset(stream->rtcp_addr, 0, sizeof(stream->rtcp_addr)); + } + if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd))) + strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag))) + strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag)); + else + memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd)); + stream->ice_mismatch = ice_check_list_is_mismatch(cl); + if ((ice_check_list_state(cl) == ICL_Running) || (ice_check_list_state(cl) == ICL_Completed)) { + memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates)); + for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) { + SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates]; + IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j); + const char *default_addr = NULL; + int default_port = 0; + if (ice_candidate->componentID == 1) { + default_addr = stream->rtp_addr; + default_port = stream->rtp_port; + } else if (ice_candidate->componentID == 2) { + default_addr = stream->rtcp_addr; + default_port = stream->rtcp_port; + } else continue; + if (default_addr[0] == '\0') default_addr = desc->addr; + /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */ + if ((ice_check_list_state(cl) == ICL_Completed) + && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0))) + continue; + strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation)); + sal_candidate->componentID = ice_candidate->componentID; + sal_candidate->priority = ice_candidate->priority; + strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type)); + strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr)); + sal_candidate->port = ice_candidate->taddr.port; + if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) { + strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr)); + sal_candidate->rport = ice_candidate->base->taddr.port; + } + nb_candidates++; + } + } + if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) { + int rtp_port, rtcp_port; + memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates)); + if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) { + strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr)); + stream->ice_remote_candidates[0].port = rtp_port; + strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr)); + stream->ice_remote_candidates[1].port = rtcp_port; + } else { + ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state"); + } + } else { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { + stream->ice_remote_candidates[j].addr[0] = '\0'; + stream->ice_remote_candidates[j].port = 0; + } + } + } +} + +static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port) +{ + if (componentID == 1) { + *addr = stream->rtp_addr; + *port = stream->rtp_port; + } else if (componentID == 2) { + *addr = stream->rtcp_addr; + *port = stream->rtcp_port; + } else return; + if ((*addr)[0] == '\0') *addr = md->addr; +} + +static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){ + if (call->audiostream && call->audiostream->ms.ice_check_list==removed) + call->audiostream->ms.ice_check_list=NULL; + if (call->videostream && call->videostream->ms.ice_check_list==removed) + call->videostream->ms.ice_check_list=NULL; +} + +void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) +{ + bool_t ice_restarted = FALSE; + bool_t ice_params_found=FALSE; + if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) { + ice_params_found=TRUE; + } else { + int i; + for (i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl) { + if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { + ice_params_found=TRUE; + } else { + ice_params_found=FALSE; + break; + } + } + } + } + if (ice_params_found) { + int i, j; + + /* Check for ICE restart and set remote credentials. */ + if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } else { + for (i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + break; + } + } + } + if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) { + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) { + if (ice_restarted == FALSE) { + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } + ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); + } + for (i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { + if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { + if (ice_restarted == FALSE + && ice_check_list_get_remote_ufrag(cl) + && ice_check_list_get_remote_pwd(cl)) { + /* restart onlu if remote ufrag/paswd was already set*/ + ice_session_restart(call->ice_session); + ice_restarted = TRUE; + } + ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); + break; + } + } + } + + /* Create ICE check lists if needed and parse ICE attributes. */ + for (i = 0; i < md->nb_streams; i++) { + const SalStreamDescription *stream = &md->streams[i]; + IceCheckList *cl = ice_session_check_list(call->ice_session, i); + /* + if ((cl == NULL) && (i < md->n_active_streams)) { + cl = ice_check_list_new(); + ice_session_add_check_list(call->ice_session, cl); + switch (stream->type) { + case SalAudio: + if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = cl; + break; + case SalVideo: + if (call->videostream != NULL) call->videostream->ms.ice_check_list = cl; + break; + default: + break; + } + } + */ + if (cl==NULL) continue; + if (stream->ice_mismatch == TRUE) { + ice_check_list_set_state(cl, ICL_Failed); + } else if (stream->rtp_port == 0) { + ice_session_remove_check_list(call->ice_session, cl); + clear_ice_check_list(call,cl); + } 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); + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { + const SalIceCandidate *candidate = &stream->ice_candidates[j]; + bool_t default_candidate = FALSE; + const char *addr = NULL; + int port = 0; + if (candidate->addr[0] == '\0') break; + if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue; + get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port); + if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) + default_candidate = TRUE; + ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID, + candidate->priority, candidate->foundation, default_candidate); + } + if (ice_restarted == FALSE) { + bool_t losing_pairs_added = FALSE; + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) { + const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j]; + const char *addr = NULL; + int port = 0; + int componentID = j + 1; + if (candidate->addr[0] == '\0') break; + get_default_addr_and_port(componentID, md, stream, &addr, &port); + if (j == 0) { + /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ + ice_check_list_unselect_valid_pairs(cl); + } + ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port); + losing_pairs_added = TRUE; + } + if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl); + } + } + } + for (i = 0; i < md->nb_streams; i++) { + IceCheckList * cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(&md->streams[i]) && (cl != NULL)) { + ice_session_remove_check_list_from_idx(call->ice_session, i); + clear_ice_check_list(call, cl); + } + } + ice_session_check_mismatch(call->ice_session); + } else { + /* Response from remote does not contain mandatory ICE attributes, delete the session. */ + linphone_call_delete_ice_session(call); + return; + } + if (ice_session_nb_check_lists(call->ice_session) == 0) { + linphone_call_delete_ice_session(call); + } +} + +bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){ + int i; + + for (i = 0; md && i < md->nb_streams; i++) { + if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0) + return TRUE; + } + return FALSE; +} + +unsigned int linphone_core_get_audio_features(LinphoneCore *lc){ + unsigned int ret=0; + const char *features=lp_config_get_string(lc->config,"sound","features",NULL); + if (features){ + char tmp[256]={0}; + char name[256]; + char *p,*n; + strncpy(tmp,features,sizeof(tmp)-1); + for(p=tmp;*p!='\0';p++){ + if (*p==' ') continue; + n=strchr(p,'|'); + if (n) *n='\0'; + sscanf(p,"%s",name); + ms_message("Found audio feature %s",name); + if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC; + else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC; + else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER; + else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND; + else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV; + else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF; + else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO; + else if (strcasecmp(name,"MIXED_RECORDING")==0) ret|=AUDIO_STREAM_FEATURE_MIXED_RECORDING; + else if (strcasecmp(name,"LOCAL_PLAYING")==0) ret|=AUDIO_STREAM_FEATURE_LOCAL_PLAYING; + else if (strcasecmp(name,"REMOTE_PLAYING")==0) ret|=AUDIO_STREAM_FEATURE_REMOTE_PLAYING; + else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL; + else if (strcasecmp(name,"NONE")==0) ret=0; + else ms_error("Unsupported audio feature %s requested in config file.",name); + if (!n) break; + p=n; + } + }else ret=AUDIO_STREAM_FEATURE_ALL; + + if (ret==AUDIO_STREAM_FEATURE_ALL){ + /*since call recording is specified before creation of the stream in linphonecore, + * it will be requested on demand. It is not necessary to include it all the time*/ + ret&=~AUDIO_STREAM_FEATURE_MIXED_RECORDING; + } + return ret; +} + +bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){ + return lp_config_get_int(lc->config,"sound","tone_indications",1); +} + +#ifdef HAVE_GETIFADDRS + +#include +static int get_local_ip_with_getifaddrs(int type, char *address, int size){ + struct ifaddrs *ifp; + struct ifaddrs *ifpstart; + char retaddr[LINPHONE_IPADDR_SIZE]={0}; + bool_t found=FALSE; + + if (getifaddrs(&ifpstart) < 0) { + return -1; + } +#ifndef __linux + #define UP_FLAG IFF_UP /* interface is up */ +#else + #define UP_FLAG IFF_RUNNING /* resources allocated */ +#endif + + for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) { + if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type + && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK)) + { + if(getnameinfo(ifp->ifa_addr, + (type == AF_INET6) ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), + retaddr, size, NULL, 0, NI_NUMERICHOST) == 0) { + if (strchr(retaddr, '%') == NULL) { /*avoid ipv6 link-local addresses */ + /*ms_message("getifaddrs() found %s",address);*/ + found=TRUE; + break; + } + } + } + } + freeifaddrs(ifpstart); + if (found) strncpy(address,retaddr,size); + return found; +} +#endif + + +static int get_local_ip_for_with_connect(int type, const char *dest, char *result){ + int err,tmp; + struct addrinfo hints; + struct addrinfo *res=NULL; + struct sockaddr_storage addr; + struct sockaddr *p_addr=(struct sockaddr*)&addr; + ortp_socket_t sock; + socklen_t s; + + memset(&hints,0,sizeof(hints)); + hints.ai_family=type; + hints.ai_socktype=SOCK_DGRAM; + /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/ + err=getaddrinfo(dest,"5060",&hints,&res); + if (err!=0){ + ms_error("getaddrinfo() error for %s : %s",dest, gai_strerror(err)); + return -1; + } + if (res==NULL){ + ms_error("bug: getaddrinfo returned nothing."); + return -1; + } + sock=socket(res->ai_family,SOCK_DGRAM,0); + tmp=1; + err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int)); + if (err<0){ + ms_warning("Error in setsockopt: %s",strerror(errno)); + } + err=connect(sock,res->ai_addr,res->ai_addrlen); + if (err<0) { + /*the network isn't reachable*/ + if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno)); + freeaddrinfo(res); + close_socket(sock); + return -1; + } + freeaddrinfo(res); + res=NULL; + s=sizeof(addr); + err=getsockname(sock,(struct sockaddr*)&addr,&s); + if (err!=0) { + ms_error("Error in getsockname: %s",strerror(errno)); + close_socket(sock); + return -1; + } + if (p_addr->sa_family==AF_INET){ + struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr; + if (p_sin->sin_addr.s_addr==0){ + close_socket(sock); + return -1; + } + } + err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST); + if (err!=0){ + ms_error("getnameinfo error: %s",strerror(errno)); + } + /*avoid ipv6 link-local addresses*/ + if (p_addr->sa_family==AF_INET6 && strchr(result,'%')!=NULL){ + strcpy(result,"::1"); + close_socket(sock); + return -1; + } + close_socket(sock); + return 0; +} + +int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ + int err; +#ifdef HAVE_GETIFADDRS + int found_ifs; +#endif + strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); + + if (dest==NULL){ + if (type==AF_INET) + dest="87.98.157.38"; /*a public IP address*/ + else dest="2a00:1450:8002::68"; + } + err=get_local_ip_for_with_connect(type,dest,result); + if (err==0) return 0; + + /* if the connect method failed, which happens when no default route is set, + * try to find 'the' running interface with getifaddrs*/ + +#ifdef HAVE_GETIFADDRS + /*we use getifaddrs for lookup of default interface */ + found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE); + if (found_ifs==1){ + return 0; + }else if (found_ifs<=0){ + /*absolutely no network on this machine */ + return -1; + } +#endif + return 0; +} + +void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result) { + if (af == AF_UNSPEC) { + if (linphone_core_ipv6_enabled(lc)) { + bool_t has_ipv6 = linphone_core_get_local_ip_for(AF_INET6, dest, result) == 0; + if (strcmp(result, "::1") != 0) + return; /*this machine has real ipv6 connectivity*/ + if ((linphone_core_get_local_ip_for(AF_INET, dest, result) == 0) && (strcmp(result, "127.0.0.1") != 0)) + return; /*this machine has only ipv4 connectivity*/ + if (has_ipv6) { + /*this machine has only local loopback for both ipv4 and ipv6, so prefer ipv6*/ + strncpy(result, "::1", LINPHONE_IPADDR_SIZE); + return; + } + } + /*in all other cases use IPv4*/ + af = AF_INET; + } + linphone_core_get_local_ip_for(af, dest, result); +} + +SalReason linphone_reason_to_sal(LinphoneReason reason){ + switch(reason){ + case LinphoneReasonNone: + return SalReasonNone; + case LinphoneReasonNoResponse: + return SalReasonRequestTimeout; + case LinphoneReasonForbidden: + return SalReasonForbidden; + case LinphoneReasonDeclined: + return SalReasonDeclined; + case LinphoneReasonNotFound: + return SalReasonNotFound; + case LinphoneReasonTemporarilyUnavailable: + return SalReasonTemporarilyUnavailable; + case LinphoneReasonBusy: + return SalReasonBusy; + case LinphoneReasonNotAcceptable: + return SalReasonNotAcceptable; + case LinphoneReasonIOError: + return SalReasonServiceUnavailable; + case LinphoneReasonDoNotDisturb: + return SalReasonDoNotDisturb; + case LinphoneReasonUnauthorized: + return SalReasonUnauthorized; + case LinphoneReasonUnsupportedContent: + return SalReasonUnsupportedContent; + case LinphoneReasonNoMatch: + return SalReasonNoMatch; + case LinphoneReasonMovedPermanently: + return SalReasonMovedPermanently; + case LinphoneReasonGone: + return SalReasonGone; + case LinphoneReasonAddressIncomplete: + return SalReasonAddressIncomplete; + case LinphoneReasonNotImplemented: + return SalReasonNotImplemented; + case LinphoneReasonBadGateway: + return SalReasonBadGateway; + case LinphoneReasonServerTimeout: + return SalReasonServerTimeout; + case LinphoneReasonNotAnswered: + return SalReasonRequestTimeout; + case LinphoneReasonUnknown: + return SalReasonUnknown; + } + return SalReasonUnknown; +} + +LinphoneReason linphone_reason_from_sal(SalReason r){ + LinphoneReason ret=LinphoneReasonNone; + switch(r){ + case SalReasonNone: + ret=LinphoneReasonNone; + break; + case SalReasonIOError: + ret=LinphoneReasonIOError; + break; + case SalReasonUnknown: + case SalReasonInternalError: + ret=LinphoneReasonUnknown; + break; + case SalReasonBusy: + ret=LinphoneReasonBusy; + break; + case SalReasonDeclined: + ret=LinphoneReasonDeclined; + break; + case SalReasonDoNotDisturb: + ret=LinphoneReasonDoNotDisturb; + break; + case SalReasonForbidden: + ret=LinphoneReasonBadCredentials; + break; + case SalReasonNotAcceptable: + ret=LinphoneReasonNotAcceptable; + break; + case SalReasonNotFound: + ret=LinphoneReasonNotFound; + break; + case SalReasonRedirect: + ret=LinphoneReasonNone; + break; + case SalReasonTemporarilyUnavailable: + ret=LinphoneReasonTemporarilyUnavailable; + break; + case SalReasonServiceUnavailable: + ret=LinphoneReasonIOError; + break; + case SalReasonRequestPending: + ret=LinphoneReasonTemporarilyUnavailable; /*might not be exactly the perfect matching, but better than LinphoneReasonNone*/ + break; + case SalReasonUnauthorized: + ret=LinphoneReasonUnauthorized; + break; + case SalReasonUnsupportedContent: + ret=LinphoneReasonUnsupportedContent; + break; + case SalReasonNoMatch: + ret=LinphoneReasonNoMatch; + break; + case SalReasonRequestTimeout: + ret=LinphoneReasonNotAnswered; + break; + case SalReasonMovedPermanently: + ret=LinphoneReasonMovedPermanently; + break; + case SalReasonGone: + ret=LinphoneReasonGone; + break; + case SalReasonAddressIncomplete: + ret=LinphoneReasonAddressIncomplete; + break; + case SalReasonNotImplemented: + ret=LinphoneReasonNotImplemented; + break; + case SalReasonBadGateway: + ret=LinphoneReasonBadGateway; + break; + case SalReasonServerTimeout: + ret=LinphoneReasonServerTimeout; + break; + } + return ret; +} + +/** + * Get reason code from the error info. + * @param ei the error info. + * @return a #LinphoneReason + * @ingroup misc +**/ +LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return linphone_reason_from_sal(sei->reason); +} + +/** + * Get textual phrase from the error info. + * This is the text that is provided by the peer in the protocol (SIP). + * @param ei the error info. + * @return the error phrase + * @ingroup misc +**/ +const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->status_string; +} + +/** + * Provides additional information regarding the failure. + * With SIP protocol, the "Reason" and "Warning" headers are returned. + * @param ei the error info. + * @return more details about the failure. + * @ingroup misc +**/ +const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->warnings; +} + +/** + * Get the status code from the low level protocol (ex a SIP status code). + * @param ei the error info. + * @return the status code. + * @ingroup misc +**/ +int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->protocol_code; +} + +/** + * Set the name of the mediastreamer2 filter to be used for rendering video. + * This is for advanced users of the library, mainly to workaround hardware/driver bugs. + * @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); +} + +/** + * Queue a task into the main loop. The data pointer must remain valid until the task is completed. + * task_fun must return BELLE_SIP_STOP when job is finished. +**/ +void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){ + belle_sip_source_t *s=sal_create_timer(lc->sal,task_fun,data, 20, task_description); + belle_sip_object_unref(s); +} + +static int get_unique_transport(LinphoneCore *lc, LinphoneTransportType *type, int *port){ + LCSipTransports tp; + linphone_core_get_sip_transports(lc,&tp); + if (tp.tcp_port==0 && tp.tls_port==0 && tp.udp_port!=0){ + *type=LinphoneTransportUdp; + *port=tp.udp_port; + return 0; + }else if (tp.tcp_port==0 && tp.udp_port==0 && tp.tls_port!=0){ + *type=LinphoneTransportTls; + *port=tp.tls_port; + return 0; + }else if (tp.tcp_port!=0 && tp.udp_port==0 && tp.tls_port==0){ + *type=LinphoneTransportTcp; + *port=tp.tcp_port; + return 0; + } + return -1; +} + +static void linphone_core_migrate_proxy_config(LinphoneCore *lc, LinphoneTransportType type){ + const MSList *elem; + for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + const char *proxy=linphone_proxy_config_get_addr(cfg); + const char *route=linphone_proxy_config_get_route(cfg); + LinphoneAddress *proxy_addr=linphone_address_new(proxy); + LinphoneAddress *route_addr=NULL; + char *tmp; + if (route) route_addr=linphone_address_new(route); + if (proxy_addr){ + linphone_address_set_transport(proxy_addr,type); + tmp=linphone_address_as_string(proxy_addr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + linphone_address_destroy(proxy_addr); + } + if (route_addr){ + linphone_address_set_transport(route_addr,type); + tmp=linphone_address_as_string(route_addr); + linphone_proxy_config_set_route(cfg,tmp); + ms_free(tmp); + linphone_address_destroy(route_addr); + } + } +} + +/** + * Migrate configuration so that all SIP transports are enabled. + * Versions of linphone < 3.7 did not support using multiple SIP transport simultaneously. + * This function helps application to migrate the configuration so that all transports are enabled. + * Existing proxy configuration are added a transport parameter so that they continue using the unique transport that was set previously. + * This function must be used just after creating the core, before any call to linphone_core_iterate() + * @param lc the linphone core + * @return 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error. + * @ingroup initializing +**/ +int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){ + if (!lp_config_get_int(lc->config,"sip","multi_transport_migration_done",0)){ + LinphoneTransportType tpt; + int port; + if (get_unique_transport(lc,&tpt,&port)==0){ + LCSipTransports newtp={0}; + if (lp_config_get_int(lc->config,"sip","sip_random_port",0)) + port=-1; + ms_message("Core is using a single SIP transport, migrating proxy config and enabling multi-transport."); + linphone_core_migrate_proxy_config(lc,tpt); + newtp.udp_port=port; + newtp.tcp_port=port; + newtp.tls_port=LC_SIP_TRANSPORT_RANDOM; + lp_config_set_string(lc->config, "sip","sip_random_port",NULL); /*remove*/ + linphone_core_set_sip_transports(lc,&newtp); + } + lp_config_set_int(lc->config,"sip","multi_transport_migration_done",1); + return 1; + } + return 0; +} + +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *obj=ms_new0(LinphoneToneDescription,1); + obj->reason=reason; + obj->toneid=id; + obj->audiofile=audiofile ? ms_strdup(audiofile) : NULL; + return obj; +} + +void linphone_tone_description_destroy(LinphoneToneDescription *obj){ + if (obj->audiofile) ms_free(obj->audiofile); + ms_free(obj); +} + +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason){ + const MSList *elem; + for (elem=lc->tones;elem!=NULL;elem=elem->next){ + LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data; + if (tone->reason==reason) return tone; + } + return NULL; +} + +const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id){ + const MSList *elem; + for (elem=lc->tones;elem!=NULL;elem=elem->next){ + LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data; + if (tone->toneid==id && tone->reason==LinphoneReasonNone && tone->audiofile!=NULL) return tone->audiofile; + } + return NULL; +} + +void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + lc->tones=ms_list_remove(lc->tones,tone); + linphone_tone_description_destroy(tone); + } + tone=linphone_tone_description_new(reason,id,audiofile); + lc->tones=ms_list_append(lc->tones,tone); +} + +/** + * Assign an audio file to be played locally upon call failure, for a given reason. + * @param lc the core + * @param reason the #LinphoneReason representing the failure error code. + * @param audiofile a wav file to be played when such call failure happens. + * @ingroup misc +**/ +void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile){ + _linphone_core_set_tone(lc,reason,LinphoneToneUndefined, audiofile); +} + +/** + * Assign an audio file to be played as a specific tone id. + * This function typically allows to customize telephony tones per country. + * @param lc the core + * @param id the tone id + * @param audiofile a wav file to be played. +**/ +void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile){ + _linphone_core_set_tone(lc, LinphoneReasonNone, id, audiofile); +} + +const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ + const char *config=lp_config_get_string(lc->config,"sip","srtp_crypto_suites","AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32, AES_CM_256_HMAC_SHA1_80, AES_CM_256_HMAC_SHA1_32"); + char *tmp=ms_strdup(config); + char *sep; + char *pos; + char *nextpos; + char *params; + int found=0; + MSCryptoSuite *result=NULL; + pos=tmp; + do{ + sep=strchr(pos,','); + if (!sep) { + sep=pos+strlen(pos); + nextpos=NULL; + }else { + *sep='\0'; + nextpos=sep+1; + } + while(*pos==' ') ++pos; /*strip leading spaces*/ + params=strchr(pos,' '); /*look for params that arrive after crypto suite name*/ + if (params){ + while(*params==' ') ++params; /*strip parameters leading space*/ + } + if (sep-pos>0){ + MSCryptoSuiteNameParams np; + MSCryptoSuite suite; + np.name=pos; + np.params=params; + suite=ms_crypto_suite_build_from_name_params(&np); + if (suite!=MS_CRYPTO_SUITE_INVALID){ + result=ms_realloc(result,(found+2)*sizeof(MSCryptoSuite)); + result[found]=suite; + result[found+1]=MS_CRYPTO_SUITE_INVALID; + found++; + ms_message("Configured srtp crypto suite: %s %s",np.name,np.params ? np.params : ""); + } + } + pos=nextpos; + }while(pos); + ms_free(tmp); + if (lc->rtp_conf.srtp_suites){ + ms_free(lc->rtp_conf.srtp_suites); + lc->rtp_conf.srtp_suites=NULL; + } + lc->rtp_conf.srtp_suites=result; + return result; +} + +static char * seperate_string_list(char **str) { + char *ret; + + if (str == NULL) return NULL; + if (*str == NULL) return NULL; + if (**str == '\0') return NULL; + + ret = *str; + for ( ; **str!='\0' && **str!=' ' && **str!=','; (*str)++); + if (**str == '\0') { + return ret; + } else { + **str = '\0'; + do { (*str)++; } while (**str!='\0' && (**str==' ' || **str==',')); + return ret; + } +} + +MsZrtpCryptoTypesCount linphone_core_get_zrtp_key_agreement_suites(LinphoneCore *lc, MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES]){ + char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_key_agreements_suites", NULL); + MsZrtpCryptoTypesCount key_agreements_count = 0; + char * entry, * origPtr; + if (zrtpConfig == NULL) { + return 0; + } + + origPtr = ms_strdup(zrtpConfig); + zrtpConfig = origPtr; + while ((entry = seperate_string_list(&zrtpConfig))) { + const MSZrtpKeyAgreement agreement = ms_zrtp_key_agreement_from_string(entry); + if (agreement != MS_ZRTP_KEY_AGREEMENT_INVALID) { + ms_message("Configured zrtp key agreement: '%s'", ms_zrtp_key_agreement_to_string(agreement)); + keyAgreements[key_agreements_count++] = agreement; + } + } + + ms_free(origPtr); + return key_agreements_count; +} + +MsZrtpCryptoTypesCount linphone_core_get_zrtp_cipher_suites(LinphoneCore *lc, MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES]){ + char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_cipher_suites", NULL); + MsZrtpCryptoTypesCount cipher_count = 0; + char * entry, * origPtr; + if (zrtpConfig == NULL) { + return 0; + } + + origPtr = ms_strdup(zrtpConfig); + zrtpConfig = origPtr; + while ((entry = seperate_string_list(&zrtpConfig))) { + const MSZrtpCipher cipher = ms_zrtp_cipher_from_string(entry); + if (cipher != MS_ZRTP_CIPHER_INVALID) { + ms_message("Configured zrtp cipher: '%s'", ms_zrtp_cipher_to_string(cipher)); + ciphers[cipher_count++] = cipher; + } + } + + ms_free(origPtr); + return cipher_count; +} + +MsZrtpCryptoTypesCount linphone_core_get_zrtp_hash_suites(LinphoneCore *lc, MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES]){ + char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_hash_suites", NULL); + MsZrtpCryptoTypesCount hash_count = 0; + char * entry, * origPtr; + if (zrtpConfig == NULL) { + return 0; + } + + origPtr = ms_strdup(zrtpConfig); + zrtpConfig = origPtr; + while ((entry = seperate_string_list(&zrtpConfig))) { + const MSZrtpHash hash = ms_zrtp_hash_from_string(entry); + if (hash != MS_ZRTP_HASH_INVALID) { + ms_message("Configured zrtp hash: '%s'", ms_zrtp_hash_to_string(hash)); + hashes[hash_count++] = hash; + } + } + + ms_free(origPtr); + return hash_count; +} + +MsZrtpCryptoTypesCount linphone_core_get_zrtp_auth_suites(LinphoneCore *lc, MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES]){ + char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_auth_suites", NULL); + MsZrtpCryptoTypesCount auth_tag_count = 0; + char * entry, * origPtr; + if (zrtpConfig == NULL) { + return 0; + } + + origPtr = ms_strdup(zrtpConfig); + zrtpConfig = origPtr; + while ((entry = seperate_string_list(&zrtpConfig))) { + const MSZrtpAuthTag authTag = ms_zrtp_auth_tag_from_string(entry); + if (authTag != MS_ZRTP_AUTHTAG_INVALID) { + ms_message("Configured zrtp auth tag: '%s'", ms_zrtp_auth_tag_to_string(authTag)); + authTags[auth_tag_count++] = authTag; + } + } + + ms_free(origPtr); + return auth_tag_count; +} + +MsZrtpCryptoTypesCount linphone_core_get_zrtp_sas_suites(LinphoneCore *lc, MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES]){ + char * zrtpConfig = (char*)lp_config_get_string(lc->config, "sip", "zrtp_sas_suites", NULL); + MsZrtpCryptoTypesCount sas_count = 0; + char * entry, * origPtr; + if (zrtpConfig == NULL) { + return 0; + } + + origPtr = ms_strdup(zrtpConfig); + zrtpConfig = origPtr; + while ((entry = seperate_string_list(&zrtpConfig))) { + const MSZrtpSasType type = ms_zrtp_sas_type_from_string(entry); + if (type != MS_ZRTP_SAS_INVALID) { + ms_message("Configured zrtp SAS type: '%s'", ms_zrtp_sas_type_to_string(type)); + sasTypes[sas_count++] = type; + } + } + + ms_free(origPtr); + return sas_count; +} + +const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){ + static const char *mkv="mkv"; + static const char *wav="wav"; + if (core->supported_formats==NULL){ + core->supported_formats=ms_malloc0(3*sizeof(char*)); + core->supported_formats[0]=wav; + if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_RECORDER_ID)){ + core->supported_formats[1]=mkv; + } + } + return core->supported_formats; +} + +bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){ + return lp_config_get_int(lc->config,"rtp","symmetric",1); +} + +int linphone_core_set_network_simulator_params(LinphoneCore *lc, const OrtpNetworkSimulatorParams *params){ + if (params!=&lc->net_conf.netsim_params) + lc->net_conf.netsim_params=*params; + /*TODO: should we make some sanity checks on the parameters here*/ + return 0; +} + +const OrtpNetworkSimulatorParams *linphone_core_get_network_simulator_params(const LinphoneCore *lc){ + return &lc->net_conf.netsim_params; +} + +static const char *_tunnel_mode_str[3] = { "disable", "enable", "auto" }; + +LinphoneTunnelMode linphone_tunnel_mode_from_string(const char *string) { + if(string != NULL) { + int i; + for(i=0; i<3 && strcmp(string, _tunnel_mode_str[i]) != 0; i++); + if(i<3) { + return (LinphoneTunnelMode)i; + } else { + ms_error("Invalid tunnel mode '%s'", string); + return LinphoneTunnelModeDisable; + } + } else { + return LinphoneTunnelModeDisable; + } +} + +const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mode) { + switch(mode){ + case LinphoneTunnelModeAuto: + return "auto"; + case LinphoneTunnelModeDisable: + return "disable"; + case LinphoneTunnelModeEnable: + return "enable"; + } + return "invalid"; +} + + +typedef struct Hook{ + LinphoneCoreIterateHook fun; + void *data; +}Hook; + +void linphone_task_list_init(LinphoneTaskList *t){ + t->hooks = NULL; +} + +static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){ + Hook *h=ms_new0(Hook,1); + h->fun=hook; + h->data=hook_data; + return h; +} + +static void hook_invoke(Hook *h){ + h->fun(h->data); +} + +void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){ + t->hooks = ms_list_append(t->hooks,hook_new(hook,hook_data)); +} + +void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){ + MSList *elem; + for(elem=t->hooks;elem!=NULL;elem=elem->next){ + Hook *h=(Hook*)elem->data; + if (h->fun==hook && h->data==hook_data){ + t->hooks = ms_list_remove_link(t->hooks,elem); + ms_free(h); + return; + } + } + ms_error("linphone_task_list_remove(): No such hook found."); +} + +void linphone_task_list_run(LinphoneTaskList *t){ + ms_list_for_each(t->hooks,(void (*)(void*))hook_invoke); +} + +void linphone_task_list_free(LinphoneTaskList *t){ + t->hooks = ms_list_free_with_data(t->hooks, (void (*)(void*))ms_free); +} + diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index c07e6e381..0b0edb931 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -31,7 +31,49 @@ static bool_t only_telephone_event(const MSList *l){ return TRUE; } -static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){ +typedef struct _PayloadTypeMatcher{ + const char *mime_type; + PayloadType *(*match_func)(const MSList *l, const PayloadType *refpt); +}PayloadTypeMatcher; + +static PayloadType * opus_match(const MSList *l, const PayloadType *refpt){ + PayloadType *pt; + const MSList *elem; + PayloadType *candidate=NULL; + + for (elem=l;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + + /*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/ + if (strcasecmp(pt->mime_type,"opus")==0 ){ + if (refpt->channels==1){ + pt->channels=1; /*so that we respond with same number of channels */ + candidate=pt; + }else if (refpt->channels==2){ + return pt; + } + } + } + return candidate; +} + +/* the reason for this matcher is for some stupid uncompliant phone that offer G729a mime type !*/ +static PayloadType * g729A_match(const MSList *l, const PayloadType *refpt){ + PayloadType *pt; + const MSList *elem; + PayloadType *candidate=NULL; + + for (elem=l;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + + if (strcasecmp(pt->mime_type,"G729")==0 && refpt->channels==pt->channels){ + candidate=pt; + } + } + return candidate; +} + +static PayloadType * amr_match(const MSList *l, const PayloadType *refpt){ PayloadType *pt; char value[10]; const MSList *elem; @@ -39,36 +81,72 @@ 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 || - (strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) - && pt->clock_rate==refpt->clock_rate){ - candidate=pt; - /*good candidate, check fmtp for H264 */ - if (strcasecmp(pt->mime_type,"H264")==0){ - if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){ - int mode1=0,mode2=0; - if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){ - mode1=atoi(value); - } - if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){ - mode2=atoi(value); - } - if (mode1==mode2) - break; /*exact match */ - } - }else break; + + if ( pt->mime_type && refpt->mime_type + && strcasecmp(pt->mime_type, refpt->mime_type)==0 + && pt->clock_rate==refpt->clock_rate + && pt->channels==refpt->channels) { + int octedalign1=0,octedalign2=0; + if (pt->recv_fmtp!=NULL && fmtp_get_value(pt->recv_fmtp,"octet-align",value,sizeof(value))){ + octedalign1=atoi(value); + } + if (refpt->send_fmtp!=NULL && fmtp_get_value(refpt->send_fmtp,"octet-align",value,sizeof(value))){ + octedalign2=atoi(value); + } + if (octedalign1==octedalign2) { + candidate=pt; + break; /*exact match */ + } } } return candidate; } +static PayloadType * generic_match(const MSList *l, const PayloadType *refpt){ + PayloadType *pt; + const MSList *elem; + + for (elem=l;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + + if ( pt->mime_type && refpt->mime_type + && strcasecmp(pt->mime_type, refpt->mime_type)==0 + && pt->clock_rate==refpt->clock_rate + && pt->channels==refpt->channels) + return pt; + } + return NULL; +} + +static PayloadTypeMatcher matchers[]={ + {"opus", opus_match}, + {"G729A", g729A_match}, + {"AMR", amr_match}, + {"AMR-WB", amr_match}, + {NULL, NULL} +}; + + +/* + * Returns a PayloadType from the local list that matches a PayloadType offered or answered in the remote list +*/ +static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){ + PayloadTypeMatcher *m; + for(m=matchers;m->mime_type!=NULL;++m){ + if (refpt->mime_type && strcasecmp(m->mime_type,refpt->mime_type)==0){ + return m->match_func(l,refpt); + } + } + return generic_match(l,refpt); +} + + static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){ const MSList *e2,*e1; MSList *res=NULL; PayloadType *matched; bool_t found_codec=FALSE; - + for(e2=remote;e2!=NULL;e2=e2->next){ PayloadType *p2=(PayloadType*)e2->data; matched=find_payload_type_best_match(local,p2); @@ -84,17 +162,29 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t }else found_codec=TRUE; } } - + newp=payload_type_clone(matched); - if (p2->send_fmtp) - payload_type_set_send_fmtp(newp,p2->send_fmtp); + if (p2->send_fmtp){ + payload_type_append_send_fmtp(newp,p2->send_fmtp); + } newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND; + if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { + newp->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED; + /* Negotiation of AVPF features (keep common features) */ + newp->avpf.features &= p2->avpf.features; + newp->avpf.rpsi_compatibility = p2->avpf.rpsi_compatibility; + /* Take bigger AVPF trr interval */ + if (p2->avpf.trr_interval < matched->avpf.trr_interval) { + newp->avpf.trr_interval = matched->avpf.trr_interval; + } + } res=ms_list_append(res,newp); /* we should use the remote numbering even when parsing a response */ payload_type_set_number(newp,remote_number); + payload_type_set_flag(newp, PAYLOAD_TYPE_FROZEN_NUMBER); if (reading_response && remote_number!=local_number){ ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i", - newp->mime_type, local_number, remote_number); + newp->mime_type, local_number, remote_number); /* We must add this payload type with our local numbering in order to be able to receive it. Indeed despite we must sent with the remote numbering, we must be able to receive with @@ -102,10 +192,13 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t */ newp=payload_type_clone(newp); payload_type_set_number(newp,local_number); + payload_type_set_flag(newp, PAYLOAD_TYPE_FROZEN_NUMBER); res=ms_list_append(res,newp); } }else{ - ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate); + if (p2->channels>0) + ms_message("No match for %s/%i/%i",p2->mime_type,p2->clock_rate,p2->channels); + else ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate); } } if (reading_response){ @@ -123,7 +216,8 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t if (!found){ ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate); p1=payload_type_clone(p1); - p1->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV; + payload_type_set_flag(p1, PAYLOAD_TYPE_FLAG_CAN_RECV); + payload_type_set_flag(p1, PAYLOAD_TYPE_FROZEN_NUMBER); res=ms_list_append(res,p1); } } @@ -131,30 +225,29 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t return res; } -static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote, +static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote, SalSrtpCryptoAlgo* result, unsigned int* choosen_local_tag, bool_t use_local_key) { int i,j; for(i=0; ialgo = remote[i].algo; - /* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */ + /* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */ if (use_local_key) { - strncpy(result->master_key, local[j].master_key, 41); + strncpy(result->master_key, local[j].master_key, sizeof(result->master_key) ); result->tag = remote[i].tag; - *choosen_local_tag = local[j].tag; + *choosen_local_tag = local[j].tag; } /* We received an answer to our SDP crypto proposal. Copy matching algo remote master key to result, and memorize local tag */ - else { - strncpy(result->master_key, remote[i].master_key, 41); + else { + strncpy(result->master_key, remote[i].master_key, sizeof(result->master_key)); result->tag = local[j].tag; - *choosen_local_tag = local[j].tag; + *choosen_local_tag = local[j].tag; } - result->master_key[40] = '\0'; return TRUE; } } @@ -204,13 +297,85 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere } static void initiate_outgoing(const SalStreamDescription *local_offer, - const SalStreamDescription *remote_answer, - SalStreamDescription *result){ + const SalStreamDescription *remote_answer, + SalStreamDescription *result){ if (remote_answer->rtp_port!=0) result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE); + else { + ms_message("Local stream description [%p] rejected by peer",local_offer); + result->rtp_port=0; + return; + } result->proto=remote_answer->proto; result->type=local_offer->type; - result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir); + + if (local_offer->rtp_addr[0]!='\0' && ms_is_multicast(local_offer->rtp_addr)) { + /*6.2 Multicast Streams + ... + If a multicast stream is accepted, the address and port information + in the answer MUST match that of the offer. Similarly, the + directionality information in the answer (sendonly, recvonly, or + sendrecv) MUST equal that of the offer. This is because all + participants in a multicast session need to have equivalent views of + the parameters of the session, an underlying assumption of the + multicast bias of RFC 2327.*/ + if (strcmp(local_offer->rtp_addr,remote_answer->rtp_addr) !=0 ) { + ms_message("Remote answered IP [%s] does not match offered [%s] for local stream description [%p]" + ,remote_answer->rtp_addr + ,local_offer->rtp_addr + ,local_offer); + result->rtp_port=0; + return; + } + if (local_offer->rtp_port!=remote_answer->rtp_port) { + ms_message("Remote answered rtp port [%i] does not match offered [%i] for local stream description [%p]" + ,remote_answer->rtp_port + ,local_offer->rtp_port + ,local_offer); + result->rtp_port=0; + return; + } + if (local_offer->dir!=remote_answer->dir) { + ms_message("Remote answered dir [%s] does not match offered [%s] for local stream description [%p]" + ,sal_stream_dir_to_string(remote_answer->dir) + ,sal_stream_dir_to_string(local_offer->dir) + ,local_offer); + result->rtp_port=0; + return; + } + if (local_offer->bandwidth!=remote_answer->bandwidth) { + ms_message("Remote answered bandwidth [%i] does not match offered [%i] for local stream description [%p]" + ,remote_answer->bandwidth + ,local_offer->bandwidth + ,local_offer); + result->rtp_port=0; + return; + } + if (local_offer->ptime > 0 && local_offer->ptime!=remote_answer->ptime) { + ms_message("Remote answered ptime [%i] does not match offered [%i] for local stream description [%p]" + ,remote_answer->ptime + ,local_offer->ptime + ,local_offer); + result->rtp_port=0; + return; + } + if (local_offer->ttl > 0 && local_offer->ttl!=remote_answer->ttl) { + ms_message("Remote answered ttl [%i] does not match offered [%i] for local stream description [%p]" + ,remote_answer->ttl + ,local_offer->ttl + ,local_offer); + result->rtp_port=0; + return; + } + result->ttl=local_offer->ttl; + result->dir=local_offer->dir; + result->multicast_role = SalMulticastSender; + + } else { + result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir); + } + + if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->rtp_addr,remote_answer->rtp_addr); @@ -222,38 +387,74 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, }else{ result->rtp_port=0; } - if (result->proto == SalProtoRtpSavp) { + if (sal_stream_description_has_srtp(result) == TRUE) { /* verify crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) result->rtp_port = 0; } + result->rtp_ssrc=local_offer->rtp_ssrc; + strncpy(result->rtcp_cname,local_offer->rtcp_cname,sizeof(result->rtcp_cname)); + + // Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, get the remote fingerprint into the result + if ((local_offer->dtls_role!=SalDtlsRoleInvalid) && (remote_answer->dtls_role!=SalDtlsRoleInvalid) + &&(strlen(local_offer->dtls_fingerprint)>0) && (strlen(remote_answer->dtls_fingerprint)>0)) { + strncpy(result->dtls_fingerprint, remote_answer->dtls_fingerprint,sizeof(result->dtls_fingerprint)); + if (remote_answer->dtls_role==SalDtlsRoleIsClient) { + result->dtls_role = SalDtlsRoleIsServer; + } else { + result->dtls_role = SalDtlsRoleIsClient; + } + } else { + result->dtls_fingerprint[0] = '\0'; + result->dtls_role = SalDtlsRoleInvalid; + } + + } static void initiate_incoming(const SalStreamDescription *local_cap, - const SalStreamDescription *remote_offer, - SalStreamDescription *result, bool_t one_matching_codec){ + const SalStreamDescription *remote_offer, + SalStreamDescription *result, bool_t one_matching_codec){ result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec); result->proto=remote_offer->proto; result->type=local_cap->type; result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir); - if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){ + if (!result->payloads || only_telephone_event(result->payloads) || remote_offer->rtp_port==0 || remote_offer->dir==SalStreamRecvOnly){ + result->rtp_port=0; + return; + } + if (remote_offer->rtp_addr[0]!='\0' && ms_is_multicast(remote_offer->rtp_addr)) { + if (sal_stream_description_has_srtp(result) == TRUE) { + ms_message("SAVP not supported for multicast address for remote stream [%p]",remote_offer); + result->rtp_port=0; + return; + } + result->dir=remote_offer->dir; + strcpy(result->rtp_addr,remote_offer->rtp_addr); + strcpy(result->rtcp_addr,remote_offer->rtcp_addr); + result->rtp_port=remote_offer->rtp_port; + /*result->rtcp_port=remote_offer->rtcp_port;*/ + result->rtcp_port=0; /* rtcp not supported yet*/ + result->bandwidth=remote_offer->bandwidth; + result->ptime=remote_offer->ptime; + result->ttl=remote_offer->ttl; + result->multicast_role = SalMulticastReceiver; + } else { strcpy(result->rtp_addr,local_cap->rtp_addr); strcpy(result->rtcp_addr,local_cap->rtcp_addr); result->rtp_port=local_cap->rtp_port; result->rtcp_port=local_cap->rtcp_port; result->bandwidth=local_cap->bandwidth; result->ptime=local_cap->ptime; - }else{ - result->rtp_port=0; } - if (result->proto == SalProtoRtpSavp) { + if (sal_stream_description_has_srtp(result) == TRUE) { /* select crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) result->rtp_port = 0; - + } strcpy(result->ice_pwd, local_cap->ice_pwd); strcpy(result->ice_ufrag, local_cap->ice_ufrag); @@ -261,8 +462,27 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->ice_completed = local_cap->ice_completed; memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); + strcpy(result->name,local_cap->name); + result->rtp_ssrc=local_cap->rtp_ssrc; + strncpy(result->rtcp_cname,local_cap->rtcp_cname,sizeof(result->rtcp_cname)); + + // Handle dtls stream attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer + // Note: local description usually stores dtls config at session level which means it apply to all streams, check this too + if (((local_cap->dtls_role!=SalDtlsRoleInvalid)) && (remote_offer->dtls_role!=SalDtlsRoleInvalid) + && (strlen(local_cap->dtls_fingerprint)>0) && (strlen(remote_offer->dtls_fingerprint)>0)) { + strncpy(result->dtls_fingerprint, local_cap->dtls_fingerprint,sizeof(result->dtls_fingerprint)); + if (remote_offer->dtls_role==SalDtlsRoleUnset) { + result->dtls_role = SalDtlsRoleIsClient; + } + } else { + result->dtls_fingerprint[0] = '\0'; + result->dtls_role = SalDtlsRoleInvalid; + } + + } + /** * Returns a media description to run the streams with, based on a local offer * and the returned response (remote). @@ -271,25 +491,68 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, SalMediaDescription *result){ int i,j; - const SalStreamDescription *ls,*rs; - for(i=0,j=0;in_total_streams;++i){ + + for(i=0,j=0;inb_streams;++i){ ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); + memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr)); + if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) { + result->streams[i].rtcp_xr.enabled = FALSE; + } + result->streams[i].rtcp_fb.generic_nack_enabled = ls->rtcp_fb.generic_nack_enabled & rs->rtcp_fb.generic_nack_enabled; + result->streams[i].rtcp_fb.tmmbr_enabled = ls->rtcp_fb.tmmbr_enabled & rs->rtcp_fb.tmmbr_enabled; ++j; } else ms_warning("No matching stream for %i",i); } - result->n_active_streams=j; - result->n_total_streams=local_offer->n_total_streams; + result->nb_streams=local_offer->nb_streams; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); + memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr)); + if ((local_offer->rtcp_xr.enabled == TRUE) && (remote_answer->rtcp_xr.enabled == FALSE)) { + result->rtcp_xr.enabled = FALSE; + } + return 0; } +static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){ + int i; + for(i=0;inb_streams;++i){ + const SalStreamDescription *ss=&result->streams[i]; + if (strcmp(ss->name,stream->name)==0){ + ms_message("video stream already used in answer"); + return FALSE; + } + } + return TRUE; +} + +/*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/ +static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { + if (local == remote) return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoUdpTlsRtpSavp) || (local == SalProtoUdpTlsRtpSavpf))) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoUdpTlsRtpSavpf)) return TRUE; + return FALSE; +} + +static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){ + int i; + for(i=0;inb_streams;++i){ + const SalStreamDescription *ss=&local_capabilities->streams[i]; + if (!sal_stream_description_active(ss)) continue; + if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto) + && local_stream_not_already_used(result,ss)) return ss; + } + return NULL; +} + /** * Returns a media description to run the streams with, based on the local capabilities and * and the received offer. @@ -301,20 +564,30 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities int i; const SalStreamDescription *ls=NULL,*rs; - result->n_active_streams=0; - for(i=0;in_total_streams;++i){ + for(i=0;inb_streams;++i){ rs=&remote_offer->streams[i]; - if (rs->proto!=SalProtoUnknown){ - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); - /* if matching failed, and remote proposes Avp only, ask for local Savp streams */ - if (!ls && rs->proto == SalProtoRtpAvp) { - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type); - } + if (rs->proto!=SalProtoOther){ + ls=find_local_matching_stream(result,local_capabilities,rs); }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); - if (result->streams[i].rtp_port!=0) result->n_active_streams++; + // Handle global RTCP FB attributes + result->streams[i].rtcp_fb.generic_nack_enabled = rs->rtcp_fb.generic_nack_enabled; + result->streams[i].rtcp_fb.tmmbr_enabled = rs->rtcp_fb.tmmbr_enabled; + // Handle media RTCP XR attribute + memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr)); + if (rs->rtcp_xr.enabled == TRUE) { + const OrtpRtcpXrConfiguration *rtcp_xr_conf = NULL; + if (ls->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &ls->rtcp_xr; + else if (local_capabilities->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &local_capabilities->rtcp_xr; + if ((rtcp_xr_conf != NULL) && (ls->dir == SalStreamSendRecv)) { + memcpy(&result->streams[i].rtcp_xr, rtcp_xr_conf, sizeof(result->streams[i].rtcp_xr)); + } else { + result->streams[i].rtcp_xr.enabled = TRUE; + } + } }else { + ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i); /* create an inactive stream for the answer, as there where no matching stream in local capabilities */ result->streams[i].dir=SalStreamInactive; result->streams[i].rtp_port=0; @@ -323,9 +596,12 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } + if (rs->proto==SalProtoOther){ + strncpy(result->streams[i].proto_other,rs->proto_other,sizeof(rs->proto_other)-1); + } } } - result->n_total_streams=i; + result->nb_streams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; @@ -335,5 +611,18 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities strcpy(result->ice_ufrag, local_capabilities->ice_ufrag); result->ice_lite = local_capabilities->ice_lite; result->ice_completed = local_capabilities->ice_completed; + + strcpy(result->name,local_capabilities->name); + + // Handle session RTCP XR attribute + memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr)); + if (remote_offer->rtcp_xr.enabled == TRUE) { + if ((local_capabilities->rtcp_xr.enabled == TRUE) && (local_capabilities->dir == SalStreamSendRecv)) { + memcpy(&result->rtcp_xr, &local_capabilities->rtcp_xr, sizeof(result->rtcp_xr)); + } else { + result->rtcp_xr.enabled = TRUE; + } + } + return 0; } diff --git a/coreapi/offeranswer.h b/coreapi/offeranswer.h index 5aa658ae6..0c8ebd7b1 100644 --- a/coreapi/offeranswer.h +++ b/coreapi/offeranswer.h @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef offeranswer_h #define offeranswer_h -/** +/** This header files defines the SDP offer answer API. It can be used by implementations of SAL directly. **/ @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. **/ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, - SalMediaDescription *result); + SalMediaDescription *result); /** * Returns a media description to run the streams with, based on the local capabilities and @@ -41,7 +41,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, **/ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, const SalMediaDescription *remote_offer, - SalMediaDescription *result, bool_t one_matching_codec); - + SalMediaDescription *result, bool_t one_matching_codec); + #endif diff --git a/coreapi/player.c b/coreapi/player.c new file mode 100644 index 000000000..1b2a01022 --- /dev/null +++ b/coreapi/player.c @@ -0,0 +1,198 @@ + +/* +linphone +Copyright (C) 2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" + +/** + * Open a new source on this player. + * @param obj the player + * @param filename file to open. + * @param cb a callback used to notify end of play. + * @param user_data a user-data provided in the callback to help the application to retrieve its context. + * @return 0 if successful, -1 otherwise +**/ +int linphone_player_open(LinphonePlayer *obj, const char *filename, LinphonePlayerEofCallback cb, void *user_data){ + obj->user_data=user_data; + obj->cb=cb; + return obj->open(obj,filename); +} + +/** + * Start a play operation. The player must have been open previously with linphone_player_open(). + * @param obj the player. + * @return 0 if successful, -1 otherwise +**/ +int linphone_player_start(LinphonePlayer *obj){ + return obj->start(obj); +} + +/** + * Suspend a play operation. The player must have been started previously with linphone_player_start(). + * @param obj the player. + * @return 0 if successful, -1 otherwise +**/ +int linphone_player_pause(LinphonePlayer *obj){ + return obj->pause(obj); +} + +/** + * Seek at a given position given in milliseconds. The player must be in the paused state. + * @param obj the player. + * @param time_ms the position to seek to. + * @return 0 if successful, -1 otherwise +**/ +int linphone_player_seek(LinphonePlayer *obj, int time_ms){ + return obj->seek(obj,time_ms); +} + +/** + * Get the state of play operation. + * @param obj the player. + * @return the state of the player within MSPlayerClosed, MSPlayerStarted, MSPlayerPaused. +**/ +MSPlayerState linphone_player_get_state(LinphonePlayer *obj){ + return obj->get_state(obj); +} + +/** + * Get the duration of the media + * @param obj the player + * @return The duration in milliseconds + */ +int linphone_player_get_duration(LinphonePlayer *obj) { + return obj->get_duration(obj); +} + +/** + * Get the position of the playback + * @param obj the player + * @return Position of the playback in milliseconds + */ +int linphone_player_get_current_position(LinphonePlayer *obj) { + return obj->get_position(obj); +} + +/** + * Close the player. + * @param obj the player. +**/ +void linphone_player_close(LinphonePlayer *obj){ + return obj->close(obj); +} + +/** + * @brief Destroy a player + * @param obj The player + */ +void linphone_player_destroy(LinphonePlayer *obj) { + if(obj->destroy) obj->destroy(obj); +} + +void _linphone_player_destroy(LinphonePlayer *player) { + ms_free(player); +} + + +/* + * Call player implementation below. + */ + + +static bool_t call_player_check_state(LinphonePlayer *player, bool_t check_player){ + LinphoneCall *call=(LinphoneCall*)player->impl; + if (call->state!=LinphoneCallStreamsRunning){ + ms_warning("Call [%p]: in-call player not usable in state [%s]",call,linphone_call_state_to_string(call->state)); + return FALSE; + } + if (call->audiostream==NULL) { + ms_error("call_player_check_state(): no audiostream."); + return FALSE; + } + if (check_player && call->audiostream->av_player.player==NULL){ + ms_error("call_player_check_state(): no player."); + return FALSE; + } + return TRUE; +} + +static void on_eof(void *user_data, MSFilter *f, unsigned int event_id, void *arg){ + LinphonePlayer *player=(LinphonePlayer *)user_data; + if (player->cb) player->cb(player,player->user_data); +} + +static int call_player_open(LinphonePlayer* player, const char *filename){ + LinphoneCall *call=(LinphoneCall*)player->impl; + MSFilter *filter; + if (!call_player_check_state(player,FALSE)) return -1; + filter=audio_stream_open_remote_play(call->audiostream,filename); + if (!filter) return -1; + ms_filter_add_notify_callback(filter,&on_eof,player,FALSE); + return 0; +} + +static int call_player_start(LinphonePlayer *player){ + LinphoneCall *call=(LinphoneCall*)player->impl; + if (!call_player_check_state(player,TRUE)) return -1; + return ms_filter_call_method_noarg(call->audiostream->av_player.player,MS_PLAYER_START); +} + +static int call_player_pause(LinphonePlayer *player){ + LinphoneCall *call=(LinphoneCall*)player->impl; + if (!call_player_check_state(player,TRUE)) return -1; + return ms_filter_call_method_noarg(call->audiostream->av_player.player,MS_PLAYER_PAUSE); +} + +static MSPlayerState call_player_get_state(LinphonePlayer *player){ + LinphoneCall *call=(LinphoneCall*)player->impl; + MSPlayerState state=MSPlayerClosed; + if (!call_player_check_state(player,TRUE)) return MSPlayerClosed; + ms_filter_call_method(call->audiostream->av_player.player,MS_PLAYER_GET_STATE,&state); + return state; +} + +static int call_player_seek(LinphonePlayer *player, int time_ms){ + LinphoneCall *call=(LinphoneCall*)player->impl; + if (!call_player_check_state(player,TRUE)) return -1; + return ms_filter_call_method(call->audiostream->av_player.player,MS_PLAYER_SEEK_MS,&time_ms); +} + +static void call_player_close(LinphonePlayer *player){ + LinphoneCall *call=(LinphoneCall*)player->impl; + if (!call_player_check_state(player,TRUE)) return; + audio_stream_close_remote_play(call->audiostream); + +} + +static void on_call_destroy(void *obj, belle_sip_object_t *call_being_destroyed){ + _linphone_player_destroy(obj); +} + +LinphonePlayer *linphone_call_build_player(LinphoneCall *call){ + LinphonePlayer *obj=ms_new0(LinphonePlayer,1); + obj->open=call_player_open; + obj->close=call_player_close; + obj->start=call_player_start; + obj->seek=call_player_seek; + obj->pause=call_player_pause; + obj->get_state=call_player_get_state; + obj->impl=call; + belle_sip_object_weak_ref(call,on_call_destroy,obj); + return obj; +} diff --git a/coreapi/plugins/buddylookup/src/lookup.c b/coreapi/plugins/buddylookup/src/lookup.c index 48a8d3bb2..736e7aa35 100644 --- a/coreapi/plugins/buddylookup/src/lookup.c +++ b/coreapi/plugins/buddylookup/src/lookup.c @@ -81,7 +81,7 @@ static void fill_buddy_info(BLReq *blreq, BuddyInfo *bi, GHashTable *ht){ }else{ strncpy(bi->sip_uri,tmp,sizeof(bi->sip_uri)-1); } - + fill_item(ht,"street",bi->address.street,sizeof(bi->address.street)); fill_item(ht,"zip",bi->address.zip,sizeof(bi->address.zip)); fill_item(ht,"city",bi->address.town,sizeof(bi->address.town)); @@ -105,7 +105,7 @@ static void fill_buddy_info(BLReq *blreq, BuddyInfo *bi, GHashTable *ht){ ms_error("Fail to fetch the image %i",status); } } - + } static MSList * make_buddy_list(BLReq *blreq, GValue *retval){ @@ -156,7 +156,7 @@ static int xml_rpc_parse_response(BLReq *blreq, SoupMessage *sm){ #if SERIALIZE_HTTPS /*on windows libsoup support for threads with gnutls is not yet functionnal (only in git) -This will come in next release of libsoup, probably. +This will come in next release of libsoup, probably. In the meantime, we are forced to serialize all soup https processing with a big ugly global mutex...*/ @@ -191,27 +191,26 @@ static int lookup_buddy(SipSetupContext *ctx, BLReq *req){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); LinphoneCore *lc=linphone_proxy_config_get_core(cfg); LpConfig *config=linphone_core_get_config(lc); - const char *identity=linphone_proxy_config_get_identity(cfg); + LinphoneAddress *from=linphone_proxy_config_get_identity_address(cfg); const char *url=lp_config_get_string(config,"BuddyLookup","url",NULL); - const LinphoneAuthInfo *aa; + const LinphoneAuthInfo *auth_info; SoupMessage *sm; - LinphoneAddress *from; - + char *identity; + if (url==NULL){ ms_error("No url defined for BuddyLookup in config file, aborting search."); return -1; } - - from=linphone_address_new(identity); - if (from==NULL){ - ms_error("Could not parse identity %s",identity); - return -1; + auth_info=linphone_core_find_auth_info(lc,linphone_address_get_domain(from),linphone_address_get_username(from)); + if (auth_info) { + ms_message("There is a password: %s",auth_info->passwd); + } else { + ms_message("No password for %s on %s",linphone_address_get_username(from),linphone_address_get_domain(from)); } - aa=linphone_core_find_auth_info(lc,linphone_address_get_domain(from),linphone_address_get_username(from)); - if (aa) ms_message("There is a password: %s",aa->passwd); - else ms_message("No password for %s on %s",linphone_address_get_username(from),linphone_address_get_domain(from)); - sm=build_xmlrpc_request(identity, aa ? aa->passwd : NULL, req->base.key, linphone_address_get_domain(from), url, req->base.max_results); - linphone_address_destroy(from); + + identity=linphone_proxy_config_get_identity(cfg); + sm=build_xmlrpc_request(identity, auth_info ? auth_info->passwd : NULL, req->base.key, linphone_address_get_domain(from), url, req->base.max_results); + ms_free(identity); req->msg=sm; ortp_thread_create(&req->th,NULL,process_xml_rpc_request,req); if (!sm) return -1; diff --git a/coreapi/presence.c b/coreapi/presence.c index ca6357258..f70f78ae0 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,1439 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +#include "lpconfig.h" +#include "linphonepresence.h" + 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. */ +}; + + +static const char *person_prefix = "/pidf:presence/dm:person"; + + +/***************************************************************************** + * PRIVATE FUNCTIONS * + ****************************************************************************/ +/*defined in http://www.w3.org/TR/REC-xml/*/ +static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz-."; +/*NameStartChar (NameChar)**/ +static char presence_id_valid_start_characters[] = ":_abcdefghijklmnopqrstuvwxyz"; + +static char * generate_presence_id(void) { + char id[7]; + int i; + id[0] = presence_id_valid_start_characters[ortp_random() % (sizeof(presence_id_valid_start_characters)-1)]; + for (i = 1; i < 6; i++) { + id[i] = presence_id_valid_characters[ortp_random() % (sizeof(presence_id_valid_characters)-1)]; + } + 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; +#ifdef LINPHONE_WINDOWS_UNIVERSAL + long adjust_timezone; +#else + time_t adjust_timezone; +#endif + + 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; + } +#ifdef LINPHONE_WINDOWS_UNIVERSAL + _get_timezone(&adjust_timezone); +#else + adjust_timezone = timezone; +#endif + return seconds - (time_t)adjust_timezone; +} + +char * linphone_timestamp_to_rfc3339_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; + int err = 0; + + 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; + + err = linphone_presence_model_add_service(model, service); + linphone_presence_service_unref(service); + return err; +} + +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; + int err = 0; + + 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; + err = linphone_presence_model_add_activity(model, activity); + linphone_presence_activity_unref(activity); + return err; +} + +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(const 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(const 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(const 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(const 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(const LinphonePresenceNote *note) { + return note->user_data; +} + + + +/***************************************************************************** + * XML PRESENCE INTERNAL HANDLING * + ****************************************************************************/ + +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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); + + note = linphone_presence_note_new(note_str, lang); + presence_service_add_note(service, note); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); + if ((service_object != NULL) && (service_object->nodesetval != NULL)) { + for (i = 1; i <= service_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i); + basic_status_str = linphone_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. */ + linphone_free_xml_text_content(basic_status_str); + return -1; + } + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i); + timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i); + contact_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i); + service_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + service = presence_service_new(service_id_str, basic_status); + if (service != NULL) { + if (timestamp_str != NULL) presence_service_set_timestamp(service, parse_timestamp(timestamp_str)); + if (contact_str != NULL) linphone_presence_service_set_contact(service, contact_str); + process_pidf_xml_presence_service_notes(xml_ctx, service, i); + linphone_presence_model_add_service(model, service); + } + if (timestamp_str != NULL) linphone_free_xml_text_content(timestamp_str); + if (contact_str != NULL) linphone_free_xml_text_content(contact_str); + if (service_id_str != NULL) linphone_free_xml_text_content(service_id_str); + linphone_free_xml_text_content(basic_status_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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) { + for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/rpid:*", person_prefix, person_idx, i); + activities_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { + for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { + activity_node = activities_object->nodesetval->nodeTab[j]; + 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')) { + linphone_free_xml_text_content(description); + description = NULL; + } + err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); + if (err < 0) break; + activity = linphone_presence_activity_new(acttype, description); + linphone_presence_person_add_activity(person, activity); + if (description != NULL) linphone_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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]", person_prefix, person_idx, i); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); + + note = linphone_presence_note_new(note_str, lang); + presence_person_add_activities_note(person, note); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); + } + } + if (note_object != NULL) xmlXPathFreeObject(note_object); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note", person_prefix, person_idx); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]", person_prefix, person_idx, i); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); + + note = linphone_presence_note_new(note_str, lang); + presence_person_add_note(person, note); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); + if ((person_object != NULL) && (person_object->nodesetval != NULL)) { + for (i = 1; i <= person_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i); + person_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i); + person_timestamp_str = linphone_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) linphone_free_xml_text_content(person_id_str); + if (person_timestamp_str != NULL) linphone_free_xml_text_content(person_timestamp_str); + } + } + if (person_object != NULL) xmlXPathFreeObject(person_object); + + 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 = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]", i); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); + + note = linphone_presence_note_new(note_str, lang); + presence_model_add_note(model, note); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_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 (linphone_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_add_incoming_subscription(fl, 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) { + { char *tmp=linphone_address_as_string(fl->uri); - lc->vtable.new_subscription_request(lc,fl,tmp); + linphone_core_notify_new_subscription_requested(lc,fl,tmp); ms_free(tmp); } } @@ -42,14 +1460,15 @@ 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); } } @@ -57,36 +1476,24 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ LinphoneFriend *lf=NULL; char *tmp; LinphoneAddress *uri; - LinphoneProxyConfig *cfg; - const char *fixed_contact; - + uri=linphone_address_new(from); linphone_address_clean(uri); tmp=linphone_address_as_string(uri); ms_message("Receiving new subscription from %s.",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); - } - } - } /* check if we answer to this subscription */ - if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ - lf->insub=op; + if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){ + linphone_friend_add_incoming_subscription(lf, 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 +1508,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 = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); + xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + model = process_pidf_xml_presence_notification(xml_ctx); + } else { + ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); + } + linphone_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 = linphone_timestamp_to_rfc3339_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; + } + + xmlTextWriterSetIndent(writer,1); + + 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={0}; + 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={0}; + st.writer = writer; + st.err = &err; + ms_list_for_each2(model->persons, (MSIterate2Func)write_xml_presence_person_obj, &st); + } + if ((err >= 0) && (model != NULL)) { + struct _presence_note_obj_st st={0}; + 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); + } + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + *content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + 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); + linphone_core_notify_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); @@ -163,8 +1891,36 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){ lf=linphone_find_friend_by_inc_subscribe(lc->friends,op); sal_op_release(op); if (lf!=NULL){ - lf->insub=NULL; + linphone_friend_remove_incoming_subscription(lf, op); }else{ 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 e37e88a2a..942f14f2c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -25,6 +25,7 @@ #ifndef _PRIVATE_H #define _PRIVATE_H #ifdef __cplusplus + extern "C" { #endif #include "linphonecore.h" @@ -33,6 +34,10 @@ extern "C" { #include "linphonecore_utils.h" #include "sal/sal.h" #include "sipsetup.h" +#include "quality_reporting.h" + +#include +#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -44,6 +49,10 @@ extern "C" { #include "upnp.h" #endif //BUILD_UPNP +#ifdef MSG_STORAGE_ENABLED +#include "sqlite3.h" +#endif + #ifndef LIBLINPHONE_VERSION #define LIBLINPHONE_VERSION LINPHONE_VERSION #endif @@ -56,10 +65,23 @@ extern "C" { #define PACKAGE_DATA_DIR "." #endif -#ifdef HAVE_GETTEXT +#ifdef ENABLE_NLS + +#ifdef _MSC_VER +// prevent libintl.h from re-defining fprintf and vfprintf +#ifndef fprintf +#define fprintf fprintf +#endif +#ifndef vfprintf +#define vfprintf vfprintf +#endif +#define _GL_STDIO_H +#endif + #include + #ifndef _ -#define _(String) gettext(String) +#define _(String) dgettext(GETTEXT_PACKAGE,String) #endif #else #ifndef _ @@ -69,102 +91,186 @@ extern "C" { #define ngettext(singular, plural, number) (((number)==1)?(singular):(plural)) #endif #endif +#ifdef ANDROID +#include +#endif + +#ifdef _WIN32 +#if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP) +#define LINPHONE_WINDOWS_DESKTOP 1 +#elif defined(WINAPI_FAMILY_PARTITION) +#if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define LINPHONE_WINDOWS_DESKTOP 1 +#elif defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +#define LINPHONE_WINDOWS_PHONE 1 +#elif defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define LINPHONE_WINDOWS_UNIVERSAL 1 +#endif +#endif +#endif struct _LinphoneCallParams{ + belle_sip_object_t base; + void *user_data; LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */ int audio_bw; /* bandwidth limit for audio stream */ 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 */ + float received_fps,sent_fps; int down_bw; int up_bw; int down_ptime; int up_ptime; char *record_file; + char *session_name; SalCustomHeader *custom_headers; bool_t has_video; + bool_t avpf_enabled; /* RTCP feedback messages are enabled */ bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ bool_t in_conference; /*in conference mode */ - bool_t pad; bool_t low_bandwidth; + bool_t no_user_consent;/*when set to TRUE an UPDATE request will be used instead of reINVITE*/ + uint16_t avpf_rr_interval; /*in milliseconds*/ + LinphonePrivacyMask privacy; + LinphoneMediaDirection audio_dir; + LinphoneMediaDirection video_dir; + bool_t video_declined; /*use to keep traces of declined video to avoid to re-offer video in case of automatic RE-INVITE*/ + bool_t internal_call_update; /*use mark that call update was requested internally (might be by ice)*/ + bool_t video_multicast_enabled; + bool_t audio_multicast_enabled; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneCallParams); + + +struct _LinphoneQualityReporting{ + reporting_session_report_t * reports[2]; /**Store information on audio and video media streams (RFC 6035) */ + bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/ + LinphoneQualityReportingReportSendCb on_report_sent; }; struct _LinphoneCallLog{ + belle_sip_object_t base; + void *user_data; struct _LinphoneCore *lc; LinphoneCallDir dir; /**< The direction of the call*/ LinphoneCallStatus status; /**< The status of the call*/ LinphoneAddress *from; /** This fingerprint is computed during stream init and is stored in call to be used when making local media description */ bool_t refer_pending; - bool_t media_pending; + bool_t expect_media_in_ack; bool_t audio_muted; - bool_t camera_active; - + bool_t camera_enabled; + bool_t all_muted; /*this flag is set during early medias*/ bool_t playing_ringbacktone; - bool_t owns_call_log; bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/ - - bool_t videostream_encrypted; - bool_t audiostream_encrypted; bool_t auth_token_verified; + bool_t defer_update; - bool_t was_automatically_paused; bool_t ping_replied; bool_t record_active; + + bool_t paused_by_app; }; +BELLE_SIP_DECLARE_VPTR(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_new_params(LinphoneCall *call, const LinphoneCallParams *params); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); - +void linphone_call_set_contact_op(LinphoneCall* call); +void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md); /* private: */ -LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); +LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *local, LinphoneAddress * remote); void linphone_call_log_completed(LinphoneCall *call); void linphone_call_log_destroy(LinphoneCallLog *cl); void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); +LinphonePlayer *linphone_call_build_player(LinphoneCall*call); + +LinphoneCallParams * linphone_call_params_new(void); +SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params); +SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params); +SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params); void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos); 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); +void _linphone_proxy_config_release(LinphoneProxyConfig *cfg); +/* + * 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_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *cfg, bool_t only_when_registered); +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); +void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op); +void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op); LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); +MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); +bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); +void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered); + +int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen); -int set_lock_file(); -int get_lock_file(); -int remove_lock_file(); -void check_sound_device(LinphoneCore *lc); -void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); -static inline int get_min_bandwidth(int dbw, int ubw){ +static MS2_INLINE int get_min_bandwidth(int dbw, int ubw){ if (dbw<=0) return ubw; if (ubw<=0) return dbw; return MIN(dbw,ubw); } -static inline bool_t bandwidth_is_greater(int bw1, int bw2){ - if (bw1<0) return TRUE; - else if (bw2<0) return FALSE; +static MS2_INLINE bool_t bandwidth_is_greater(int bw1, int bw2){ + if (bw1<=0) return TRUE; + else if (bw2<=0) return FALSE; else return bw1>=bw2; } -static inline int get_video_bandwidth(int total, int audio){ - if (total<=0) return 0; - return total-audio-10; +static MS2_INLINE int get_remaining_bandwidth_for_video(int total, int audio){ + int ret = total-audio-10; + if (ret < 0) ret = 0; + return ret; } -static inline void set_string(char **dest, const char *src){ +static MS2_INLINE void set_string(char **dest, const char *src){ if (*dest){ ms_free(*dest); *dest=NULL; @@ -262,28 +396,37 @@ static inline void set_string(char **dest, const char *src){ } #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 +#define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 +#define PAYLOAD_TYPE_FROZEN_NUMBER PAYLOAD_TYPE_USER_FLAG_4 -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_core_soundcard_hint_check(LinphoneCore* lc); + 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); +void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw); -int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_resolve_stun_server(LinphoneCore *lc); +LINPHONE_PUBLIC 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); -void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); -void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); +void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev); +void linphone_call_stop_ice_for_inactive_streams(LinphoneCall *call); +void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); +void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call); +void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); @@ -292,89 +435,120 @@ void linphone_friend_write_to_config_file(struct _LpConfig *config, LinphoneFrie LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index); 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); +void linphone_core_get_local_ip(LinphoneCore *lc, int af, const char *dest, char *result); -LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index); -int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); - void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); - -void linphone_core_play_tone(LinphoneCore *lc); +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); void linphone_call_init_stats(LinphoneCallStats *stats, int type); - +void linphone_call_fix_call_parameters(LinphoneCall *call); void linphone_call_init_audio_stream(LinphoneCall *call); void linphone_call_init_video_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); -void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone); +void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState target_state); void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); -void linphone_call_stop_audio_stream(LinphoneCall *call); -void linphone_call_stop_video_stream(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); void linphone_call_delete_ice_session(LinphoneCall *call); void linphone_call_delete_upnp_session(LinphoneCall *call); 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); void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); - +int _linphone_core_apply_transports(LinphoneCore *lc); 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_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination/* = NULL if to be taken from the call log */); +int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call); +/* + * param automatic_offering aims is to take into account previous answer for video in case of automatic re-invite. + * Purpose is to avoid to re-ask video previously declined */ 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); +int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState next_state, const char *state_info); void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error); bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); +bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -LinphoneCall * is_a_linphone_call(void *user_pointer); -LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); +void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); -static const int linphone_proxy_config_magic=0x7979; +typedef enum _LinphoneProxyConfigAddressComparisonResult{ + LinphoneProxyConfigAddressDifferent, + LinphoneProxyConfigAddressEqual, + LinphoneProxyConfigAddressWeakEqual +} LinphoneProxyConfigAddressComparisonResult; -/*chat*/ +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); +LINPHONE_PUBLIC LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); +/** + * unregister without moving the register_enable flag + */ +void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); +void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); + +/*chat*/ +void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_message_destroy(LinphoneChatMessage* msg); -/**/ +void linphone_chat_message_update_state(LinphoneChatMessage* chat_msg ); +/**/ struct _LinphoneProxyConfig { - int magic; + belle_sip_object_t base; + void *user_data; struct _LinphoneCore *lc; char *reg_proxy; char *reg_identity; + LinphoneAddress* identity_address; char *reg_route; + char *quality_reporting_collector; char *realm; char *contact_params; + char *contact_uri_params; int expires; - int reg_time; + int publish_expires; SalOp *op; + SalCustomHeader *sent_headers; char *type; struct _SipSetupContext *ssctx; int auth_failures; char *dial_prefix; LinphoneRegistrationState state; SalOp *publish_op; + LinphoneAVPFMode avpf_mode; + bool_t commit; bool_t reg_sendregister; bool_t publish; bool_t dial_escape_plus; - void* user_data; + + bool_t send_publish; + bool_t quality_reporting_enabled; + uint8_t avpf_rr_interval; + uint8_t quality_reporting_interval; + time_t deletion_date; - LinphoneReason error; + LinphonePrivacyMask privacy; + /*use to check if server config has changed between edit() and done()*/ + LinphoneAddress *saved_proxy; + LinphoneAddress *saved_identity; + /*---*/ + LinphoneAddress *pending_contact; /*use to store previous contact in case of network failure*/ + }; +BELLE_SIP_DECLARE_VPTR(LinphoneProxyConfig); + struct _LinphoneAuthInfo { char *username; @@ -382,26 +556,41 @@ struct _LinphoneAuthInfo char *userid; char *passwd; char *ha1; - int usecount; - time_t last_use_time; - bool_t works; + char *domain; }; +typedef enum _LinphoneIsComposingState { + LinphoneIsComposingIdle, + LinphoneIsComposingActive +} LinphoneIsComposingState; + struct _LinphoneChatRoom{ + belle_sip_object_t base; + void *user_data; struct _LinphoneCore *lc; char *peer; LinphoneAddress *peer_url; - void * user_data; + MSList *messages_hist; + MSList *transient_messages; + int unread_count; + LinphoneIsComposingState remote_is_composing; + LinphoneIsComposingState is_composing; + belle_sip_source_t *remote_composing_refresh_timer; + belle_sip_source_t *composing_idle_timer; + belle_sip_source_t *composing_refresh_timer; }; +BELLE_SIP_DECLARE_VPTR(LinphoneChatRoom); + - struct _LinphoneFriend{ + belle_sip_object_t base; + void *user_data; LinphoneAddress *uri; - SalOp *insub; + MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/ SalOp *outsub; LinphoneSubscribePolicy pol; - LinphoneOnlineStatus status; + LinphonePresenceModel *presence; struct _LinphoneCore *lc; BuddyInfo *info; char *refkey; @@ -409,8 +598,11 @@ struct _LinphoneFriend{ 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*/ }; +BELLE_SIP_DECLARE_VPTR(LinphoneFriend); + typedef struct sip_config { @@ -423,8 +615,6 @@ typedef struct sip_config int delayed_timeout; /*timeout after a delayed call is resumed */ unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/ LCSipTransports transports; - bool_t use_info; - bool_t use_rfc2833; /*force RFC2833 to be sent*/ bool_t guess_hostname; bool_t loopback_only; bool_t ipv6_enabled; @@ -434,6 +624,8 @@ typedef struct sip_config bool_t ping_with_options; bool_t auto_net_state_mon; bool_t tcp_tls_keepalive; + bool_t vfu_with_info; /*use to enable vfu request using sip info*/ + bool_t save_auth_info; // if true, auth infos will be write in the config file when they are added to the list } sip_config_t; typedef struct rtp_config @@ -445,11 +637,20 @@ typedef struct rtp_config int audio_jitt_comp; /*jitter compensation*/ int video_jitt_comp; /*jitter compensation*/ int nortp_timeout; + int disable_upnp; + MSCryptoSuite *srtp_suites; + LinphoneAVPFMode avpf_mode; bool_t rtp_no_xmit_on_audio_mute; - /* stop rtp xmit when audio muted */ + /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; bool_t video_adaptive_jitt_comp_enabled; bool_t pad; + char* audio_multicast_addr; + bool_t audio_multicast_enabled; + int audio_multicast_ttl; + char* video_multicast_addr; + int video_multicast_ttl; + bool_t video_multicast_enabled; }rtp_config_t; @@ -459,11 +660,12 @@ 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; + OrtpNetworkSimulatorParams netsim_params; bool_t nat_sdp_only; }net_config_t; @@ -493,18 +695,22 @@ typedef struct sound_config typedef struct codecs_config { MSList *audio_codecs; /* list of audio codecs in order of preference*/ - MSList *video_codecs; /* for later use*/ + MSList *video_codecs; + int dyn_pt; + int telephone_event_pt; }codecs_config_t; typedef struct video_config{ struct _MSWebCam *device; const char **cams; MSVideoSize vsize; + MSVideoSize preview_vsize; /*is 0,0 if no forced preview size is set, in which case vsize field above is used.*/ + float fps; bool_t capture; bool_t show_local; bool_t display; bool_t selfview; /*during calls*/ - const char *displaytype; + bool_t reuse_preview_source; }video_config_t; typedef struct ui_config @@ -533,17 +739,43 @@ struct _LinphoneConference{ MSAudioEndpoint *record_endpoint; RtpProfile *local_dummy_profile; bool_t local_muted; + bool_t terminated; }; + +typedef struct _LinphoneToneDescription{ + LinphoneReason reason; + LinphoneToneID toneid; + char *audiofile; +}LinphoneToneDescription; + +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile); +void linphone_tone_description_destroy(LinphoneToneDescription *obj); +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason); +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); +void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); +const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); +int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info); typedef struct _LinphoneConference LinphoneConference; +typedef struct _LinphoneTaskList{ + MSList *hooks; +}LinphoneTaskList; + +void linphone_task_list_init(LinphoneTaskList *t); +void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); +void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data); +void linphone_task_list_run(LinphoneTaskList *t); +void linphone_task_list_free(LinphoneTaskList *t); + struct _LinphoneCore { - LinphoneCoreVTable vtable; + MSList* vtable_refs; Sal *sal; LinphoneGlobalState state; struct _LpConfig *config; - RtpProfile *default_profile; + MSList *default_audio_codecs; + MSList *default_video_codecs; net_config_t net_conf; sip_config_t sip_conf; rtp_config_t rtp_conf; @@ -552,8 +784,6 @@ struct _LinphoneCore codecs_config_t codecs_conf; ui_config_t ui_conf; autoreplier_config_t autoreplier_conf; - MSList *payload_types; - int dyn_pt; LinphoneProxyConfig *default_proxy; MSList *friends; MSList *auth_info; @@ -573,48 +803,90 @@ 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; + int audio_bw; /*IP bw consumed by audio codec, set as soon as used codec is known, its purpose is to know the remaining bw for video*/ + LinphoneCoreWaitingCallback wait_cb; void *wait_ctx; - unsigned long video_window_id; - unsigned long preview_window_id; + void *video_window_id; + void *preview_window_id; time_t netup_time; /*time when network went reachable */ struct _EcCalibrator *ecc; - MSList *hooks; + LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/ LinphoneConference conf_ctx; char* zrtp_secrets_cache; + char* user_certificates_path; LinphoneVideoPolicy video_policy; + time_t network_last_check; + bool_t use_files; bool_t apply_nat_settings; bool_t initial_subscribes_sent; bool_t bl_refresh; - + bool_t preview_finished; bool_t auto_net_state_mon; bool_t network_reachable; - bool_t use_preview_window; - - time_t network_last_check; - bool_t network_last_status; + bool_t network_reachable_to_be_notified; /*set to true when state must be notified in next iterate*/ + bool_t use_preview_window; + bool_t network_last_status; bool_t ringstream_autorelease; - bool_t pad[3]; + bool_t vtables_running; + char localip[LINPHONE_IPADDR_SIZE]; int device_rotation; int max_calls; LinphoneTunnel *tunnel; char* device_id; MSList *last_recv_msg_ids; + char *chat_db_file; +#ifdef MSG_STORAGE_ENABLED + sqlite3 *db; + bool_t debug_storage; +#endif #ifdef BUILD_UPNP UpnpContext *upnp; #endif //BUILD_UPNP + belle_http_provider_t *http_provider; + belle_tls_verify_policy_t *http_verify_policy; + MSList *tones; + LinphoneReason chat_deny_code; + char *file_transfer_server; + const char **supported_formats; + LinphoneContent *log_collection_upload_information; + LinphoneCoreVTable *current_vtable; // the latest vtable to call a callback, see linphone_core_get_current_vtable +#ifdef ANDROID + jobject wifi_lock; + jclass wifi_lock_class; + jmethodID wifi_lock_acquire_id; + jmethodID wifi_lock_release_id; + jobject multicast_lock; + jclass multicast_lock_class; + jmethodID multicast_lock_acquire_id; + jmethodID multicast_lock_release_id; +#endif }; + +struct _LinphoneEvent{ + LinphoneSubscriptionDir dir; + LinphoneCore *lc; + SalOp *op; + SalCustomHeader *send_custom_headers; + LinphoneSubscriptionState subscription_state; + LinphonePublishState publish_state; + void *userdata; + int refcnt; + char *name; + int expires; + bool_t terminating; + bool_t is_out_of_dialog_op; /*used for out of dialog notify*/ +}; + + LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); void linphone_tunnel_destroy(LinphoneTunnel *tunnel); void linphone_tunnel_configure(LinphoneTunnel *tunnel); @@ -627,12 +899,15 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); -void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); -void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); +void linphone_call_make_local_media_description(LinphoneCall *call); +void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); +void linphone_call_increment_local_media_description(LinphoneCall *call); +void linphone_call_fill_media_multicast_addr(LinphoneCall *call); +void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state); -bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit); +bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); -#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup) +#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown) void _linphone_core_configure_resolver(); struct _EcCalibrator{ @@ -644,6 +919,8 @@ struct _EcCalibrator{ MSTicker *ticker; LinphoneEcCalibrationCallback cb; void *cb_data; + LinphoneEcCalibrationAudioInit audio_init_cb; + LinphoneEcCalibrationAudioUninit audio_uninit_cb; int64_t acc; int delay; unsigned int rate; @@ -659,6 +936,8 @@ void ec_calibrator_destroy(EcCalibrator *ecc); void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed); void linphone_core_preempt_sound_resources(LinphoneCore *lc); +int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); + /*conferencing subsystem*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted); /* When a conference participant pause the conference he may send a music. @@ -681,16 +960,357 @@ void _linphone_core_codec_config_write(LinphoneCore *lc); #ifndef NB_MAX_CALLS #define NB_MAX_CALLS (10) #endif +void call_logs_read_from_config_file(LinphoneCore *lc); void call_logs_write_to_config_file(LinphoneCore *lc); int linphone_core_get_edge_bw(LinphoneCore *lc); int linphone_core_get_edge_ptime(LinphoneCore *lc); -void _linphone_call_params_copy(LinphoneCallParams *params, const LinphoneCallParams *refparams); -void linphone_call_params_uninit(LinphoneCallParams *params); int linphone_upnp_init(LinphoneCore *lc); 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_state(LinphoneChatMessage *msg); +void linphone_chat_message_store_appdata(LinphoneChatMessage* msg); +void linphone_core_message_storage_init(LinphoneCore *lc); +void linphone_core_message_storage_close(LinphoneCore *lc); +void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); + +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); +bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); +const char *linphone_core_create_uuid(LinphoneCore *lc); +void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); +void linphone_call_create_op(LinphoneCall *call); +int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer); +void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); +LinphoneContent * linphone_content_new(void); +LinphoneContent * linphone_content_copy(const LinphoneContent *ref); +SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content); +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, int expires); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); +/** + * Useful for out of dialog notify + * */ +LinphoneEvent *linphone_event_new_with_out_of_dialog_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); +LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); +LinphoneContent *linphone_content_from_sal_body(const SalBody *ref); +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); + + +struct _LinphoneContent { + belle_sip_object_t base; + void *user_data; + struct _LinphoneContentPrivate lcp; + bool_t owned_fields; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneContent); + +struct _LinphoneBuffer { + belle_sip_object_t base; + void *user_data; + uint8_t *content; /**< A pointer to the buffer content */ + size_t size; /**< The size of the buffer content */ +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneBuffer); + + +/***************************************************************************** + * XML-RPC interface * + ****************************************************************************/ + +typedef struct _LinphoneXmlRpcArg { + LinphoneXmlRpcArgType type; + union { + int i; + char *s; + } data; +} LinphoneXmlRpcArg; + +struct _LinphoneXmlRpcRequestCbs { + belle_sip_object_t base; + void *user_data; + LinphoneXmlRpcRequestCbsResponseCb response; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneXmlRpcRequestCbs); + +struct _LinphoneXmlRpcRequest { + belle_sip_object_t base; + void *user_data; + LinphoneXmlRpcRequestCbs *callbacks; + belle_sip_list_t *arg_list; + char *content; /**< The string representation of the XML-RPC request */ + char *method; + LinphoneXmlRpcStatus status; + LinphoneXmlRpcArg response; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneXmlRpcRequest); + +struct _LinphoneXmlRpcSession { + belle_sip_object_t base; + void *user_data; + LinphoneCore *core; + char *url; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneXmlRpcSession); + + +/***************************************************************************** + * Account creator interface * + ****************************************************************************/ + +struct _LinphoneAccountCreatorCbs { + belle_sip_object_t base; + void *user_data; + LinphoneAccountCreatorCbsExistenceTestedCb existence_tested; + LinphoneAccountCreatorCbsValidationTestedCb validation_tested; + LinphoneAccountCreatorCbsValidatedCb validated; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneAccountCreatorCbs); + +struct _LinphoneAccountCreator { + belle_sip_object_t base; + void *user_data; + LinphoneAccountCreatorCbs *callbacks; + LinphoneXmlRpcSession *xmlrpc_session; + LinphoneCore *core; + char *xmlrpc_url; + char *username; + char *password; + char *domain; + char *route; + char *email; + bool_t subscribe_to_newsletter; + char *display_name; +}; + +BELLE_SIP_DECLARE_VPTR(LinphoneAccountCreator); + + +/***************************************************************************** + * REMOTE PROVISIONING FUNCTIONS * + ****************************************************************************/ + +void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); +int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); +LINPHONE_PUBLIC int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path); + +/***************************************************************************** + * Player interface + ****************************************************************************/ + +struct _LinphonePlayer{ + int (*open)(struct _LinphonePlayer* player, const char *filename); + int (*start)(struct _LinphonePlayer* player); + int (*pause)(struct _LinphonePlayer* player); + int (*seek)(struct _LinphonePlayer* player, int time_ms); + MSPlayerState (*get_state)(struct _LinphonePlayer* player); + int (*get_duration)(struct _LinphonePlayer *player); + int (*get_position)(struct _LinphonePlayer *player); + void (*close)(struct _LinphonePlayer* player); + void (*destroy)(struct _LinphonePlayer *player); + LinphonePlayerEofCallback cb; + void *user_data; + void *impl; +}; + +void _linphone_player_destroy(LinphonePlayer *player); + + +/***************************************************************************** + * XML UTILITY FUNCTIONS * + ****************************************************************************/ + +#include +#include +#include +#include + +#define XMLPARSING_BUFFER_LEN 2048 +#define MAX_XPATH_LENGTH 256 + +typedef struct _xmlparsing_context { + xmlDoc *doc; + xmlXPathContextPtr xpath_ctx; + char errorBuffer[XMLPARSING_BUFFER_LEN]; + char warningBuffer[XMLPARSING_BUFFER_LEN]; +} xmlparsing_context_t; + +xmlparsing_context_t * linphone_xmlparsing_context_new(void); +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx); +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...); +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx); +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +void linphone_free_xml_text_content(const char *text); +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); + +/***************************************************************************** + * OTHER UTILITY FUNCTIONS * + ****************************************************************************/ +char * linphone_timestamp_to_rfc3339_string(time_t timestamp); + + +static MS2_INLINE const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ + if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none(); + return (const LinphoneErrorInfo*)sal_op_get_error_info(op); +} + +static MS2_INLINE void payload_type_set_enable(PayloadType *pt,int value) +{ + if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ + else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); +} + +static MS2_INLINE bool_t payload_type_enabled(const PayloadType *pt) { + return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); +} + +bool_t is_payload_type_number_available(const MSList *l, int number, const PayloadType *ignore); + +const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_key_agreement_suites(LinphoneCore *lc, MSZrtpKeyAgreement keyAgreements[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_cipher_suites(LinphoneCore *lc, MSZrtpCipher ciphers[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_hash_suites(LinphoneCore *lc, MSZrtpHash hashes[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_auth_suites(LinphoneCore *lc, MSZrtpAuthTag authTags[MS_MAX_ZRTP_CRYPTO_TYPES]); +MsZrtpCryptoTypesCount linphone_core_get_zrtp_sas_suites(LinphoneCore *lc, MSZrtpSasType sasTypes[MS_MAX_ZRTP_CRYPTO_TYPES]); + +/** Belle Sip-based objects need unique ids + */ + +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) +BELLE_SIP_TYPE_ID(LinphoneAccountCreator), +BELLE_SIP_TYPE_ID(LinphoneAccountCreatorCbs), +BELLE_SIP_TYPE_ID(LinphoneBuffer), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneCall), +BELLE_SIP_TYPE_ID(LinphoneCallLog), +BELLE_SIP_TYPE_ID(LinphoneCallParams), +BELLE_SIP_TYPE_ID(LinphoneChatMessage), +BELLE_SIP_TYPE_ID(LinphoneChatMessageCbs), +BELLE_SIP_TYPE_ID(LinphoneChatRoom), +BELLE_SIP_TYPE_ID(LinphoneContent), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), +BELLE_SIP_TYPE_ID(LinphoneProxyConfig), +BELLE_SIP_TYPE_ID(LinphoneFriend), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs), +BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession) +BELLE_SIP_DECLARE_TYPES_END + + + +void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); +void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); +void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); +void linphone_core_notify_show_interface(LinphoneCore *lc); +void linphone_core_notify_display_status(LinphoneCore *lc, const char *message); +void linphone_core_notify_display_message(LinphoneCore *lc, const char *message); +void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message); +void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url); +void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); +void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); +void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl); +void linphone_core_notify_text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); +void linphone_core_notify_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +void linphone_core_notify_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size); +void linphone_core_notify_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); +void linphone_core_notify_file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); +void linphone_core_notify_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); +void linphone_core_notify_dtmf_received(LinphoneCore* lc, LinphoneCall *call, int dtmf); +/* + * return true if at least a registered vtable has a cb for dtmf received*/ +bool_t linphone_core_dtmf_received_has_listener(const LinphoneCore* lc); +void linphone_core_notify_refer_received(LinphoneCore *lc, const char *refer_to); +void linphone_core_notify_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); +void linphone_core_notify_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); +void linphone_core_notify_call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); +void linphone_core_notify_info_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); +void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable); + +void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); +void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); +void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); +void linphone_core_notify_log_collection_upload_state_changed(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info); +void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset, size_t total); + +void set_mic_gain_db(AudioStream *st, float gain); +void set_playback_gain_db(AudioStream *st, float gain); + +LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir); +SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir); + +/***************************************************************************** + * LINPHONE CONTENT PRIVATE ACCESSORS * + ****************************************************************************/ +/** + * Get the key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The key to encrypt/decrypt the file associated to this content. + */ +const char *linphone_content_get_key(const LinphoneContent *content); + +/** + * Get the size of key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The key size in bytes + */ +size_t linphone_content_get_key_size(const LinphoneContent *content); +/** + * Set the key associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @param[in] key The key to be used to encrypt/decrypt file associated to this content. + */ +void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength); + +/** + * Get the address of the crypto context associated with a RCS file transfer message if encrypted + * @param[in] content LinphoneContent object. + * @return The address of the pointer to the crypto context. Crypto context is managed(alloc/free) + * by the encryption/decryption functions, so we give the address to store/retrieve the pointer + */ +void ** linphone_content_get_cryptoContext_address(LinphoneContent *content); + +#ifdef ANDROID +void linphone_core_wifi_lock_acquire(LinphoneCore *lc); +void linphone_core_wifi_lock_release(LinphoneCore *lc); +void linphone_core_multicast_lock_acquire(LinphoneCore *lc); +void linphone_core_multicast_lock_release(LinphoneCore *lc); +#endif + +struct _VTableReference{ + LinphoneCoreVTable *vtable; + bool_t valid; + bool_t autorelease; +}; + +typedef struct _VTableReference VTableReference; + +void v_table_reference_destroy(VTableReference *ref); + +void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease); +#ifdef VIDEO_ENABLED +LINPHONE_PUBLIC MSWebCam *linphone_call_get_video_device(const LinphoneCall *call); +MSWebCam *get_nowebcam_device(); +#endif +bool_t linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc); + #ifdef __cplusplus } #endif diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5546102ba..5378236a1 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -17,21 +17,76 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) * 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 "sipsetup.h" #include "lpconfig.h" #include "private.h" #include "mediastreamer2/mediastream.h" +#include "enum.h" #include +/*store current config related to server location*/ +static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* cfg) { + if (cfg->saved_identity) linphone_address_destroy(cfg->saved_identity); + if (cfg->identity_address) + cfg->saved_identity = linphone_address_clone(cfg->identity_address); + else + cfg->saved_identity = NULL; + + if (cfg->saved_proxy) linphone_address_destroy(cfg->saved_proxy); + if (cfg->reg_proxy) + cfg->saved_proxy = linphone_address_new(cfg->reg_proxy); + else + cfg->saved_proxy = NULL; +} + +LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b) { + if (a == NULL && b == NULL) + return LinphoneProxyConfigAddressEqual; + else if (!a || !b) + return LinphoneProxyConfigAddressDifferent; + + if (linphone_address_equal(a,b)) + return LinphoneProxyConfigAddressEqual; + if (linphone_address_weak_equal(a,b)) { + /*also check both transport and uri */ + if (linphone_address_is_secure(a) == linphone_address_is_secure(b) && linphone_address_get_transport(a) == linphone_address_get_transport(b)) + return LinphoneProxyConfigAddressWeakEqual; + else + return LinphoneProxyConfigAddressDifferent; + } + return LinphoneProxyConfigAddressDifferent; /*either username, domain or port ar not equals*/ +} + +LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* cfg) { + LinphoneAddress *current_proxy=cfg->reg_proxy?linphone_address_new(cfg->reg_proxy):NULL; + LinphoneProxyConfigAddressComparisonResult result_identity; + LinphoneProxyConfigAddressComparisonResult result; + + result = linphone_proxy_config_address_equal(cfg->saved_identity,cfg->identity_address); + if (result == LinphoneProxyConfigAddressDifferent) goto end; + result_identity = result; + + result = linphone_proxy_config_address_equal(cfg->saved_proxy,current_proxy); + if (result == LinphoneProxyConfigAddressDifferent) goto end; + /** If the proxies are equal use the result of the difference between the identities, + * otherwise the result is weak-equal and so weak-equal must be returned even if the + * identities were equal. + */ + if (result == LinphoneProxyConfigAddressEqual) result = result_identity; + + end: + if (current_proxy) linphone_address_destroy(current_proxy); + return result; +} void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ MSList *elem; int i; if (!linphone_core_ready(lc)) return; - + for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; linphone_proxy_config_write_to_config_file(lc->config,cfg,i); @@ -41,77 +96,118 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL)); } -static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){ - memset(obj,0,sizeof(LinphoneProxyConfig)); - obj->magic=linphone_proxy_config_magic; - obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600); - obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0')); - obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0); +static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cfg) { + const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL; + const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL; + const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL; + const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; + const char *realm = lc ? lp_config_get_default_string(lc->config, "proxy", "realm", NULL) : NULL; + const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL; + const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL; + const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL; + + cfg->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600; + cfg->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1; + cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; + cfg->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; + cfg->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; + cfg->identity_address = identity ? linphone_address_new(identity) : NULL; + cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL; + cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL; + cfg->reg_route = route ? ms_strdup(route) : NULL; + cfg->realm = realm ? ms_strdup(realm) : NULL; + cfg->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; + cfg->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; + cfg->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0; + cfg->contact_params = contact_params ? ms_strdup(contact_params) : NULL; + cfg->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; + cfg->avpf_mode = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", LinphoneAVPFDefault) : LinphoneAVPFDefault; + cfg->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5; + cfg->publish_expires=-1; } -/** - * @addtogroup proxies - * @{ -**/ - -/** - * @deprecated, use #linphone_core_create_proxy_config instead - *Creates an empty proxy config. -**/ LinphoneProxyConfig *linphone_proxy_config_new() { return linphone_core_create_proxy_config(NULL); } + +static void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneProxyConfig); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneProxyConfig, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_proxy_config_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) { - LinphoneProxyConfig *obj=NULL; - obj=ms_new(LinphoneProxyConfig,1); - linphone_proxy_config_init(lc,obj); - return obj; + LinphoneProxyConfig *cfg = belle_sip_object_new(LinphoneProxyConfig); + linphone_proxy_config_init(lc,cfg); + return cfg; } - - -/** - * Destroys a proxy config. - * - * @note: LinphoneProxyConfig that have been removed from LinphoneCore with - * linphone_core_remove_proxy_config() must not be freed. -**/ -void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ - if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); - if (obj->reg_identity!=NULL) ms_free(obj->reg_identity); - if (obj->reg_route!=NULL) ms_free(obj->reg_route); - if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx); - if (obj->realm!=NULL) ms_free(obj->realm); - if (obj->type!=NULL) ms_free(obj->type); - 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); +void _linphone_proxy_config_release_ops(LinphoneProxyConfig *cfg){ + if (cfg->op) { + sal_op_release(cfg->op); + cfg->op=NULL; + } + if (cfg->publish_op){ + sal_op_release(cfg->publish_op); + cfg->publish_op=NULL; + } } -/** - * Returns a boolean indicating that the user is sucessfully registered on the proxy. -**/ -bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ - return obj->state == LinphoneRegistrationOk; +void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){ + if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy); + if (cfg->reg_identity!=NULL) ms_free(cfg->reg_identity); + if (cfg->identity_address!=NULL) linphone_address_destroy(cfg->identity_address); + if (cfg->reg_route!=NULL) ms_free(cfg->reg_route); + if (cfg->quality_reporting_collector!=NULL) ms_free(cfg->quality_reporting_collector); + if (cfg->ssctx!=NULL) sip_setup_context_free(cfg->ssctx); + if (cfg->realm!=NULL) ms_free(cfg->realm); + if (cfg->type!=NULL) ms_free(cfg->type); + if (cfg->dial_prefix!=NULL) ms_free(cfg->dial_prefix); + if (cfg->contact_params) ms_free(cfg->contact_params); + if (cfg->contact_uri_params) ms_free(cfg->contact_uri_params); + if (cfg->saved_proxy!=NULL) linphone_address_destroy(cfg->saved_proxy); + if (cfg->saved_identity!=NULL) linphone_address_destroy(cfg->saved_identity); + if (cfg->sent_headers!=NULL) sal_custom_header_free(cfg->sent_headers); + if (cfg->pending_contact) linphone_address_unref(cfg->pending_contact); + _linphone_proxy_config_release_ops(cfg); } -/** - * Sets the proxy address - * - * Examples of valid sip proxy address are: - * - IP address: sip:87.98.157.38 - * - IP address with port: sip:87.98.157.38:5062 - * - hostnames : sip:sip.example.net -**/ -int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ +void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg) { + belle_sip_object_unref(cfg); +} + +void _linphone_proxy_config_release(LinphoneProxyConfig *cfg) { + _linphone_proxy_config_release_ops(cfg); + belle_sip_object_unref(cfg); +} + +LinphoneProxyConfig *linphone_proxy_config_ref(LinphoneProxyConfig *cfg) { + belle_sip_object_ref(cfg); + return cfg; +} + +void linphone_proxy_config_unref(LinphoneProxyConfig *cfg) { + belle_sip_object_unref(cfg); +} + +bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg){ + return cfg->state == LinphoneRegistrationOk; +} + +int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr){ LinphoneAddress *addr=NULL; char *modified=NULL; - - if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); - obj->reg_proxy=NULL; - + + if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy); + cfg->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); @@ -119,7 +215,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * if (addr==NULL) addr=linphone_address_new(server_addr); if (addr){ - obj->reg_proxy=linphone_address_as_string(addr); + cfg->reg_proxy=linphone_address_as_string(addr); linphone_address_destroy(addr); }else{ ms_warning("Could not parse %s",server_addr); @@ -129,43 +225,38 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * return 0; } -/** - * Sets the user identity as a SIP address. - * - * This identity is normally formed with display name, username and domain, such - * as: - * Alice - * The REGISTER messages will have from and to set to this identity. - * -**/ -int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){ - LinphoneAddress *addr; + +int linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *addr){ + if (!addr || linphone_address_get_username(addr)==NULL){ + char* as_string = linphone_address_as_string(addr); + ms_warning("Invalid sip identity: %s", addr?as_string:"NULL"); + ms_free(as_string); + return -1; + } + if (cfg->identity_address != NULL) { + linphone_address_destroy(cfg->identity_address); + } + cfg->identity_address=linphone_address_clone(addr); + + if (cfg->reg_identity!=NULL) { + ms_free(cfg->reg_identity); + } + cfg->reg_identity= linphone_address_as_string(cfg->identity_address); + return 0; +} + +int linphone_proxy_config_set_identity(LinphoneProxyConfig *cfg, const char *identity){ if (identity!=NULL && strlen(identity)>0){ - addr=linphone_address_new(identity); - if (!addr || linphone_address_get_username(addr)==NULL){ - ms_warning("Invalid sip identity: %s",identity); - if (addr) - linphone_address_destroy(addr); - return -1; - }else{ - if (obj->reg_identity!=NULL) { - ms_free(obj->reg_identity); - obj->reg_identity=NULL; - } - obj->reg_identity=ms_strdup(identity); - if (obj->realm){ - ms_free(obj->realm); - } - obj->realm=ms_strdup(linphone_address_get_domain(addr)); - linphone_address_destroy(addr); - return 0; - } + LinphoneAddress *addr=linphone_address_new(identity); + int ret=linphone_proxy_config_set_identity_address(cfg, addr); + linphone_address_destroy(addr); + return ret; } return -1; } const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ - return cfg->realm; + return cfg->identity_address ? linphone_address_get_domain(cfg->identity_address) : NULL; } /** @@ -173,17 +264,17 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ * When a route is set, all outgoing calls will go to the route's destination if this proxy * is the default one (see linphone_core_set_default_proxy() ). **/ -int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) +int linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route) { - if (obj->reg_route!=NULL){ - ms_free(obj->reg_route); - obj->reg_route=NULL; + if (cfg->reg_route!=NULL){ + ms_free(cfg->reg_route); + cfg->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); @@ -193,158 +284,183 @@ int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) ms_free(tmp); tmp=NULL; } - obj->reg_route=tmp; + cfg->reg_route=tmp; } return 0; } -bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){ - if (obj->reg_proxy==NULL){ - if (lc->vtable.display_warning) - lc->vtable.display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\"" +bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){ + if (cfg->reg_proxy==NULL){ + if (lc) + linphone_core_notify_display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\"" " followed by a hostname.")); return FALSE; } - if (obj->reg_identity==NULL){ - if (lc->vtable.display_warning) - lc->vtable.display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like " + if (cfg->identity_address==NULL){ + if (lc) + linphone_core_notify_display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like " "sip:username@proxydomain, such as sip:alice@example.net")); return FALSE; } return TRUE; } -/** - * Indicates whether a REGISTER request must be sent to the proxy. -**/ -void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){ - obj->reg_sendregister=val; +void linphone_proxy_config_enableregister(LinphoneProxyConfig *cfg, bool_t val){ + cfg->reg_sendregister=val; } -/** - * Sets the registration expiration time in seconds. -**/ -void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){ +void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int val){ if (val<0) val=600; - obj->expires=val; + cfg->expires=val; } -void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ - obj->publish=val; +void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val){ + cfg->publish=val; } -/** - * Starts editing a proxy configuration. - * - * Because proxy configuration must be consistent, applications MUST - * call linphone_proxy_config_edit() before doing any attempts to modify - * proxy configuration (such as identity, proxy address and so on). - * Once the modifications are done, then the application must call - * linphone_proxy_config_done() to commit the changes. -**/ -void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ - if (obj->reg_sendregister){ - /* unregister */ - if (obj->state != LinphoneRegistrationNone && obj->state != LinphoneRegistrationCleared) { - sal_unregister(obj->op); - } + +void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){ + if (cfg->op) sal_op_stop_refreshing(cfg->op); +} + +void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){ + if (cfg->publish && cfg->publish_op){ + /*unpublish*/ + sal_publish_presence(cfg->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL); + sal_op_release(cfg->publish_op); + cfg->publish_op=NULL; + } + /*store current config related to server location*/ + linphone_proxy_config_store_server_config(cfg); + + /*stop refresher in any case*/ + linphone_proxy_config_pause_register(cfg); +} + +void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){ + cfg->lc=lc; + linphone_proxy_config_done(cfg); +} + +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){ + LinphoneAddress *contact_addr=NULL; + if ( cfg->op + && cfg->state == LinphoneRegistrationOk + && (contact_addr = (LinphoneAddress*)sal_op_get_contact_address(cfg->op)) + && linphone_address_get_transport(contact_addr) != LinphoneTransportUdp /*with udp, there is a risk of port reuse, so I prefer to not do anything for now*/) { + /*need to save current contact in order to reset is later*/ + linphone_address_ref(contact_addr); + if (cfg->pending_contact) + linphone_address_unref(cfg->pending_contact); + cfg->pending_contact=contact_addr; + + } + if (cfg->publish_op){ + sal_op_release(cfg->publish_op); + cfg->publish_op=NULL; + } + if (cfg->op){ + sal_op_release(cfg->op); + cfg->op=NULL; } } -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){ - LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); - char *ret=NULL; +LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){ + LinphoneAddress *ret=NULL; + LinphoneAddress *proxy=linphone_address_new(cfg->reg_proxy); const char *host; + if (proxy==NULL) return NULL; - host=linphone_address_get_domain (proxy); + host=linphone_address_get_domain(proxy); if (host!=NULL){ int localport = -1; - char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'}; const char *localip = NULL; - char *tmp; - LCSipTransports tr; - LinphoneAddress *contact; - - contact=linphone_address_new(obj->reg_identity); + LinphoneAddress *contact=linphone_address_clone(cfg->identity_address); + + linphone_address_clean(contact); + + if (cfg->contact_params) { + // We want to add a list of contacts params to the linphone address + sal_address_set_params(contact,cfg->contact_params); + } + if (cfg->contact_uri_params){ + sal_address_set_uri_params(contact,cfg->contact_uri_params); + } #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) { - localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp); - localport = linphone_upnp_context_get_external_port(obj->lc->upnp); + if (cfg->lc->upnp != NULL && linphone_core_get_firewall_policy(cfg->lc)==LinphonePolicyUseUpnp && + linphone_upnp_context_get_state(cfg->lc->upnp) == LinphoneUpnpStateOk) { + localip = linphone_upnp_context_get_external_ipaddress(cfg->lc->upnp); + localport = linphone_upnp_context_get_external_port(cfg->lc->upnp); } -#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); - ms_free(tmp); + + ret=contact; } - linphone_address_destroy (proxy); + linphone_address_destroy(proxy); return ret; } -static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ - if (obj->reg_sendregister){ - char *contact; - 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); - sal_op_set_user_pointer(obj->op,obj); - if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { - linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress"); +void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) { + if (obj->op && (obj->state == LinphoneRegistrationOk || + (obj->state == LinphoneRegistrationProgress && obj->expires != 0))) { + sal_unregister(obj->op); + } +} + +static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ + if (cfg->reg_sendregister){ + LinphoneAddress* proxy=linphone_address_new(cfg->reg_proxy); + char* proxy_string; + char * from = linphone_address_as_string(cfg->identity_address); + LinphoneAddress *contact; + ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",cfg,linphone_core_get_version()); + proxy_string=linphone_address_as_string_uri_only(proxy); + linphone_address_destroy(proxy); + if (cfg->op) + sal_op_release(cfg->op); + cfg->op=sal_op_new(cfg->lc->sal); + + linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE); + + if ((contact=guess_contact_for_register(cfg))) { + sal_op_set_contact_address(cfg->op,contact); + linphone_address_destroy(contact); + } + + sal_op_set_user_pointer(cfg->op,cfg); + + + if (sal_register(cfg->op,proxy_string, cfg->reg_identity, cfg->expires, cfg->pending_contact)==0) { + if (cfg->pending_contact) { + linphone_address_unref(cfg->pending_contact); + cfg->pending_contact=NULL; + } + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,"Registration in progress"); } else { - linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed"); + linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,"Registration failed"); } + ms_free(proxy_string); + ms_free(from); + } else { + /* unregister if registered*/ + if (cfg->state == LinphoneRegistrationProgress) { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationCleared,"Registration cleared"); + } + _linphone_proxy_config_unregister(cfg); } } -/** - * Refresh a proxy registration. - * This is useful if for example you resuming from suspend, thus IP address may have changed. -**/ -void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){ - if (obj->reg_sendregister && obj->op){ - if (sal_register_refresh(obj->op,obj->expires) == 0) { - linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress, "Refresh registration"); +void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg){ + if (cfg->reg_sendregister && cfg->op && cfg->state!=LinphoneRegistrationProgress){ + if (sal_register_refresh(cfg->op,cfg->expires) == 0) { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress, "Refresh registration"); } } } -/** - * Sets a dialing prefix to be automatically prepended when inviting a number with - * linphone_core_invite(); - * This dialing prefix shall usually be the country code of the country where the user is living. - * -**/ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix){ if (cfg->dial_prefix!=NULL){ ms_free(cfg->dial_prefix); @@ -353,32 +469,57 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char if (prefix && prefix[0]!='\0') cfg->dial_prefix=ms_strdup(prefix); } -/** - * Returns dialing prefix. - * - * -**/ const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){ return cfg->dial_prefix; } -/** - * Sets whether liblinphone should replace "+" by international calling prefix in dialed numbers (passed to - * #linphone_core_invite ). - * -**/ void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val){ cfg->dial_escape_plus=val; } -/** - * Returns whether liblinphone should replace "+" by "00" in dialed numbers (passed to - * #linphone_core_invite ). - * -**/ bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){ return cfg->dial_escape_plus; } + +void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){ + cfg->quality_reporting_enabled = val; +} + +bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){ + return cfg->quality_reporting_enabled; +} + +void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) { + cfg->quality_reporting_interval = interval; +} + +int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { + return cfg->quality_reporting_interval; +} + +void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){ + if (collector!=NULL && strlen(collector)>0){ + LinphoneAddress *addr=linphone_address_new(collector); + if (!addr){ + ms_error("Invalid SIP collector URI: %s. Quality reporting will be DISABLED.",collector); + } else { + if (cfg->quality_reporting_collector != NULL){ + ms_free(cfg->quality_reporting_collector); + } + cfg->quality_reporting_collector = ms_strdup(collector); + } + + if (addr){ + linphone_address_destroy(addr); + } + } +} + +const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){ + return cfg->quality_reporting_collector; +} + + /* * http://en.wikipedia.org/wiki/Telephone_numbering_plan * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe @@ -389,12 +530,11 @@ typedef struct dial_plan{ char ccc[8]; /*country calling code*/ int nnl; /*maximum national number length*/ const char * icp; /*international call prefix, ex: 00 in europe*/ - + }dial_plan_t; -/* TODO: fill with information for all countries over the world*/ - static dial_plan_t const dial_plans[]={ + //Country , iso country code, e164 country calling code, number length, international usual prefix {"Afghanistan" ,"AF" , "93" , 9 , "00" }, {"Albania" ,"AL" , "355" , 9 , "00" }, {"Algeria" ,"DZ" , "213" , 9 , "00" }, @@ -413,7 +553,7 @@ static dial_plan_t const dial_plans[]={ {"Bahrain" ,"BH" , "973" , 8 , "00" }, {"Bangladesh" ,"BD" , "880" , 10 , "00" }, {"Barbados" ,"BB" , "1" , 10 , "011" }, - {"Belarus" ,"BY" , "375" , 9 , "00" }, + {"Belarus" ,"BY" , "375" , 9 , "00" }, {"Belgium" ,"BE" , "32" , 9 , "00" }, {"Belize" ,"BZ" , "501" , 7 , "00" }, {"Benin" ,"BJ" , "229" , 8 , "00" }, @@ -422,12 +562,12 @@ static dial_plan_t const dial_plans[]={ {"Bolivia" ,"BO" , "591" , 8 , "00" }, {"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" }, {"Botswana" ,"BW" , "267" , 8 , "00" }, - {"Brazil" ,"BR" , "55" , 10 , "00" }, + {"Brazil" ,"BR" , "55" , 10 , "00" }, {"Brunei Darussalam" ,"BN" , "673" , 7 , "00" }, {"Bulgaria" ,"BG" , "359" , 9 , "00" }, {"Burkina Faso" ,"BF" , "226" , 8 , "00" }, {"Burundi" ,"BI" , "257" , 8 , "011" }, - {"Cambodia" ,"KH" , "855" , 9 , "00" }, + {"Cambodia" ,"KH" , "855" , 9 , "00" }, {"Cameroon" ,"CM" , "237" , 8 , "00" }, {"Canada" ,"CA" , "1" , 10 , "011" }, {"Cape Verde" ,"CV" , "238" , 7 , "00" }, @@ -436,188 +576,190 @@ static dial_plan_t const dial_plans[]={ {"Chad" ,"TD" , "235" , 8 , "00" }, {"Chile" ,"CL" , "56" , 9 , "00" }, {"China" ,"CN" , "86" , 11 , "00" }, - {"Colombia" ,"CO" , "57" , 10 , "00" }, - {"Comoros" ,"KM" , "269" , 7 , "00" }, - {"Congo" ,"CG" , "242" , 9 , "00" }, - {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, - {"Cook Islands" ,"CK" , "682" , 5 , "00" }, - {"Costa Rica" ,"CR" , "506" , 8 , "00" }, - {"C�te d'Ivoire" ,"AD" , "225" , 8 , "00" }, - {"Croatia" ,"HR" , "385" , 9 , "00" }, - {"Cuba" ,"CU" , "53" , 8 , "119" }, - {"Cyprus" ,"CY" , "357" , 8 , "00" }, - {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, - {"Denmark" ,"DK" , "45" , 8 , "00" }, - {"Djibouti" ,"DJ" , "253" , 8 , "00" }, - {"Dominica" ,"DM" , "1" , 10 , "011" }, - {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, - {"Ecuador" ,"EC" , "593" , 9 , "00" }, - {"Egypt" ,"EG" , "20" , 10 , "00" }, - {"El Salvador" ,"SV" , "503" , 8 , "00" }, - {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, - {"Eritrea" ,"ER" , "291" , 7 , "00" }, - {"Estonia" ,"EE" , "372" , 8 , "00" }, - {"Ethiopia" ,"ET" , "251" , 9 , "00" }, - {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, - {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, - {"Fiji" ,"FJ" , "679" , 7 , "00" }, - {"Finland" ,"FI" , "358" , 9 , "00" }, - {"France" ,"FR" , "33" , 9 , "00" }, - {"French Guiana" ,"GF" , "594" , 9 , "00" }, - {"French Polynesia" ,"PF" , "689" , 6 , "00" }, - {"Gabon" ,"GA" , "241" , 8 , "00" }, - {"Gambia" ,"GM" , "220" , 7 , "00" }, - {"Georgia" ,"GE" , "995" , 9 , "00" }, - {"Germany" ,"DE" , "49" , 11 , "00" }, - {"Ghana" ,"GH" , "233" , 9 , "00" }, - {"Gibraltar" ,"GI" , "350" , 8 , "00" }, - {"Greece" ,"GR" , "30" ,10 , "00" }, - {"Greenland" ,"GL" , "299" , 6 , "00" }, - {"Grenada" ,"GD" , "1" , 10 , "011" }, - {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, - {"Guam" ,"GU" , "1" , 10 , "011" }, - {"Guatemala" ,"GT" , "502" , 8 , "00" }, - {"Guinea" ,"GN" , "224" , 8 , "00" }, - {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, - {"Guyana" ,"GY" , "592" , 7 , "001" }, - {"Haiti" ,"HT" , "509" , 8 , "00" }, - {"Honduras" ,"HN" , "504" , 8 , "00" }, - {"Hong Kong" ,"HK" , "852" , 8 , "001" }, - {"Hungary" ,"HU" , "36" , 9 , "00" }, - {"Iceland" ,"IS" , "354" , 9 , "00" }, - {"India" ,"IN" , "91" , 10 , "00" }, - {"Indonesia" ,"ID" , "62" , 10 , "001" }, - {"Iran" ,"IR" , "98" , 10 , "00" }, - {"Iraq" ,"IQ" , "964" , 10 , "00" }, - {"Ireland" ,"IE" , "353" , 9 , "00" }, - {"Israel" ,"IL" , "972" , 9 , "00" }, - {"Italy" ,"IT" , "39" , 10 , "00" }, - {"Jamaica" ,"JM" , "1" , 10 , "011" }, - {"Japan" ,"JP" , "81" , 10 , "010" }, - {"Jordan" ,"JO" , "962" , 9 , "00" }, - {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, - {"Kenya" ,"KE" , "254" , 9 , "000" }, - {"Kiribati" ,"KI" , "686" , 5 , "00" }, - {"Korea, North" ,"KP" , "850" , 12 , "99" }, - {"Korea, South" ,"KR" , "82" , 12 , "001" }, - {"Kuwait" ,"KW" , "965" , 8 , "00" }, - {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, - {"Laos" ,"LA" , "856" , 10 , "00" }, - {"Latvia" ,"LV" , "371" , 8 , "00" }, - {"Lebanon" ,"LB" , "961" , 7 , "00" }, - {"Lesotho" ,"LS" , "266" , 8 , "00" }, - {"Liberia" ,"LR" , "231" , 8 , "00" }, - {"Libya" ,"LY" , "218" , 8 , "00" }, - {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, - {"Lithuania" ,"LT" , "370" , 8 , "00" }, - {"Luxembourg" ,"LU" , "352" , 9 , "00" }, - {"Macau" ,"MO" , "853" , 8 , "00" }, - {"Macedonia" ,"MK" , "389" , 8 , "00" }, - {"Madagascar" ,"MG" , "261" , 9 , "00" }, - {"Malawi" ,"MW" , "265" , 9 , "00" }, - {"Malaysia" ,"MY" , "60" , 9 , "00" }, - {"Maldives" ,"MV" , "960" , 7 , "00" }, - {"Mali" ,"ML" , "223" , 8 , "00" }, - {"Malta" ,"MT" , "356" , 8 , "00" }, - {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, - {"Martinique" ,"MQ" , "596" , 9 , "00" }, - {"Mauritania" ,"MR" , "222" , 8 , "00" }, - {"Mauritius" ,"MU" , "230" , 7 , "00" }, - {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, - {"Mexico" ,"MX" , "52" , 10 , "00" }, - {"Micronesia" ,"FM" , "691" , 7 , "011" }, - {"Moldova" ,"MD" , "373" , 8 , "00" }, - {"Monaco" ,"MC" , "377" , 8 , "00" }, - {"Mongolia" ,"MN" , "976" , 8 , "001" }, - {"Montenegro" ,"ME" , "382" , 8 , "00" }, - {"Montserrat" ,"MS" , "664" , 10 , "011" }, - {"Morocco" ,"MA" , "212" , 9 , "00" }, - {"Mozambique" ,"MZ" , "258" , 9 , "00" }, - {"Myanmar" ,"MM" , "95" , 8 , "00" }, - {"Namibia" ,"NA" , "264" , 9 , "00" }, - {"Nauru" ,"NR" , "674" , 7 , "00" }, - {"Nepal" ,"NP" , "43" , 10 , "00" }, - {"Netherlands" ,"NL" , "31" , 9 , "00" }, - {"New Caledonia" ,"NC" , "687" , 6 , "00" }, - {"New Zealand" ,"NZ" , "64" , 10 , "00" }, - {"Nicaragua" ,"NI" , "505" , 8 , "00" }, - {"Niger" ,"NE" , "227" , 8 , "00" }, - {"Nigeria" ,"NG" , "234" , 10 , "009" }, - {"Niue" ,"NU" , "683" , 4 , "00" }, - {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, - {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, - {"Norway" ,"NO" , "47" , 8 , "00" }, - {"Oman" ,"OM" , "968" , 8 , "00" }, - {"Pakistan" ,"PK" , "92" , 10 , "00" }, - {"Palau" ,"PW" , "680" , 7 , "011" }, - {"Palestine" ,"PS" , "970" , 9 , "00" }, - {"Panama" ,"PA" , "507" , 8 , "00" }, - {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, - {"Paraguay" ,"PY" , "595" , 9 , "00" }, - {"Peru" ,"PE" , "51" , 9 , "00" }, - {"Philippines" ,"PH" , "63" , 10 , "00" }, - {"Poland" ,"PL" , "48" , 9 , "00" }, - {"Portugal" ,"PT" , "351" , 9 , "00" }, - {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, - {"Qatar" ,"QA" , "974" , 8 , "00" }, - {"R�union Island" ,"RE" , "262" , 9 , "011" }, - {"Romania" ,"RO" , "40" , 9 , "00" }, - {"Russian Federation" ,"RU" , "7" , 10 , "8" }, - {"Rwanda" ,"RW" , "250" , 9 , "00" }, - {"Saint Helena" ,"SH" , "290" , 4 , "00" }, - {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, - {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, - {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, - {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, - {"Samoa" ,"WS" , "685" , 7 , "0" }, - {"San Marino" ,"SM" , "378" , 10 , "00" }, - {"S�o Tom� and Pr�ncipe" ,"ST" , "239" , 7 , "00" }, - {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, - {"Senegal" ,"SN" , "221" , 9 , "00" }, - {"Serbia" ,"RS" , "381" , 9 , "00" }, - {"Seychelles" ,"SC" , "248" , 7 , "00" }, - {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, - {"Singapore" ,"SG" , "65" , 8 , "001" }, - {"Slovakia" ,"SK" , "421" , 9 , "00" }, - {"Slovenia" ,"SI" , "386" , 8 , "00" }, - {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, - {"Somalia" ,"SO" , "252" , 8 , "00" }, - {"South Africa" ,"ZA" , "27" , 9 , "00" }, - {"Spain" ,"ES" , "34" , 9 , "00" }, - {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, - {"Sudan" ,"SD" , "249" , 9 , "00" }, - {"Suriname" ,"SR" , "597" , 7 , "00" }, - {"Swaziland" ,"SZ" , "268" , 8 , "00" }, - {"Sweden" ,"SE" , "1" , 9 , "00" }, - {"Switzerland" ,"XK" , "41" , 9 , "00" }, - {"Syria" ,"SY" , "963" , 9 , "00" }, - {"Taiwan" ,"TW" , "886" , 9 , "810" }, - {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, - {"Tanzania" ,"TZ" , "255" , 9 , "000" }, - {"Thailand" ,"TH" , "66" , 9 , "001" }, - {"Togo" ,"TG" , "228" , 8 , "00" }, - {"Tokelau" ,"TK" , "690" , 4 , "00" }, - {"Tonga" ,"TO" , "676" , 5 , "00" }, - {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, - {"Tunisia" ,"TN" , "216" , 8 , "00" }, - {"Turkey" ,"TR" , "90" , 10 , "00" }, - {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, - {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, - {"Tuvalu" ,"TV" , "688" , 5 , "00" }, - {"Uganda" ,"UG" , "256" , 9 , "000" }, - {"Ukraine" ,"UA" , "380" , 9 , "00" }, - {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, - {"United Kingdom" ,"UK" , "44" , 10 , "00" }, - {"United States" ,"US" , "1" , 10 , "011" }, - {"Uruguay" ,"UY" , "598" , 8 , "00" }, - {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, - {"Vanuatu" ,"VU" , "678" , 7 , "00" }, - {"Venezuela" ,"VE" , "58" , 10 , "00" }, - {"Vietnam" ,"VN" , "84" , 9 , "00" }, - {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, - {"Yemen" ,"YE" , "967" , 9 , "00" }, - {"Zambia" ,"ZM" , "260" , 9 , "00" }, - {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, + {"Colombia" ,"CO" , "57" , 10 , "00" }, + {"Comoros" ,"KM" , "269" , 7 , "00" }, + {"Congo" ,"CG" , "242" , 9 , "00" }, + {"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" }, + {"Cook Islands" ,"CK" , "682" , 5 , "00" }, + {"Costa Rica" ,"CR" , "506" , 8 , "00" }, + {"Cote d'Ivoire" ,"AD" , "225" , 8 , "00" }, + {"Croatia" ,"HR" , "385" , 9 , "00" }, + {"Cuba" ,"CU" , "53" , 8 , "119" }, + {"Cyprus" ,"CY" , "357" , 8 , "00" }, + {"Czech Republic" ,"CZ" , "420" , 9 , "00" }, + {"Denmark" ,"DK" , "45" , 8 , "00" }, + {"Djibouti" ,"DJ" , "253" , 8 , "00" }, + {"Dominica" ,"DM" , "1" , 10 , "011" }, + {"Dominican Republic" ,"DO" , "1" , 10 , "011" }, + {"Ecuador" ,"EC" , "593" , 9 , "00" }, + {"Egypt" ,"EG" , "20" , 10 , "00" }, + {"El Salvador" ,"SV" , "503" , 8 , "00" }, + {"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" }, + {"Eritrea" ,"ER" , "291" , 7 , "00" }, + {"Estonia" ,"EE" , "372" , 8 , "00" }, + {"Ethiopia" ,"ET" , "251" , 9 , "00" }, + {"Falkland Islands" ,"FK" , "500" , 5 , "00" }, + {"Faroe Islands" ,"FO" , "298" , 6 , "00" }, + {"Fiji" ,"FJ" , "679" , 7 , "00" }, + {"Finland" ,"FI" , "358" , 9 , "00" }, + {"France" ,"FR" , "33" , 9 , "00" }, + {"French Guiana" ,"GF" , "594" , 9 , "00" }, + {"French Polynesia" ,"PF" , "689" , 6 , "00" }, + {"Gabon" ,"GA" , "241" , 8 , "00" }, + {"Gambia" ,"GM" , "220" , 7 , "00" }, + {"Georgia" ,"GE" , "995" , 9 , "00" }, + {"Germany" ,"DE" , "49" , 11 , "00" }, + {"Ghana" ,"GH" , "233" , 9 , "00" }, + {"Gibraltar" ,"GI" , "350" , 8 , "00" }, + {"Greece" ,"GR" , "30" ,10 , "00" }, + {"Greenland" ,"GL" , "299" , 6 , "00" }, + {"Grenada" ,"GD" , "1" , 10 , "011" }, + {"Guadeloupe" ,"GP" , "590" , 9 , "00" }, + {"Guam" ,"GU" , "1" , 10 , "011" }, + {"Guatemala" ,"GT" , "502" , 8 , "00" }, + {"Guinea" ,"GN" , "224" , 8 , "00" }, + {"Guinea-Bissau" ,"GW" , "245" , 7 , "00" }, + {"Guyana" ,"GY" , "592" , 7 , "001" }, + {"Haiti" ,"HT" , "509" , 8 , "00" }, + {"Honduras" ,"HN" , "504" , 8 , "00" }, + {"Hong Kong" ,"HK" , "852" , 8 , "001" }, + {"Hungary" ,"HU" , "36" , 9 , "00" }, + {"Iceland" ,"IS" , "354" , 9 , "00" }, + {"India" ,"IN" , "91" , 10 , "00" }, + {"Indonesia" ,"ID" , "62" , 10 , "001" }, + {"Iran" ,"IR" , "98" , 10 , "00" }, + {"Iraq" ,"IQ" , "964" , 10 , "00" }, + {"Ireland" ,"IE" , "353" , 9 , "00" }, + {"Israel" ,"IL" , "972" , 9 , "00" }, + {"Italy" ,"IT" , "39" , 10 , "00" }, +/* {"Jersey" ,"JE" , "44" , 10 , "00" },*/ + {"Jamaica" ,"JM" , "1" , 10 , "011" }, + {"Japan" ,"JP" , "81" , 10 , "010" }, + {"Jordan" ,"JO" , "962" , 9 , "00" }, + {"Kazakhstan" ,"KZ" , "7" , 10 , "00" }, + {"Kenya" ,"KE" , "254" , 9 , "000" }, + {"Kiribati" ,"KI" , "686" , 5 , "00" }, + {"Korea, North" ,"KP" , "850" , 12 , "99" }, + {"Korea, South" ,"KR" , "82" , 12 , "001" }, + {"Kuwait" ,"KW" , "965" , 8 , "00" }, + {"Kyrgyzstan" ,"KG" , "996" , 9 , "00" }, + {"Laos" ,"LA" , "856" , 10 , "00" }, + {"Latvia" ,"LV" , "371" , 8 , "00" }, + {"Lebanon" ,"LB" , "961" , 7 , "00" }, + {"Lesotho" ,"LS" , "266" , 8 , "00" }, + {"Liberia" ,"LR" , "231" , 8 , "00" }, + {"Libya" ,"LY" , "218" , 8 , "00" }, + {"Liechtenstein" ,"LI" , "423" , 7 , "00" }, + {"Lithuania" ,"LT" , "370" , 8 , "00" }, + {"Luxembourg" ,"LU" , "352" , 9 , "00" }, + {"Macau" ,"MO" , "853" , 8 , "00" }, + {"Macedonia" ,"MK" , "389" , 8 , "00" }, + {"Madagascar" ,"MG" , "261" , 9 , "00" }, + {"Malawi" ,"MW" , "265" , 9 , "00" }, + {"Malaysia" ,"MY" , "60" , 9 , "00" }, + {"Maldives" ,"MV" , "960" , 7 , "00" }, + {"Mali" ,"ML" , "223" , 8 , "00" }, + {"Malta" ,"MT" , "356" , 8 , "00" }, + {"Marshall Islands" ,"MH" , "692" , 7 , "011" }, + {"Martinique" ,"MQ" , "596" , 9 , "00" }, + {"Mauritania" ,"MR" , "222" , 8 , "00" }, + {"Mauritius" ,"MU" , "230" , 7 , "00" }, + {"Mayotte Island" ,"YT" , "262" , 9 , "00" }, + {"Mexico" ,"MX" , "52" , 10 , "00" }, + {"Micronesia" ,"FM" , "691" , 7 , "011" }, + {"Moldova" ,"MD" , "373" , 8 , "00" }, + {"Monaco" ,"MC" , "377" , 8 , "00" }, + {"Mongolia" ,"MN" , "976" , 8 , "001" }, + {"Montenegro" ,"ME" , "382" , 8 , "00" }, + {"Montserrat" ,"MS" , "664" , 10 , "011" }, + {"Morocco" ,"MA" , "212" , 9 , "00" }, + {"Mozambique" ,"MZ" , "258" , 9 , "00" }, + {"Myanmar" ,"MM" , "95" , 8 , "00" }, + {"Namibia" ,"NA" , "264" , 9 , "00" }, + {"Nauru" ,"NR" , "674" , 7 , "00" }, + {"Nepal" ,"NP" , "43" , 10 , "00" }, + {"Netherlands" ,"NL" , "31" , 9 , "00" }, + {"New Caledonia" ,"NC" , "687" , 6 , "00" }, + {"New Zealand" ,"NZ" , "64" , 10 , "00" }, + {"Nicaragua" ,"NI" , "505" , 8 , "00" }, + {"Niger" ,"NE" , "227" , 8 , "00" }, + {"Nigeria" ,"NG" , "234" , 10 , "009" }, + {"Niue" ,"NU" , "683" , 4 , "00" }, + {"Norfolk Island" ,"NF" , "672" , 5 , "00" }, + {"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" }, + {"Norway" ,"NO" , "47" , 8 , "00" }, + {"Oman" ,"OM" , "968" , 8 , "00" }, + {"Pakistan" ,"PK" , "92" , 10 , "00" }, + {"Palau" ,"PW" , "680" , 7 , "011" }, + {"Palestine" ,"PS" , "970" , 9 , "00" }, + {"Panama" ,"PA" , "507" , 8 , "00" }, + {"Papua New Guinea" ,"PG" , "675" , 8 , "00" }, + {"Paraguay" ,"PY" , "595" , 9 , "00" }, + {"Peru" ,"PE" , "51" , 9 , "00" }, + {"Philippines" ,"PH" , "63" , 10 , "00" }, + {"Poland" ,"PL" , "48" , 9 , "00" }, + {"Portugal" ,"PT" , "351" , 9 , "00" }, + {"Puerto Rico" ,"PR" , "1" , 10 , "011" }, + {"Qatar" ,"QA" , "974" , 8 , "00" }, + {"R�union Island" ,"RE" , "262" , 9 , "011" }, + {"Romania" ,"RO" , "40" , 9 , "00" }, + {"Russian Federation" ,"RU" , "7" , 10 , "8" }, + {"Rwanda" ,"RW" , "250" , 9 , "00" }, + {"Saint Helena" ,"SH" , "290" , 4 , "00" }, + {"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" }, + {"Saint Lucia" ,"LC" , "1" , 10 , "011" }, + {"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" }, + {"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" }, + {"Samoa" ,"WS" , "685" , 7 , "0" }, + {"San Marino" ,"SM" , "378" , 10 , "00" }, + {"Sao Tome and Principe" ,"ST" , "239" , 7 , "00" }, + {"Saudi Arabia" ,"SA" , "966" , 9 , "00" }, + {"Senegal" ,"SN" , "221" , 9 , "00" }, + {"Serbia" ,"RS" , "381" , 9 , "00" }, + {"Seychelles" ,"SC" , "248" , 7 , "00" }, + {"Sierra Leone" ,"SL" , "232" , 8 , "00" }, + {"Singapore" ,"SG" , "65" , 8 , "001" }, + {"Slovakia" ,"SK" , "421" , 9 , "00" }, + {"Slovenia" ,"SI" , "386" , 8 , "00" }, + {"Solomon Islands" ,"SB" , "677" , 7 , "00" }, + {"Somalia" ,"SO" , "252" , 8 , "00" }, + {"South Africa" ,"ZA" , "27" , 9 , "00" }, + {"Spain" ,"ES" , "34" , 9 , "00" }, + {"Sri Lanka" ,"LK" , "94" , 9 , "00" }, + {"Sudan" ,"SD" , "249" , 9 , "00" }, + {"Suriname" ,"SR" , "597" , 7 , "00" }, + {"Swaziland" ,"SZ" , "268" , 8 , "00" }, + {"Sweden" ,"SE" , "1" , 9 , "00" }, + {"Switzerland" ,"XK" , "41" , 9 , "00" }, + {"Syria" ,"SY" , "963" , 9 , "00" }, + {"Taiwan" ,"TW" , "886" , 9 , "810" }, + {"Tajikistan" ,"TJ" , "992" , 9 , "002" }, + {"Tanzania" ,"TZ" , "255" , 9 , "000" }, + {"Thailand" ,"TH" , "66" , 9 , "001" }, + {"Togo" ,"TG" , "228" , 8 , "00" }, + {"Tokelau" ,"TK" , "690" , 4 , "00" }, + {"Tonga" ,"TO" , "676" , 5 , "00" }, + {"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" }, + {"Tunisia" ,"TN" , "216" , 8 , "00" }, + {"Turkey" ,"TR" , "90" , 10 , "00" }, + {"Turkmenistan" ,"TM" , "993" , 8 , "00" }, + {"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" }, + {"Tuvalu" ,"TV" , "688" , 5 , "00" }, + {"Uganda" ,"UG" , "256" , 9 , "000" }, + {"Ukraine" ,"UA" , "380" , 9 , "00" }, + {"United Arab Emirates" ,"AE" , "971" , 9 , "00" }, + {"United Kingdom" ,"GB" , "44" , 10 , "00" }, +/* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/ + {"United States" ,"US" , "1" , 10 , "011" }, + {"Uruguay" ,"UY" , "598" , 8 , "00" }, + {"Uzbekistan" ,"UZ" , "998" , 9 , "8" }, + {"Vanuatu" ,"VU" , "678" , 7 , "00" }, + {"Venezuela" ,"VE" , "58" , 10 , "00" }, + {"Vietnam" ,"VN" , "84" , 9 , "00" }, + {"Wallis and Futuna" ,"WF" , "681" , 5 , "00" }, + {"Yemen" ,"YE" , "967" , 9 , "00" }, + {"Zambia" ,"ZM" , "260" , 9 , "00" }, + {"Zimbabwe" ,"ZW" , "263" , 9 , "00" }, {NULL ,NULL , "" , 0 , NULL } }; static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"}; @@ -658,35 +800,41 @@ int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { return -1; } -static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){ +static bool_t lookup_dial_plan_by_ccc(const char *ccc, dial_plan_t *plan){ int i; for(i=0;dial_plans[i].country!=NULL;++i){ if (strcmp(ccc,dial_plans[i].ccc)==0){ *plan=dial_plans[i]; - return; + return TRUE; } } /*else return a generic "most common" dial plan*/ *plan=most_common_dialplan; strcpy(plan->ccc,ccc); + return FALSE; } -static bool_t is_a_phone_number(const char *username){ +bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig *proxy, const char *username){ const char *p; for(p=username;*p!='\0';++p){ - if (isdigit(*p) || - *p==' ' || - *p=='.' || - *p=='-' || - *p==')' || + if (isdigit(*p) || + *p==' ' || + *p=='.' || + *p=='-' || + *p==')' || *p=='(' || *p=='/' || - *p=='+') continue; - else return FALSE; + *p=='+' || + (unsigned char)*p==0xca || (unsigned char)*p==0xc2 || (unsigned char)*p==0xa0 // non-breakable space (iOS uses it to format contacts phone number) + ) { + continue; + } + return FALSE; } return TRUE; } +//remove anything but [0-9] and + static char *flatten_number(const char *number){ char *result=ms_malloc0(strlen(number)+1); char *w=result; @@ -700,14 +848,14 @@ static char *flatten_number(const char *number){ return result; } -static void replace_plus(const char *src, char *dest, size_t destlen, const char *icp){ +static void replace_plus_with_icp(const char *src, char *dest, size_t destlen, const char *icp){ int i=0; - + if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){ src++; - strcpy(dest,icp); + strncpy(dest, icp, destlen); } - + for(;(idial_prefix==NULL || proxy->dial_prefix[0]=='\0'){ - /*no prefix configured, nothing else to do*/ - strncpy(result,flatten,result_len); - ms_free(flatten); - return 0; - }else{ - dial_plan_t dialplan; - lookup_dial_plan(proxy->dial_prefix,&dialplan); - ms_message("Using dialplan '%s'",dialplan.country); - if (flatten[0]=='+' || strstr(flatten,dialplan.icp)==flatten){ - /* the number has international prefix or +, so nothing to do*/ - ms_message("Prefix already present."); - /*eventually replace the plus*/ - replace_plus(flatten,result,result_len,proxy->dial_escape_plus ? dialplan.icp : NULL); - ms_free(flatten); - return 0; +static char* replace_plus_with_icp_new(char *phone, const char* icp){ + return (icp && phone[0]=='+') ? ms_strdup_printf("%s%s", icp, phone+1) : ms_strdup(phone); +} + +static char* replace_icp_with_plus_new(char *phone, const char *icp){ + return (strstr(phone, icp) == phone) ? ms_strdup_printf("+%s", phone+strlen(icp)) : ms_strdup(phone); +} + +bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len){ + bool_t ret; + LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new(); + memset(result, 0, result_len); + if (linphone_proxy_config_is_phone_number(tmpproxy, username)){ + dial_plan_t dialplan = {0}; + char *flatten=flatten_number(username); + ms_debug("Flattened number is '%s'",flatten); + + /*username does not contain a dial prefix nor the tmpproxy, nothing else to do*/ + if (tmpproxy->dial_prefix==NULL || tmpproxy->dial_prefix[0]=='\0'){ + strncpy(result,flatten,result_len-1); + } else { + lookup_dial_plan_by_ccc(tmpproxy->dial_prefix,&dialplan); + ms_debug("Using dial plan '%s'",dialplan.country); + /* the number has international prefix or +, so nothing to do*/ + if (flatten[0]=='+'){ + ms_debug("Prefix already present."); + /*eventually replace the plus by the international calling prefix of the country*/ + if (tmpproxy->dial_escape_plus) { + replace_plus_with_icp(flatten,result,result_len,dialplan.icp); + }else{ + strncpy(result, flatten, result_len-1); + } + }else if (strstr(flatten,dialplan.icp)==flatten){ + if (tmpproxy->dial_escape_plus){ + strncpy(result, flatten, result_len-1); + }else{ + replace_icp_with_plus(flatten, result, result_len, dialplan.icp); + } }else{ + int numlen; int i=0; int skip; numlen=strlen(flatten); /*keep at most national number significant digits */ skip=numlen-dialplan.nnl; if (skip<0) skip=0; - /*first prepend internation calling prefix or +*/ - if (proxy->dial_escape_plus){ + /*first prepend international calling prefix or +*/ + if (tmpproxy->dial_escape_plus){ strncpy(result,dialplan.icp,result_len); i+=strlen(dialplan.icp); }else{ @@ -761,122 +933,272 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const cha } /*add user digits */ strncpy(result+i,flatten+skip,result_len-i-1); - ms_free(flatten); } } - }else strncpy(result,username,result_len); - return 0; + ms_free(flatten); + ret = TRUE; + } else { + strncpy(result,username,result_len-1); + ret = FALSE; + } + if (proxy==NULL) ms_free(tmpproxy); + return ret; +} + +char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username) { + LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new(); + char* result = NULL; + if (linphone_proxy_config_is_phone_number(tmpproxy, username)){ + dial_plan_t dialplan = {0}; + char * flatten=flatten_number(username); + ms_debug("Flattened number is '%s'",flatten); + + /*if proxy has a dial prefix, modify phonenumber accordingly*/ + if (tmpproxy->dial_prefix!=NULL && tmpproxy->dial_prefix[0]!='\0'){ + lookup_dial_plan_by_ccc(tmpproxy->dial_prefix,&dialplan); + ms_debug("Using dial plan '%s'",dialplan.country); + /* the number already starts with + or international prefix*/ + if (flatten[0]=='+'||strstr(flatten,dialplan.icp)==flatten){ + ms_debug("Prefix already present."); + if (tmpproxy->dial_escape_plus) { + result = replace_plus_with_icp_new(flatten,dialplan.icp); + } else { + result = replace_icp_with_plus_new(flatten,dialplan.icp); + } + }else{ + /*0. keep at most national number significant digits */ + char* flatten_start = flatten + MAX(0, strlen(flatten) - dialplan.nnl); + /*1. First prepend international calling prefix or +*/ + /*2. Second add prefix*/ + /*3. Finally add user digits */ + + result = ms_strdup_printf("%s%s%s" + , tmpproxy->dial_escape_plus ? dialplan.icp : "+" + , dialplan.ccc + , flatten_start); + } + } + if (result==NULL) { + result = flatten; + } else { + ms_free(flatten); + } + } + if (proxy==NULL) ms_free(tmpproxy); + return result; +} + +static LinphoneAddress* _linphone_core_destroy_addr_if_not_sip( LinphoneAddress* addr ){ + if( linphone_address_is_sip(addr) ) { + return addr; + } else { + linphone_address_destroy(addr); + return NULL; + } +} + +LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *proxy, const char *username) { + enum_lookup_res_t *enumres=NULL; + char *enum_domain=NULL; + char *tmpurl; + LinphoneAddress *uri; + + if (!username || *username=='\0') return NULL; + + if (is_enum(username,&enum_domain)){ + if (proxy) { + linphone_core_notify_display_status(proxy->lc,_("Looking for telephone number destination...")); + } + if (enum_lookup(enum_domain,&enumres)<0){ + if (proxy) { + linphone_core_notify_display_status(proxy->lc,_("Could not resolve this number.")); + } + ms_free(enum_domain); + return NULL; + } + ms_free(enum_domain); + tmpurl=enumres->sip_address[0]; + uri=linphone_address_new(tmpurl); + enum_lookup_res_free(enumres); + return _linphone_core_destroy_addr_if_not_sip(uri); + } + /* check if we have a "sip:" or a "sips:" */ + if ( (strstr(username,"sip:")==NULL) && (strstr(username,"sips:")==NULL) ){ + /* this doesn't look like a true sip uri */ + if (strchr(username,'@')!=NULL){ + /* seems like sip: is missing !*/ + tmpurl=ms_strdup_printf("sip:%s",username); + uri=linphone_address_new(tmpurl); + ms_free(tmpurl); + if (uri){ + return _linphone_core_destroy_addr_if_not_sip(uri); + } + } + + if (proxy!=NULL){ + /* append the proxy domain suffix but remove any custom parameters/headers */ + LinphoneAddress *uri=linphone_address_clone(linphone_proxy_config_get_identity_address(proxy)); + linphone_address_clean(uri); + if (uri==NULL){ + return NULL; + } else { + char normalized_username[128]; + linphone_address_set_display_name(uri,NULL); + linphone_proxy_config_normalize_number(proxy,username,normalized_username, + sizeof(normalized_username)); + linphone_address_set_username(uri,normalized_username); + return _linphone_core_destroy_addr_if_not_sip(uri); + } + } else { + return NULL; + } + } + uri=linphone_address_new(username); + if (uri!=NULL){ + return _linphone_core_destroy_addr_if_not_sip(uri); + } + + return NULL; } /** * Commits modification made to the proxy configuration. **/ -int linphone_proxy_config_done(LinphoneProxyConfig *obj) +int linphone_proxy_config_done(LinphoneProxyConfig *cfg) { - if (!linphone_proxy_config_check(obj->lc,obj)) return -1; - obj->commit=TRUE; - linphone_proxy_config_write_all_to_config_file(obj->lc); + LinphoneProxyConfigAddressComparisonResult res; + + if (!linphone_proxy_config_check(cfg->lc,cfg)) + return -1; + + /*check if server address as changed*/ + res = linphone_proxy_config_is_server_config_changed(cfg); + if (res != LinphoneProxyConfigAddressEqual) { + /* server config has changed, need to unregister from previous first*/ + if (cfg->op) { + if (res == LinphoneProxyConfigAddressDifferent) { + _linphone_proxy_config_unregister(cfg); + } + sal_op_set_user_pointer(cfg->op,NULL); /*we don't want to receive status for this un register*/ + sal_op_unref(cfg->op); /*but we keep refresher to handle authentication if needed*/ + cfg->op=NULL; + } + } + cfg->commit=TRUE; + linphone_proxy_config_write_all_to_config_file(cfg->lc); return 0; } +const char* linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg) +{ + return cfg?cfg->realm:NULL; +} void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm) { if (cfg->realm!=NULL) { ms_free(cfg->realm); - cfg->realm=NULL; } - if (realm!=NULL) cfg->realm=ms_strdup(realm); + 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); - 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){ + const LinphoneAddress *to=linphone_proxy_config_get_identity_address(proxy); + proxy->publish_op=sal_op_new(proxy->lc->sal); + + linphone_configure_op(proxy->lc, proxy->publish_op, + to, NULL, FALSE); + + if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){ + sal_op_set_contact_address(proxy->publish_op,linphone_proxy_config_get_identity_address(proxy)); + } + } + err=sal_publish_presence(proxy->publish_op + ,NULL + ,NULL + ,linphone_proxy_config_get_publish_expires(proxy) + ,(SalPresenceModel *)presence); + }else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/ return err; } -/** - * Returns the route set for this proxy configuration. -**/ -const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj){ - return obj->reg_route; +const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){ + return cfg->reg_route; +} + +const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg){ + return cfg->identity_address; +} + +const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg){ + return cfg->reg_identity; +} + +bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg){ + return cfg->publish; +} + +const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *cfg){ + return cfg->reg_proxy; } /** - * Returns the SIP identity that belongs to this proxy configuration. - * - * The SIP identity is a SIP address (Display Name ) + * @return the duration of registration. **/ -const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj){ - return obj->reg_identity; +int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg){ + return cfg->expires; } -/** - * Returns TRUE if PUBLISH request is enabled for this proxy. -**/ -bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj){ - return obj->publish; +bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *cfg){ + return cfg->reg_sendregister; } -/** - * Returns the proxy's SIP address. -**/ -const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj){ - return obj->reg_proxy; -} - -/** - * Returns the duration of registration. -**/ -int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj){ - return obj->expires; -} - -/** - * Returns TRUE if registration to the proxy is enabled. -**/ -bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){ - return obj->reg_sendregister; -} - -/** - * Set optional contact parameters that will be added to the contact information sent in the registration. - * @param obj the proxy config object - * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" - * - * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. - * As an example, the contact address in the SIP register sent will look like . -**/ -void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params){ - if (obj->contact_params) { - ms_free(obj->contact_params); - obj->contact_params=NULL; +void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *cfg, const char *contact_params){ + if (cfg->contact_params) { + ms_free(cfg->contact_params); + cfg->contact_params=NULL; } if (contact_params){ - obj->contact_params=ms_strdup(contact_params); + cfg->contact_params=ms_strdup(contact_params); } } -/** - * Returns previously set contact parameters. -**/ -const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj){ - return obj->contact_params; +void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *cfg, const char *contact_uri_params){ + if (cfg->contact_uri_params) { + ms_free(cfg->contact_uri_params); + cfg->contact_uri_params=NULL; + } + if (contact_uri_params){ + cfg->contact_uri_params=ms_strdup(contact_uri_params); + } } -struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){ - return obj->lc; +const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg){ + return cfg->contact_params; +} + +const char *linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *cfg){ + return cfg->contact_uri_params; +} + +struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *cfg){ + return cfg->lc; +} + +const char *linphone_proxy_config_get_custom_header(LinphoneProxyConfig *cfg, const char *header_name){ + const SalCustomHeader *ch; + if (!cfg->op) return NULL; + ch = sal_op_get_recv_custom_header(cfg->op); + return sal_custom_header_find(ch, header_name); +} + +void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const char *header_name, const char *header_value){ + cfg->sent_headers=sal_custom_header_append(cfg->sent_headers, header_name, header_value); } -/** - * Add a proxy configuration. - * This will start registration on the proxy, if registration is enabled. -**/ int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ if (!linphone_proxy_config_check(lc,cfg)) { return -1; @@ -885,41 +1207,36 @@ int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ ms_warning("ProxyConfig already entered, ignored."); return 0; } - lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)cfg); + lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)linphone_proxy_config_ref(cfg)); linphone_proxy_config_apply(cfg,lc); return 0; } -/** - * Removes a proxy configuration. - * - * LinphoneCore will then automatically unregister and place the proxy configuration - * on a deleted list. For that reason, a removed proxy does NOT need to be freed. -**/ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ /* check this proxy config is in the list before doing more*/ if (ms_list_find(lc->sip_conf.proxies,cfg)==NULL){ - ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig %p is not known by LinphoneCore (programming error?)",cfg); + 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); - cfg->deletion_date=ms_time(NULL); - if (cfg->state==LinphoneRegistrationOk){ - /* this will unREGISTER */ - linphone_proxy_config_edit(cfg); - } + lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,cfg); + if (lc->default_proxy==cfg){ lc->default_proxy=NULL; } + + cfg->deletion_date=ms_time(NULL); + if (cfg->state==LinphoneRegistrationOk){ + /* UNREGISTER */ + linphone_proxy_config_edit(cfg); + linphone_proxy_config_enable_register(cfg,FALSE); + linphone_proxy_config_done(cfg); + linphone_proxy_config_update(cfg); + } linphone_proxy_config_write_all_to_config_file(lc); } -/** - * Erase all proxies from config. - * - * @ingroup proxy -**/ + void linphone_core_clear_proxy_config(LinphoneCore *lc){ MSList* list=ms_list_copy(linphone_core_get_proxy_config_list((const LinphoneCore*)lc)); MSList* copy=list; @@ -929,14 +1246,16 @@ void linphone_core_clear_proxy_config(LinphoneCore *lc){ ms_list_free(copy); linphone_proxy_config_write_all_to_config_file(lc); } -/** - * Sets the default proxy. - * - * This default proxy must be part of the list of already entered LinphoneProxyConfig. - * Toggling it as default will make LinphoneCore use the identity associated with - * the proxy configuration in all incoming and outgoing calls. -**/ -void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config){ + +static int linphone_core_get_default_proxy_config_index(LinphoneCore *lc) { + int pos = -1; + if (lc->default_proxy != NULL) { + pos = ms_list_position(lc->sip_conf.proxies, ms_list_find(lc->sip_conf.proxies, (void *)lc->default_proxy)); + } + return pos; +} + +void linphone_core_set_default_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config){ /* check if this proxy is in our list */ if (config!=NULL){ if (ms_list_find(lc->sip_conf.proxies,config)==NULL){ @@ -947,105 +1266,126 @@ void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *conf } lc->default_proxy=config; if (linphone_core_ready(lc)) - lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL)); -} + lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy_config_index(lc)); +} void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){ if (index<0) linphone_core_set_default_proxy(lc,NULL); else linphone_core_set_default_proxy(lc,ms_list_nth_data(lc->sip_conf.proxies,index)); } -/** - * Returns the default proxy configuration, that is the one used to determine the current identity. -**/ int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config){ - int pos=-1; if (config!=NULL) *config=lc->default_proxy; - if (lc->default_proxy!=NULL){ - pos=ms_list_position(lc->sip_conf.proxies,ms_list_find(lc->sip_conf.proxies,(void *)lc->default_proxy)); - } - return pos; + return linphone_core_get_default_proxy_config_index(lc); +} + +LinphoneProxyConfig * linphone_core_get_default_proxy_config(LinphoneCore *lc) { + return lc->default_proxy; } -/** - * Returns an unmodifiable list of entered proxy configurations. -**/ const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc){ return lc->sip_conf.proxies; } -void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *obj, int index) +void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *cfg, int index) { char key[50]; sprintf(key,"proxy_%i",index); lp_config_clean_section(config,key); - if (obj==NULL){ + if (cfg==NULL){ return; } - if (obj->type!=NULL){ - lp_config_set_string(config,key,"type",obj->type); + if (cfg->type!=NULL){ + lp_config_set_string(config,key,"type",cfg->type); } - if (obj->reg_proxy!=NULL){ - lp_config_set_string(config,key,"reg_proxy",obj->reg_proxy); + if (cfg->reg_proxy!=NULL){ + lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy); } - if (obj->reg_route!=NULL){ - lp_config_set_string(config,key,"reg_route",obj->reg_route); + if (cfg->reg_route!=NULL){ + lp_config_set_string(config,key,"reg_route",cfg->reg_route); } - if (obj->reg_identity!=NULL){ - lp_config_set_string(config,key,"reg_identity",obj->reg_identity); + if (cfg->reg_identity!=NULL){ + lp_config_set_string(config,key,"reg_identity",cfg->reg_identity); } - if (obj->contact_params!=NULL){ - lp_config_set_string(config,key,"contact_parameters",obj->contact_params); + if (cfg->realm!=NULL){ + lp_config_set_string(config,key,"realm",cfg->realm); } - lp_config_set_int(config,key,"reg_expires",obj->expires); - lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); - lp_config_set_int(config,key,"publish",obj->publish); - lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); - lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); + if (cfg->contact_params!=NULL){ + lp_config_set_string(config,key,"contact_parameters",cfg->contact_params); + } + if (cfg->contact_uri_params!=NULL){ + lp_config_set_string(config,key,"contact_uri_parameters",cfg->contact_uri_params); + } + if (cfg->quality_reporting_collector!=NULL){ + lp_config_set_string(config,key,"quality_reporting_collector",cfg->quality_reporting_collector); + } + lp_config_set_int(config,key,"quality_reporting_enabled",cfg->quality_reporting_enabled); + lp_config_set_int(config,key,"quality_reporting_interval",cfg->quality_reporting_interval); + lp_config_set_int(config,key,"reg_expires",cfg->expires); + lp_config_set_int(config,key,"reg_sendregister",cfg->reg_sendregister); + lp_config_set_int(config,key,"publish",cfg->publish); + lp_config_set_int(config, key, "avpf", cfg->avpf_mode); + lp_config_set_int(config, key, "avpf_rr_interval", cfg->avpf_rr_interval); + lp_config_set_int(config,key,"dial_escape_plus",cfg->dial_escape_plus); + lp_config_set_string(config,key,"dial_prefix",cfg->dial_prefix); + lp_config_set_int(config,key,"privacy",cfg->privacy); } +#define CONFIGURE_STRING_VALUE(cfg,config,key,param,param_name) \ + {\ + char* default_value = linphone_proxy_config_get_##param(cfg)?ms_strdup(linphone_proxy_config_get_##param(cfg)):NULL;\ + linphone_proxy_config_set_##param(cfg,lp_config_get_string(config,key,param_name,default_value)); \ + if ( default_value) ms_free(default_value); \ + } -LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config, int index) +#define CONFIGURE_BOOL_VALUE(cfg,config,key,param,param_name) \ + linphone_proxy_config_enable_##param(cfg,lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(cfg))); + +#define CONFIGURE_INT_VALUE(cfg,config,key,param,param_name) \ + linphone_proxy_config_set_##param(cfg,lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(cfg))); + +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index) { const char *tmp; - const char *identity; - const char *proxy; LinphoneProxyConfig *cfg; char key[50]; - + LpConfig *config=lc->config; + sprintf(key,"proxy_%i",index); if (!lp_config_has_section(config,key)){ return NULL; } - cfg=linphone_proxy_config_new(); + cfg=linphone_core_create_proxy_config(lc); - identity=lp_config_get_string(config,key,"reg_identity",NULL); - proxy=lp_config_get_string(config,key,"reg_proxy",NULL); - - linphone_proxy_config_set_identity(cfg,identity); - linphone_proxy_config_set_server_addr(cfg,proxy); - - tmp=lp_config_get_string(config,key,"reg_route",NULL); - if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity") + CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy") + CONFIGURE_STRING_VALUE(cfg,config,key,route,"reg_route") - linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); - - linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600))); - linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); - - linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); + CONFIGURE_STRING_VALUE(cfg,config,key,realm,"realm") + + CONFIGURE_BOOL_VALUE(cfg,config,key,quality_reporting,"quality_reporting_enabled") + CONFIGURE_STRING_VALUE(cfg,config,key,quality_reporting_collector,"quality_reporting_collector") + CONFIGURE_INT_VALUE(cfg,config,key,quality_reporting_interval,"quality_reporting_interval") + + CONFIGURE_STRING_VALUE(cfg,config,key,contact_parameters,"contact_parameters") + CONFIGURE_STRING_VALUE(cfg,config,key,contact_uri_parameters,"contact_uri_parameters") + + CONFIGURE_INT_VALUE(cfg,config,key,expires,"reg_expires") + CONFIGURE_BOOL_VALUE(cfg,config,key,register,"reg_sendregister") + CONFIGURE_BOOL_VALUE(cfg,config,key,publish,"publish") + CONFIGURE_INT_VALUE(cfg,config,key,avpf_mode,"avpf") + CONFIGURE_INT_VALUE(cfg,config,key,avpf_rr_interval,"avpf_rr_interval") + CONFIGURE_INT_VALUE(cfg,config,key,dial_escape_plus,"dial_escape_plus") + CONFIGURE_STRING_VALUE(cfg,config,key,dial_prefix,"dial_prefix") - linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",LP_CONFIG_DEFAULT_INT(config,"dial_escape_plus",0))); - linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",LP_CONFIG_DEFAULT_STRING(config,"dial_prefix",NULL))); - tmp=lp_config_get_string(config,key,"type",NULL); - if (tmp!=NULL && strlen(tmp)>0) + if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); - + CONFIGURE_INT_VALUE(cfg,config,key,privacy,"privacy") return cfg; } @@ -1063,10 +1403,10 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ } caps=sip_setup_context_get_capabilities(ssc); if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){ - if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL)!=0){ - if (lc->vtable.display_warning){ + if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0){ + { char *tmp=ms_strdup_printf(_("Could not login as %s"),cfg->reg_identity); - lc->vtable.display_warning(lc,tmp); + linphone_core_notify_display_warning(lc,tmp); ms_free(tmp); } return; @@ -1080,7 +1420,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ ms_error("Could not retrieve proxy uri !"); } } - + } SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){ @@ -1091,29 +1431,37 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){ return NULL; } +static bool_t can_register(LinphoneProxyConfig *cfg){ + LinphoneCore *lc=cfg->lc; +#ifdef BUILD_UPNP + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp){ + if(lc->sip_conf.register_only_when_upnp_is_ok && + (lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) { + return FALSE; + } + } +#endif //BUILD_UPNP + if (lc->sip_conf.register_only_when_network_is_up){ + return lc->network_reachable; + } + return TRUE; +} + void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ LinphoneCore *lc=cfg->lc; if (cfg->commit){ if (cfg->type && cfg->ssctx==NULL){ linphone_proxy_config_activate_sip_setup(cfg); } - switch(linphone_core_get_firewall_policy(lc)) { - case LinphonePolicyUseUpnp: -#ifdef BUILD_UPNP - if(lc->sip_conf.register_only_when_upnp_is_ok && - (lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) { - break; - } -#endif //BUILD_UPNP - default: - if ((!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable)) { - linphone_proxy_config_register(cfg); - } - } - if (cfg->publish && cfg->publish_op==NULL){ - linphone_proxy_config_send_publish(cfg,lc->presence_mode); + if (can_register(cfg)){ + linphone_proxy_config_register(cfg); + cfg->commit=FALSE; + if (cfg->publish) cfg->send_publish=TRUE; } - cfg->commit=FALSE; + } + if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){ + linphone_proxy_config_send_publish(cfg,lc->presence_model); + cfg->send_publish=FALSE; } } @@ -1131,115 +1479,43 @@ SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig return cfg->ssctx; } -/** - * @} -**/ - -LinphoneAccountCreator *linphone_account_creator_new(struct _LinphoneCore *core, const char *type){ - LinphoneAccountCreator *obj; - LinphoneProxyConfig *cfg; - SipSetup *ss=sip_setup_lookup(type); - SipSetupContext *ssctx; - if (!ss){ - return NULL; - } - if (!(sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER)){ - ms_error("%s cannot manage accounts.",type); - return NULL; - } - obj=ms_new0(LinphoneAccountCreator,1); - cfg=linphone_proxy_config_new(); - ssctx=sip_setup_context_new(ss,cfg); - obj->lc=core; - obj->ssctx=ssctx; - set_string(&obj->domain,sip_setup_context_get_domains(ssctx)[0]); - cfg->lc=core; - return obj; +void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cfg, void *ud) { + cfg->user_data = ud; } -void linphone_account_creator_set_username(LinphoneAccountCreator *obj, const char *username){ - set_string(&obj->username,username); -} - -void linphone_account_creator_set_password(LinphoneAccountCreator *obj, const char *password){ - set_string(&obj->password,password); -} - -void linphone_account_creator_set_domain(LinphoneAccountCreator *obj, const char *domain){ - set_string(&obj->domain,domain); -} - -void linphone_account_creator_set_route(LinphoneAccountCreator *obj, const char *route) { - set_string(&obj->route,route); -} - -void linphone_account_creator_set_email(LinphoneAccountCreator *obj, const char *email) { - set_string(&obj->email,email); -} - -void linphone_account_creator_set_suscribe(LinphoneAccountCreator *obj, int suscribe) { - obj->suscribe = suscribe; -} - -const char * linphone_account_creator_get_username(LinphoneAccountCreator *obj){ - return obj->username; -} - -const char * linphone_account_creator_get_domain(LinphoneAccountCreator *obj){ - return obj->domain; -} - -int linphone_account_creator_test_existence(LinphoneAccountCreator *obj){ - SipSetupContext *ssctx=obj->ssctx; - char *uri=ms_strdup_printf("%s@%s",obj->username,obj->domain); - int err=sip_setup_context_account_exists(ssctx,uri); - ms_free(uri); - return err; -} - -int linphone_account_creator_test_validation(LinphoneAccountCreator *obj) { - SipSetupContext *ssctx=obj->ssctx; - int err=sip_setup_context_account_validated(ssctx,obj->username); - return err; -} - -LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj){ - SipSetupContext *ssctx=obj->ssctx; - char *uri=ms_strdup_printf("%s@%s",obj->username,obj->domain); - int err=sip_setup_context_create_account(ssctx, uri, obj->password, obj->email, obj->suscribe); - ms_free(uri); - if (err==0) { - obj->succeeded=TRUE; - return sip_setup_context_get_proxy_config(ssctx); - } - return NULL; -} - -void linphone_account_creator_destroy(LinphoneAccountCreator *obj){ - if (obj->username) - ms_free(obj->username); - if (obj->password) - ms_free(obj->password); - if (obj->domain) - ms_free(obj->domain); - if (!obj->succeeded){ - linphone_proxy_config_destroy(sip_setup_context_get_proxy_config(obj->ssctx)); - } -} - -void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud) { - cr->user_data=ud; -} - -void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) { - return cr->user_data; +void * linphone_proxy_config_get_user_data(const LinphoneProxyConfig *cfg) { + return cfg->user_data; } 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); + bool_t update_friends=FALSE; + + if (state==LinphoneRegistrationProgress) { + char *msg=ortp_strdup_printf(_("Refreshing on %s..."), linphone_proxy_config_get_identity(cfg)); + linphone_core_notify_display_status(lc,msg); + ms_free(msg); + + } + + if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ + ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg, + linphone_proxy_config_get_identity(cfg), + linphone_registration_state_to_string(cfg->state), + linphone_registration_state_to_string(state)); + if (linphone_core_should_subscribe_friends_only_when_registered(lc)){ + update_friends=(state==LinphoneRegistrationOk && cfg->state!=LinphoneRegistrationOk) + || (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk); + } + cfg->state=state; + + if (update_friends){ + linphone_core_update_friends_subscriptions(lc,cfg,TRUE); + } + if (lc) + linphone_core_notify_registration_state_changed(lc,cfg,state,message); + } else { + /*state already reported*/ } } @@ -1269,11 +1545,83 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon } LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { - return cfg->error; + return linphone_error_info_get_reason(linphone_proxy_config_get_error_info(cfg)); } -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) { - cfg->error = error; +const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){ + return linphone_error_info_from_sal_op(cfg->op); } +const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { + 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; +} +void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *cfg, int expires) { + cfg->publish_expires=expires; +} +int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *cfg) { + if (cfg->publish_expires<0) { + return cfg->expires; /*default value is same as register*/ + } else { + return cfg->publish_expires; + } +} + +void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) { + cfg->avpf_mode=enable ? LinphoneAVPFEnabled : LinphoneAVPFDisabled; +} + +bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg) { + if (cfg->avpf_mode==LinphoneAVPFDefault && cfg->lc){ + return linphone_core_get_avpf_mode(cfg->lc)==LinphoneAVPFEnabled; + } + return cfg->avpf_mode == LinphoneAVPFEnabled; +} + +LinphoneAVPFMode linphone_proxy_config_get_avpf_mode(const LinphoneProxyConfig *cfg){ + return cfg->avpf_mode; +} + +void linphone_proxy_config_set_avpf_mode(LinphoneProxyConfig *cfg, LinphoneAVPFMode mode){ + cfg->avpf_mode=mode; +} + +void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval) { + if (interval > 5) interval = 5; + cfg->avpf_rr_interval = interval; +} + +uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg) { + return cfg->avpf_rr_interval; +} + +const LinphoneAddress* linphone_proxy_config_get_contact(const LinphoneProxyConfig *cfg) { + return sal_op_get_contact_address(cfg->op); +} diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c new file mode 100644 index 000000000..4df8a2e0e --- /dev/null +++ b/coreapi/quality_reporting.c @@ -0,0 +1,783 @@ +/* +linphone +Copyright (C) 2014 - 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "linphonecore.h" +#include "private.h" +#include "sal/sal.h" +#include "ortp/rtpsession.h" + +#include + +#if TARGET_OS_IPHONE +#include +#endif + +#define STR_REASSIGN(dest, src) {\ + if (dest != NULL) \ + ms_free(dest); \ + dest = src; \ +} + +/*since printf family functions are LOCALE dependent, float separator may differ +depending on the user's locale (LC_NUMERIC environment var).*/ +static char * float_to_one_decimal_string(float f) { + float rounded_f = floorf(f * 10 + .5f) / 10; + + int floor_part = (int) rounded_f; + int one_decimal_part = floorf (10 * (rounded_f - floor_part) + .5f); + + return ms_strdup_printf("%d.%d", floor_part, one_decimal_part); +} + +static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offset, const char *fmt, va_list args) { + belle_sip_error_code ret; + size_t prevoffset = *offset; + + #ifndef _WIN32 + va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ + va_copy(cap,args); + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, cap); + va_end(cap); + #else + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, args); + #endif + + /*if we are out of memory, we add some size to buffer*/ + if (ret == BELLE_SIP_BUFFER_OVERFLOW) { + /*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/ + ms_warning("QualityReporting: Buffer was too small to contain the whole report - increasing its size from %lu to %lu", + (unsigned long)*buff_size, (unsigned long)*buff_size + 2048); + *buff_size += 2048; + *buff = (char *) ms_realloc(*buff, *buff_size); + + *offset = prevoffset; + /*recall itself since we did not write all things into the buffer but + only a part of it*/ + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + } +} + +static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + va_end(args); +} + +static void reset_avg_metrics(reporting_session_report_t * report){ + int i; + reporting_content_metrics_t * metrics[2] = {&report->local_metrics, &report->remote_metrics}; + + for (i = 0; i < 2; i++) { + metrics[i]->rtcp_sr_count = 0; + metrics[i]->rtcp_xr_count = 0; + metrics[i]->jitter_buffer.nominal = 0; + metrics[i]->jitter_buffer.max = 0; + + metrics[i]->quality_estimates.moslq = 0; + metrics[i]->quality_estimates.moscq = 0; + + metrics[i]->delay.round_trip_delay = 0; + } + report->last_report_date = ms_time(NULL); +} + +#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) +#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement + +#define METRICS_PACKET_LOSS 1 << 0 +#define METRICS_QUALITY_ESTIMATES 1 << 1 +#define METRICS_SESSION_DESCRIPTION 1 << 2 +#define METRICS_JITTER_BUFFER 1 << 3 +#define METRICS_DELAY 1 << 4 +#define METRICS_SIGNAL 1 << 5 + +static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { + uint8_t ret = 0; + + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret|=METRICS_PACKET_LOSS); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret|=METRICS_PACKET_LOSS); + + if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION; + + IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret|=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER); + + IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY); + + if (rm.signal.level != 127) ret|=METRICS_SIGNAL; + if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; + + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + + if (rm.rtcp_xr_count>0){ + IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); + } + if (rm.rtcp_sr_count+rm.rtcp_xr_count>0){ + IF_NUM_IN_RANGE(rm.delay.round_trip_delay/(rm.rtcp_sr_count+rm.rtcp_xr_count), 0, 65535, ret|=METRICS_DELAY); + } + + return ret; +} + +static bool_t quality_reporting_enabled(const LinphoneCall * call) { + return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); +} + +static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ + if (! quality_reporting_enabled(call)) + return FALSE; + + if (stats_type == LINPHONE_CALL_STATS_VIDEO && !linphone_call_params_video_enabled(linphone_call_get_current_params(call))) + return FALSE; + + return (call->log->reporting.reports[stats_type] != NULL); +} + +static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { + char * timestamps_start_str = NULL; + char * timestamps_stop_str = NULL; + char * network_packet_loss_rate_str = NULL; + char * jitter_buffer_discard_rate_str = NULL; + /*char * gap_loss_density_str = NULL;*/ + char * moslq_str = NULL; + char * moscq_str = NULL; + uint8_t available_metrics = are_metrics_filled(rm); + + if (rm.timestamps.start > 0) + timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start); + if (rm.timestamps.stop > 0) + timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop); + + append_to_buffer(buffer, size, offset, "Timestamps:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str); + + if ((available_metrics & METRICS_SESSION_DESCRIPTION) != 0){ + append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); + APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); + APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1); + APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); + APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1); + } + + if ((available_metrics & METRICS_JITTER_BUFFER) != 0){ + append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); + if (rm.rtcp_xr_count){ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535); + } + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); + + append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256)); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256)); + + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); + } + + /*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/ + /*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/ + /* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/ + /* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/ + /* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/ + /* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/ + /* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/ + + if ((available_metrics & METRICS_DELAY) != 0){ + append_to_buffer(buffer, size, offset, "\r\nDelay:"); + if (rm.rtcp_xr_count+rm.rtcp_sr_count){ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/(rm.rtcp_xr_count+rm.rtcp_sr_count), 0, 65535); + } + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); + } + + if ((available_metrics & METRICS_SIGNAL) != 0){ + append_to_buffer(buffer, size, offset, "\r\nSignal:"); + APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127); + APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127); + } + + /*if quality estimates metrics are available, rtcp_xr_count should be always not null*/ + if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){ + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); + + append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); + } + + if (rm.user_agent!=NULL){ + append_to_buffer(buffer, size, offset, "\r\nLinphoneExt:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " UA=\"%s\"", rm.user_agent); + } + + append_to_buffer(buffer, size, offset, "\r\n"); + + ms_free(timestamps_start_str); + ms_free(timestamps_stop_str); + ms_free(network_packet_loss_rate_str); + ms_free(jitter_buffer_discard_rate_str); + /*ms_free(gap_loss_density_str);*/ + ms_free(moslq_str); + ms_free(moscq_str); +} + +static int send_report(LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { + LinphoneContent *content = linphone_content_new(); + int expires = -1; + size_t offset = 0; + size_t size = 2048; + char * buffer; + int ret = 0; + LinphoneEvent *lev; + LinphoneAddress *request_uri; + char * domain; + const char* route; + + /*if we are on a low bandwidth network, do not send reports to not overload it*/ + if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))){ + ms_warning("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call); + ret = 1; + goto end; + } + + /*if the call was hung up too early, we might have invalid IPs information + in that case, we abort the report since it's not useful data*/ + if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0 + || report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) { + ms_warning("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could " + "not be retrieved so dropping this report" + , call + , report_event + , linphone_call_get_duration(call) + , (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote"); + ret = 2; + goto end; + } + + buffer = (char *) belle_sip_malloc(size); + linphone_content_set_type(content, "application"); + linphone_content_set_subtype(content, "vq-rtcpxr"); + + append_to_buffer(&buffer, &size, &offset, "%s\r\n", report_event); + append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", report->info.call_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_addr.id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_addr.id); + append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id); + + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_addr.group); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_addr.group); + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_addr.mac); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_addr.mac); + + append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); + append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); + + if (are_metrics_filled(report->remote_metrics)!=0) { + append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); + append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); + } + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); + + if (report->qos_analyzer.timestamp!=NULL){ + append_to_buffer(&buffer, &size, &offset, "AdaptiveAlg:"); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " NAME=\"%s\"", report->qos_analyzer.name); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " TS=\"%s\"", report->qos_analyzer.timestamp); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN_LEG=\"%s\"", report->qos_analyzer.input_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN=\"%s\"", report->qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT_LEG=\"%s\"", report->qos_analyzer.output_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT=\"%s\"", report->qos_analyzer.output); + append_to_buffer(&buffer, &size, &offset, "\r\n"); + } + +#if TARGET_OS_IPHONE + { + size_t namesize; + char *machine; + sysctlbyname("hw.machine", NULL, &namesize, NULL, 0); + machine = malloc(namesize); + sysctlbyname("hw.machine", machine, &namesize, NULL, 0); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "Device: %s\r\n", machine); + } +#endif + + linphone_content_set_buffer(content, buffer, strlen(buffer)); + ms_free(buffer); + + if (call->log->reporting.on_report_sent != NULL){ + call->log->reporting.on_report_sent( + call, + (report==call->log->reporting.reports[0])?LINPHONE_CALL_STATS_AUDIO:LINPHONE_CALL_STATS_VIDEO, + content); + } + + + route = linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy); + domain = ms_strdup_printf("sip:%s", linphone_proxy_config_get_domain(call->dest_proxy)); + request_uri = linphone_address_new(route ? route : domain); + ms_free(domain); + lev=linphone_core_create_publish(call->core, request_uri, "vq-rtcpxr", expires); + if (route) { + ms_message("Publishing report with custom route %s", route); + sal_op_set_route(lev->op, route); + } + + if (linphone_event_send_publish(lev, content) != 0){ + linphone_event_unref(lev); + lev=NULL; + ret=4; + } else { + reset_avg_metrics(report); + STR_REASSIGN(report->qos_analyzer.timestamp, NULL); + STR_REASSIGN(report->qos_analyzer.input_leg, NULL); + STR_REASSIGN(report->qos_analyzer.input, NULL); + STR_REASSIGN(report->qos_analyzer.output_leg, NULL); + STR_REASSIGN(report->qos_analyzer.output, NULL); + } + + linphone_address_destroy(request_uri); + linphone_content_unref(content); + + end: + ms_message("QualityReporting[%p]: Send '%s' with status %d", + call, + report_event, + ret + ); + + return ret; +} + +static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { + int count; + if (smd != NULL) { + for (count = 0; count < smd->nb_streams; ++count) { + if (smd->streams[count].type == sal_stream_type) { + return &smd->streams[count]; + } + } + } + return NULL; +} + +static void update_ip(LinphoneCall * call, int stats_type) { + SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; + const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); + const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type); + + if (local_desc != NULL) { + /*since this function might be called for video stream AFTER it has been uninitialized, local description might + be invalid. In any other case, IP/port should be always filled and valid*/ + if (strlen(local_desc->rtp_addr) > 0) { + call->log->reporting.reports[stats_type]->info.local_addr.port = local_desc->rtp_port; + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); + } + } + + if (remote_desc != NULL) { + /*port is always stored in stream description struct*/ + call->log->reporting.reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; + + /*for IP it can be not set if we are using a direct route*/ + if (strlen(remote_desc->rtp_addr) > 0) { + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); + } else { + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); + } + } +} + +static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){ + reporting_session_report_t *report = (reporting_session_report_t*)user_data; + LinphoneCall *call = report->call; + char * appendbuf; + int i; + int ptime = -1; + int bitrate[2] = {-1, -1}; + int up_bw[2] = {-1, -1}; + int down_bw[2] = {-1, -1}; + MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; + for (i=0;i<2;i++){ + if (streams[i]!=NULL){ + if (streams[i]->encoder!=NULL){ + if (ms_filter_has_method(streams[i]->encoder,MS_FILTER_GET_BITRATE)){ + ms_filter_call_method(streams[i]->encoder,MS_FILTER_GET_BITRATE,&bitrate[i]); + bitrate[i] /= 1000.f; + } + } + up_bw[i] = media_stream_get_up_bw(streams[i])/1000.f; + down_bw[i] = media_stream_get_down_bw(streams[i])/1000.f; + } + } + if (call->audiostream!=NULL){ + if (call->audiostream->ms.encoder!=NULL){ + if(ms_filter_has_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){ + ms_filter_call_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime); + } + } + } + + appendbuf=ms_strdup_printf("%s%d;", report->qos_analyzer.timestamp?report->qos_analyzer.timestamp:"", ms_time(0)); + STR_REASSIGN(report->qos_analyzer.timestamp,appendbuf); + + STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup_printf("%s aenc_ptime aenc_br a_dbw a_ubw venc_br v_dbw v_ubw", datav[0])); + appendbuf=ms_strdup_printf("%s%s %d %d %d %d %d %d %d;", report->qos_analyzer.input?report->qos_analyzer.input:"", datav[1], + ptime, bitrate[0], down_bw[0], up_bw[0], bitrate[1], down_bw[1], up_bw[1] ); + STR_REASSIGN(report->qos_analyzer.input,appendbuf); + STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(datav[2])); + appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", datav[3]); + STR_REASSIGN(report->qos_analyzer.output, appendbuf); +} + +void linphone_reporting_update_ip(LinphoneCall * call) { + update_ip(call, LINPHONE_CALL_STATS_AUDIO); + update_ip(call, LINPHONE_CALL_STATS_VIDEO); +} + +void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { + MediaStream * stream = NULL; + const PayloadType * local_payload = NULL; + const PayloadType * remote_payload = NULL; + const LinphoneCallParams * current_params = linphone_call_get_current_params(call); + reporting_session_report_t * report = call->log->reporting.reports[stats_type]; + char * dialog_id; + + // call->op might be already released if hanging up in state LinphoneCallOutgoingInit + if (!media_report_enabled(call, stats_type) || call->op == NULL) + return; + + dialog_id = sal_op_get_dialog_id(call->op); + + STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); + + STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(call->core))); + STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(linphone_call_get_remote_user_agent(call))); + + // RFC states: "LocalGroupID provides the identification for the purposes + // of aggregation for the local endpoint.". + STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s" + , dialog_id + , "local" + , report->local_metrics.user_agent + ) + ); + STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s" + , dialog_id + , "remote" + , report->remote_metrics.user_agent + ) + ); + + + if (call->dir == LinphoneCallIncoming) { + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id)); + } else { + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id)); + } + + + report->local_metrics.timestamps.start = call->log->start_date_time; + report->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); + + /*we use same timestamps for remote too*/ + report->remote_metrics.timestamps.start = call->log->start_date_time; + report->remote_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); + + + /*yet we use the same payload config for local and remote, since this is the largest use case*/ + if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { + stream = &call->audiostream->ms; + local_payload = linphone_call_params_get_used_audio_codec(current_params); + remote_payload = local_payload; + } else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) { + stream = &call->videostream->ms; + local_payload = linphone_call_params_get_used_video_codec(current_params); + remote_payload = local_payload; + } + + if (stream != NULL) { + RtpSession * session = stream->sessions.rtp_session; + + report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); + report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); + + if (stream->qi != NULL){ + report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_lq_rating(stream->qi)) : -1; + report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_rating(stream->qi)) : -1; + } + } + + STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialog_id, report->info.local_addr.ssrc)); + + if (local_payload != NULL) { + report->local_metrics.session_description.payload_type = local_payload->type; + if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); + report->local_metrics.session_description.sample_rate = local_payload->clock_rate; + if (local_payload->recv_fmtp!=NULL) STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp)); + } + + if (remote_payload != NULL) { + report->remote_metrics.session_description.payload_type = remote_payload->type; + STR_REASSIGN(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_type)); + report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; + STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp)); + } + + ms_free(dialog_id); +} + +/* generate random float in interval ] 0.9 t ; 1.1 t [*/ +static float reporting_rand(float t){ + return t * (.2f * (rand() / (RAND_MAX * 1.0f)) + 0.9f); +} + +void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_type) { + reporting_session_report_t * report = call->log->reporting.reports[stats_type]; + reporting_content_metrics_t * metrics = NULL; + LinphoneCallStats stats = call->stats[stats_type]; + mblk_t *block = NULL; + int report_interval; + + if (! media_report_enabled(call,stats_type)) + return; + + report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy); + + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { + metrics = &report->remote_metrics; + block = stats.received_rtcp; + } else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) { + metrics = &report->local_metrics; + block = stats.sent_rtcp; + } + do{ + if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){ + + uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); + + metrics->rtcp_xr_count++; + + // for local mos rating, we'll use the quality indicator directly + // because rtcp XR might not be enabled + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE){ + metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ? + 127 : rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ? + 127 : rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + } + + metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); + metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); + metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block); + metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; + metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block); + metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block); + + metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; + + metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); + }else if (rtcp_is_SR(block)){ + MediaStream *ms=(stats_type==0 ? &call->audiostream->ms : &call->videostream->ms); + float rtt = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session); + + if (rtt > 1e-6){ + metrics->rtcp_sr_count++; + metrics->delay.round_trip_delay += 1000*rtt; + } + } + }while(rtcp_next_packet(block)); + + /* check if we should send an interval report - use a random sending time to + dispatch reports and avoid sending them too close from each other */ + if (report_interval>0 && ms_time(NULL)-report->last_report_date>reporting_rand(report_interval)){ + linphone_reporting_update_media_info(call, stats_type); + send_report(call, report, "VQIntervalReport"); + } +} + +static int publish_report(LinphoneCall *call, const char *event_type){ + int ret = 0; + int i; + for (i = 0; i < 2; i++){ + if (media_report_enabled(call, i)){ + int sndret; + linphone_reporting_update_media_info(call, i); + sndret=send_report(call, call->log->reporting.reports[i], event_type); + if (sndret>0){ + ret += 10+(i+1)*sndret; + } + } else{ + ret += i+1; + } + } + return ret; +} + +int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term) { + char * session_type = call_term?"VQSessionReport: CallTerm":"VQSessionReport"; + return publish_report(call, session_type); +} + +int linphone_reporting_publish_interval_report(LinphoneCall* call) { + return publish_report(call, "VQIntervalReport"); +} + +static bool_t set_on_action_suggested_cb(MediaStream *stream,void (*on_action_suggested)(void*,int,const char**),void* u) { + if (stream&&stream->rc){ + MSQosAnalyzer *analyzer=ms_bitrate_controller_get_qos_analyzer(stream->rc); + if (analyzer){ + ms_qos_analyzer_set_on_action_suggested(analyzer, + on_action_suggested, + u); + return TRUE; + } + } + return FALSE; +} + +void linphone_reporting_call_state_updated(LinphoneCall *call){ + LinphoneCallState state=linphone_call_get_state(call); + if (state == LinphoneCallReleased||!quality_reporting_enabled(call)){ + return; + } + switch (state){ + case LinphoneCallStreamsRunning:{ + int i = 0; + MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; + for (i=0;i<2;i++) { + bool_t enabled=media_report_enabled(call, i); + if (enabled && set_on_action_suggested_cb(streams[i], qos_analyzer_on_action_suggested, call->log->reporting.reports[i])) { + call->log->reporting.reports[i]->call=call; + STR_REASSIGN(call->log->reporting.reports[i]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(ms_bitrate_controller_get_qos_analyzer(streams[i]->rc)))); + } + } + linphone_reporting_update_ip(call); + if (!media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO) && call->log->reporting.was_video_running){ + send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport"); + } + call->log->reporting.was_video_running=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); + break; + } + case LinphoneCallEnd:{ + set_on_action_suggested_cb(&call->audiostream->ms, NULL, NULL); + set_on_action_suggested_cb(&call->videostream->ms, NULL, NULL); + if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ + linphone_reporting_publish_session_report(call, TRUE); + } + break; + } + default:{ + break; + } + } +} + +reporting_session_report_t * linphone_reporting_new() { + int i; + reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1); + reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics}; + + memset(rm, 0, sizeof(reporting_session_report_t)); + + for (i = 0; i < 2; i++) { + metrics[i]->session_description.payload_type = -1; + metrics[i]->session_description.sample_rate = -1; + metrics[i]->session_description.frame_duration = -1; + metrics[i]->session_description.packet_loss_concealment = -1; + + metrics[i]->packet_loss.network_packet_loss_rate = -1; + metrics[i]->packet_loss.jitter_buffer_discard_rate = -1; + + + metrics[i]->jitter_buffer.adaptive = -1; + metrics[i]->jitter_buffer.abs_max = -1; + + metrics[i]->delay.end_system_delay = -1; + metrics[i]->delay.interarrival_jitter = -1; + metrics[i]->delay.mean_abs_jitter = -1; + + metrics[i]->signal.level = 127; + metrics[i]->signal.noise_level = 127; + } + + reset_avg_metrics(rm); + return rm; +} + +void linphone_reporting_destroy(reporting_session_report_t * report) { + STR_REASSIGN(report->info.call_id, NULL); + STR_REASSIGN(report->info.local_addr.id, NULL); + STR_REASSIGN(report->info.remote_addr.id, NULL); + STR_REASSIGN(report->info.orig_id, NULL); + STR_REASSIGN(report->info.local_addr.ip, NULL); + STR_REASSIGN(report->info.remote_addr.ip, NULL); + STR_REASSIGN(report->info.local_addr.group, NULL); + STR_REASSIGN(report->info.remote_addr.group, NULL); + STR_REASSIGN(report->info.local_addr.mac, NULL); + STR_REASSIGN(report->info.remote_addr.mac, NULL); + STR_REASSIGN(report->dialog_id, NULL); + STR_REASSIGN(report->local_metrics.session_description.fmtp, NULL); + STR_REASSIGN(report->local_metrics.session_description.payload_desc, NULL); + STR_REASSIGN(report->local_metrics.user_agent, NULL); + STR_REASSIGN(report->remote_metrics.session_description.fmtp, NULL); + STR_REASSIGN(report->remote_metrics.session_description.payload_desc, NULL); + STR_REASSIGN(report->remote_metrics.user_agent, NULL); + STR_REASSIGN(report->qos_analyzer.name, NULL); + STR_REASSIGN(report->qos_analyzer.timestamp, NULL); + STR_REASSIGN(report->qos_analyzer.input_leg, NULL); + STR_REASSIGN(report->qos_analyzer.input, NULL); + STR_REASSIGN(report->qos_analyzer.output_leg, NULL); + STR_REASSIGN(report->qos_analyzer.output, NULL); + + ms_free(report); +} + + +void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb){ + call->log->reporting.on_report_sent = cb; +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h new file mode 100644 index 000000000..07ad65055 --- /dev/null +++ b/coreapi/quality_reporting.h @@ -0,0 +1,216 @@ +/* +linphone +Copyright (C) 2014 - 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 quality_reporting_h +#define quality_reporting_h + +#include "linphonecore.h" +#include "sal/sal.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/** + * Linphone quality report sub object storing address related information. + */ +typedef struct reporting_addr { + char * id; + char * ip; + int port; + uint32_t ssrc; + + char * group; + char * mac; // optional +} reporting_addr_t; + +/** + * Linphone quality report sub object storing media metrics information as required by RFC6035. + */ + +typedef struct reporting_content_metrics { + // timestamps - mandatory + struct { + time_t start; + time_t stop; + } timestamps; + + // session description - optional + struct { + int payload_type; + char * payload_desc; + int sample_rate; + int frame_duration; + char * fmtp; + int packet_loss_concealment; + } session_description; + + // jitter buffet - optional + struct { + int adaptive; + int nominal; + int max; + int abs_max; + } jitter_buffer; + + // packet loss - optional + struct { + float network_packet_loss_rate; + float jitter_buffer_discard_rate; + } packet_loss; + + // delay - optional + struct { + int round_trip_delay; + int end_system_delay; + int symm_one_way_delay; + int interarrival_jitter; + int mean_abs_jitter; + } delay; + + // signal - optional + struct { + int level; + int noise_level; + } signal; + + // quality estimates - optional + struct { + float moslq; + float moscq; + } quality_estimates; + + // custom extension + char * user_agent; + + // for internal processing + uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) + uint8_t rtcp_sr_count; // number of RTCP SR packets received since last report, used to compute RTT average values in case RTCP XR voip metrics is not enabled + +} reporting_content_metrics_t; + + +/** + * Linphone quality report main object created by function linphone_reporting_new(). + * It contains all fields required by RFC6035 + */ +typedef struct reporting_session_report { + struct { + char * call_id; + char * orig_id; + reporting_addr_t local_addr; + reporting_addr_t remote_addr; + } info; + + reporting_content_metrics_t local_metrics; + reporting_content_metrics_t remote_metrics; // optional + + char * dialog_id; // optional + + // Quality of Service analyzer - custom extension + /* This should allow us to analysis bad network conditions and quality adaptation + on server side*/ + struct { + char * name; /*type of the QoS analyzer used*/ + char* timestamp; /*time of each decision in seconds*/ + char* input_leg; /*input parameters' name*/ + char* input; /*set of inputs for each semicolon separated decision*/ + char* output_leg; /*output parameters' name*/ + char* output; /*set of outputs for each semicolon separated decision*/ + } qos_analyzer; + + // for internal processing + time_t last_report_date; + LinphoneCall *call; +} reporting_session_report_t; + + +typedef void (*LinphoneQualityReportingReportSendCb)(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content); + +reporting_session_report_t * linphone_reporting_new(); +void linphone_reporting_destroy(reporting_session_report_t * report); + +/** + * Fill media information about a given call. This function must be called before + * stopping the media stream. + * @param call #LinphoneCall object to consider + * @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO) + * + */ +void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type); + +/** + * Fill IP information about a given call. This function must be called each + * time call state is 'LinphoneCallStreamsRunning' since IP might be updated (if we + * found a direct route between caller and callee for example). + * When call is starting, remote IP/port might be the proxy ones to which callee is registered + * @param call #LinphoneCall object to consider + * + */ +void linphone_reporting_update_ip(LinphoneCall * call); + +/** + * Publish a session report. This function should be called when session terminates, + * media change (codec change or session fork), session terminates due to no media packets being received. + * @param call #LinphoneCall object to consider + * @param call_term whether the call has ended or is continuing + * + * @return error code. 0 for success, positive value otherwise. + */ +int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term); + +/** + * Publish an interval report. This function should be used for periodic interval + * @param call #LinphoneCall object to consider + * @return error code. 0 for success, positive value otherwise. + * + */ +int linphone_reporting_publish_interval_report(LinphoneCall* call); + +/** + * Update publish reports with newly sent/received RTCP-XR packets (if available). + * @param call #LinphoneCall object to consider + * @param stats_type the media type + * + */ +void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_type); + +/** + * Update publish reports on call state change. + * @param call #LinphoneCall object to consider + * + */ +void linphone_reporting_call_state_updated(LinphoneCall *call); + +/** + * Setter of the #LinphoneQualityReportingReportSendCb callback method which is + * notified each time a report will be submitted to the collector, if quality + * reporting is enabled + * @param call #LinphoneCall object to consider + * @param cb #LinphoneQualityReportingReportSendCb callback function to notify + * + */ +LINPHONE_PUBLIC void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c new file mode 100644 index 000000000..40355fa89 --- /dev/null +++ b/coreapi/remote_provisioning.c @@ -0,0 +1,143 @@ +/* +remote_provisioning.c +Copyright (C) 2010 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "private.h" +#include "xml2lpc.h" + +#define XML2LPC_CALLBACK_BUFFER_SIZE 1024 + +static void xml2lpc_callback(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) { + char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; + vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); + + if (level == XML2LPC_ERROR) + ms_error("%s", buffer); + else if (level == XML2LPC_WARNING) + ms_warning("%s", buffer); + /*else + ms_message("%s", buffer); // Don't log debug messages */ +} + +static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml) { + xml2lpc_context *context = xml2lpc_context_new(xml2lpc_callback, lc); + int result = xml2lpc_set_xml_string(context, xml); + char * error_msg = NULL; + if (result == 0) { + LpConfig * lpc = linphone_core_get_config(lc); + result = xml2lpc_convert(context, lpc); + if (result == 0) { + // if the remote provisioning added a proxy config and none was set before, set it + if (lp_config_has_section(lpc, "proxy_0") && lp_config_get_int(lpc, "sip", "default_proxy", -1) == -1){ + lp_config_set_int(lpc, "sip", "default_proxy", 0); + } + lp_config_sync(lpc); + + } else { + error_msg = "xml to lpc failed"; + } + } else { + error_msg = "invalid xml"; + } + + xml2lpc_context_destroy(context); + linphone_configuring_terminated(lc + ,error_msg ? LinphoneConfiguringFailed : LinphoneConfiguringSuccessful + , error_msg); +} + +int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path){ + int status = -1; + char* provisioning=ms_load_path_content(file_path, NULL); + + if (provisioning){ + linphone_remote_provisioning_apply(lc, provisioning); + status = 0; + ms_free(provisioning); + } + return status; +} + +static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) { + LinphoneCore *lc = (LinphoneCore *)ctx; + belle_sip_message_t *message = BELLE_SIP_MESSAGE(event->response); + const char *body = belle_sip_message_get_body(message); + + if (belle_http_response_get_status_code(event->response) == 200) { + linphone_remote_provisioning_apply(lc, body); + } else { + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http error"); + } +} + +static void belle_request_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) { + LinphoneCore *lc = (LinphoneCore *)ctx; + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http io error"); +} + +static void belle_request_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) { + LinphoneCore *lc = (LinphoneCore *)ctx; + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http timeout"); +} + +static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) { + LinphoneCore *lc = (LinphoneCore *)ctx; + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http auth requested"); +} + +int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) { + + belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri); + const char* scheme = uri ? belle_generic_uri_get_scheme(uri) : NULL; + const char *host = uri ? belle_generic_uri_get_host(uri) : NULL; + + if( scheme && (strcmp(scheme,"file") == 0) ){ + // We allow for 'local remote-provisioning' in case the file is to be opened from the hard drive. + const char* file_path = remote_provisioning_uri + strlen("file://"); // skip scheme + return linphone_remote_provisioning_load_file(lc, file_path); + + } else if( scheme && strncmp(scheme, "http", 4) == 0 && host && strlen(host) > 0) { + belle_http_request_listener_callbacks_t belle_request_listener={0}; + belle_http_request_listener_t *listener; + belle_http_request_t *request; + + belle_request_listener.process_response=belle_request_process_response_event; + belle_request_listener.process_auth_requested=belle_request_process_auth_requested; + belle_request_listener.process_io_error=belle_request_process_io_error; + belle_request_listener.process_timeout=belle_request_process_timeout; + + listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); + + request=belle_http_request_create("GET",uri, NULL); + return belle_http_provider_send_request(lc->http_provider, request, listener); + } else { + ms_error("Invalid provisioning URI [%s] (missing scheme or host ?)",remote_provisioning_uri); + return -1; + } +} + +void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char *uri) { + lp_config_set_string(lc->config,"misc","config-uri",uri); +} + +const char*linphone_core_get_provisioning_uri(const LinphoneCore *lc){ + return lp_config_get_string(lc->config,"misc","config-uri",NULL); +} + +bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc) { + return lp_config_get_int(lc->config, "misc", "transient_provisioning", 0) == 1; +} diff --git a/coreapi/sal.c b/coreapi/sal.c index ba02ef345..efbc2ea0d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -17,13 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/** +/** This header files defines the Signaling Abstraction Layer. - The purpose of this layer is too allow experiment different call signaling + 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 "bellesip_sal/sal_impl.h" + +#include + const char* sal_transport_to_string(SalTransport transport) { switch (transport) { case SalTransportUDP:return "udp"; @@ -33,11 +39,12 @@ const char* sal_transport_to_string(SalTransport transport) { default: { ms_fatal("Unexpected transport [%i]",transport); return NULL; - } + } } } 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; @@ -55,15 +62,17 @@ SalMediaDescription *sal_media_description_new(){ static void sal_media_description_destroy(SalMediaDescription *md){ int i; for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); - ms_list_free(md->streams[i].payloads); + ms_list_free_with_data(md->streams[i].payloads,(void (*)(void *))payload_type_destroy); + ms_list_free_with_data(md->streams[i].already_assigned_payloads,(void (*)(void *))payload_type_destroy); md->streams[i].payloads=NULL; + md->streams[i].already_assigned_payloads=NULL; } ms_free(md); } -void sal_media_description_ref(SalMediaDescription *md){ +SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){ md->refcount++; + return md; } void sal_media_description_unref(SalMediaDescription *md){ @@ -74,28 +83,75 @@ void sal_media_description_unref(SalMediaDescription *md){ } SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, - SalMediaProto proto, SalStreamType type){ + SalMediaProto proto, SalStreamType type){ int i; - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ SalStreamDescription *ss=&md->streams[i]; + if (!sal_stream_description_active(ss)) continue; if (ss->proto==proto && ss->type==type) return ss; } return NULL; } +unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) { + unsigned int i; + unsigned int nb = 0; + for (i = 0; i < md->nb_streams; ++i) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (md->streams[i].type == type) nb++; + } + return nb; +} + +SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) { + unsigned int i; + for (i = 0; i < md->nb_streams; ++i) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (md->streams[i].type == type) { + if (idx-- == 0) return &md->streams[i]; + } + } + return NULL; +} + +SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) { + SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); + return desc; +} + +SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) { + SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type); + return desc; +} + bool_t sal_media_description_empty(const SalMediaDescription *md){ - if (md->n_active_streams > 0) return FALSE; + if (sal_media_description_get_nb_active_streams(md) > 0) return FALSE; return TRUE; } void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ SalStreamDescription *ss=&md->streams[i]; + if (!sal_stream_description_active(ss)) continue; ss->dir=stream_dir; } } +int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { + int i; + int nb = 0; + for (i = 0; i < md->nb_streams; i++) { + if (sal_stream_description_active(&md->streams[i])) nb++; + } + return nb; +} static bool_t is_null_address(const char *addr){ return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0; @@ -104,25 +160,27 @@ static bool_t is_null_address(const char *addr){ /*check for the presence of at least one stream with requested direction */ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ int i; - + /* we are looking for at least one stream with requested direction, inactive streams are ignored*/ - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ const SalStreamDescription *ss=&md->streams[i]; - if (ss->dir==stream_dir) return TRUE; - /*compatibility check for phones that only used the null address and no attributes */ - if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))) + if (!sal_stream_description_active(ss)) continue; + if (ss->dir==stream_dir) { return TRUE; + } + /*compatibility check for phones that only used the null address and no attributes */ + if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))){ + return TRUE; + } } return FALSE; } bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ if (stream_dir==SalStreamRecvOnly){ - if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE; - else return TRUE; + return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)); }else if (stream_dir==SalStreamSendOnly){ - if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE; - else return TRUE; + return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)); }else if (stream_dir==SalStreamSendRecv){ return has_dir(md,SalStreamSendRecv); }else{ @@ -134,6 +192,52 @@ bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir return FALSE; } +bool_t sal_stream_description_active(const SalStreamDescription *sd) { + return (sd->rtp_port > 0); +} + +bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoUdpTlsRtpSavpf)); +} + +bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf)); +} + +bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoUdpTlsRtpSavp) || (sd->proto == SalProtoUdpTlsRtpSavpf)); +} + +bool_t sal_media_description_has_avpf(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + +bool_t sal_media_description_has_srtp(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + +bool_t sal_media_description_has_dtls(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + /* static bool_t fmtp_equals(const char *p1, const char *p2){ if (p1 && p2 && strcmp(p1,p2)==0) return TRUE; @@ -153,7 +257,7 @@ static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){ */ /* if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) || - !fmtp_equals(p1->send_fmtp,p2->send_fmtp)) + !fmtp_equals(p1->send_fmtp,p2->send_fmtp)) return FALSE; */ return TRUE; @@ -193,14 +297,18 @@ int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStre if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { if ((sd1->crypto[i].tag != sd2->crypto[i].tag) - || (sd1->crypto[i].algo != sd2->crypto[i].algo) - || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { - result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED; + || (sd1->crypto[i].algo != sd2->crypto[i].algo)){ + result|=SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED; + } + if ((strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { + result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; } } if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtp_addr[0]!='\0' && sd2->rtp_addr[0]!='\0' && ms_is_multicast(sd1->rtp_addr) != ms_is_multicast(sd2->rtp_addr)) + result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; if (sd1->rtp_port != sd2->rtp_port) { if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; @@ -212,6 +320,10 @@ int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStre if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + /*DTLS*/ + if (sd1->dtls_role != sd2->dtls_role) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; + if (strcmp(sd1->dtls_fingerprint, sd2->dtls_fingerprint) != 0) result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; + return result; } @@ -220,13 +332,23 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD int i; if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (md1->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (md1->addr[0]!='\0' && md2->addr[0]!='\0' && ms_is_multicast(md1->addr) != ms_is_multicast(md2->addr)) + result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; + if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for(i = 0; i < md1->n_total_streams; ++i){ + for(i = 0; i < md1->nb_streams; ++i){ result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } 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 +359,82 @@ static void assign_string(char **str, const char *arg){ *str=ms_strdup(arg); } -void sal_op_set_contact(SalOp *op, const char *contact){ - assign_string(&((SalOpBase*)op)->contact,contact); +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; +} + +const SalAddress*sal_op_get_remote_contact_address(const SalOp* op) +{ + return ((SalOpBase*)op)->remote_contact_address; +} + +#define SET_PARAM(op,name) \ + char* name##_string=NULL; \ + assign_address(&((SalOpBase*)op)->name##_address,name); \ + 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); + 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_realm(SalOp *op, const char *realm){ + SalOpBase* op_base = (SalOpBase*)op; + if (op_base->realm != NULL){ + ms_free(op_base->realm); + } + op_base->realm = ms_strdup(realm); } - 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 +448,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; } @@ -299,21 +485,54 @@ const char *sal_op_get_network_origin(const SalOp *op){ const char* sal_op_get_call_id(const SalOp *op) { return ((SalOpBase*)op)->call_id; } +char* sal_op_get_dialog_id(const SalOp *op) { + if (op->dialog != NULL) { + return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id, + belle_sip_dialog_get_remote_tag(op->dialog), belle_sip_dialog_get_local_tag(op->dialog)); + } + return NULL; + +} void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); ((SalOpBase*)b)->root=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_remote_contact(SalOp *op, const char* remote_contact){ + SET_PARAM(op,remote_contact); +} + +void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){ + char* address_string=sal_address_as_string(origin); /*can probably be optimized*/ + __sal_op_set_network_origin(op,address_string); + 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,9 +545,12 @@ void __sal_op_free(SalOp *op){ ms_free(b->route); b->route=NULL; } - if (b->contact) { - ms_free(b->contact); - b->contact=NULL; + if (b->realm) { + ms_free(b->realm); + b->realm=NULL; + } + if (b->contact_address) { + sal_address_destroy(b->contact_address); } if (b->origin){ ms_free(b->origin); @@ -342,14 +564,26 @@ void __sal_op_free(SalOp *op){ ms_free(b->remote_contact); b->remote_contact=NULL; } + if (b->remote_contact_address){ + sal_address_destroy(b->remote_contact_address); + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) 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,72 +596,177 @@ 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_stream_type_to_string(SalStreamType type) { + switch (type) { + case SalAudio:return "audio"; + case SalVideo:return "video"; + default: return "other"; + } } -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_description_get_type_as_string(const SalStreamDescription *desc){ + if (desc->type==SalOther) return desc->typeother; + else return sal_stream_type_to_string(desc->type); +} + +const char* sal_media_proto_to_string(SalMediaProto type) { + switch (type) { + case SalProtoRtpAvp:return "RTP/AVP"; + case SalProtoRtpSavp:return "RTP/SAVP"; + case SalProtoUdpTlsRtpSavp:return "UDP/TLS/RTP/SAVP"; + case SalProtoRtpAvpf:return "RTP/AVPF"; + case SalProtoRtpSavpf:return "RTP/SAVPF"; + case SalProtoUdpTlsRtpSavpf:return "UDP/TLS/RTP/SAVPF"; + default: return "unknown"; + } +} + +const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){ + if (desc->proto==SalProtoOther) return desc->proto_other; + else return sal_media_proto_to_string(desc->proto); +} + + +const char* sal_stream_dir_to_string(SalStreamDir type) { + switch (type) { + case SalStreamSendRecv:return "sendrecv"; + case SalStreamSendOnly:return "sendonly"; + case SalStreamRecvOnly:return "recvonly"; + case SalStreamInactive:return "inative"; + default: return "unknown"; + } + +} + +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 SalReasonUnsupportedContent: return "SalReasonUnsupportedContent"; + 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; +} + +belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal) { + return sal->stack; +} + +char* sal_op_get_public_uri(SalOp *op) { + if (op && op->refresher) { + return belle_sip_refresher_get_public_uri(op->refresher); } 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); - } - 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; - } - b->custom_headers=ch; -} - - - diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c deleted file mode 100644 index 1777c0d42..000000000 --- a/coreapi/sal_eXosip2.c +++ /dev/null @@ -1,2668 +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; - 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 && strcasecmp(h->hvalue,"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 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; - } - }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(&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); -} - -static void sal_register_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_register_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_register_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); - 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_register_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 68a2d05ef..000000000 --- a/coreapi/sal_eXosip2.h +++ /dev/null @@ -1,102 +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*)); - -#endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c deleted file mode 100644 index 1e49970bf..000000000 --- a/coreapi/sal_eXosip2_presence.c +++ /dev/null @@ -1,797 +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); -} - -#ifdef WIN32 - -static inline char *my_ctime_r(const time_t *t, char *buf){ - strcpy(buf,ctime(t)); - return buf; -} - -#else -#define my_ctime_r ctime_r -#endif - -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ - osip_message_t *sip=NULL; - time_t t=time(NULL); - char buf[26]; - - 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); - osip_message_set_date(sip,my_ctime_r(&t,buf)); - 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; - } - 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]; - - mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - - i = eXosip_build_publish(&pub,from, to, NULL, "presence", "300", - presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); - if (i<0){ - ms_warning("Failed to build publish request."); - return -1; - } - - 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 9297077e6..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) strncmp(key,b,sizeof(key)) - -#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 %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 (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 f29398c93..f10c98a60 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -49,7 +49,7 @@ static void guess_display_name(LinphoneAddress *from){ ms_free(dn); } -static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){ +static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); LinphoneCore *lc=linphone_proxy_config_get_core(cfg); LinphoneAuthInfo *auth; @@ -66,7 +66,8 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char tmp=linphone_address_as_string(parsed_uri); linphone_proxy_config_set_identity(cfg,tmp); if (passwd ) { - auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),userid,passwd,NULL,NULL, + linphone_address_get_domain(parsed_uri)); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); @@ -79,6 +80,7 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char static int sip_login_do_logout(SipSetupContext * ctx){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); + linphone_proxy_config_edit(cfg); linphone_proxy_config_enable_register(cfg,FALSE); linphone_proxy_config_done(cfg); return 0; diff --git a/coreapi/sipsetup.c b/coreapi/sipsetup.c index a5b846a64..7c9f074d9 100644 --- a/coreapi/sipsetup.c +++ b/coreapi/sipsetup.c @@ -18,20 +18,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H -#include "../config.h" +#include "config.h" #endif #include "linphonecore.h" extern SipSetup linphone_sip_login; -#ifdef BUILD_WIZARD -extern SipSetup linphone_sip_wizard; -#endif static SipSetup *all_sip_setups[]={ &linphone_sip_login, -#ifdef BUILD_WIZARD - &linphone_sip_wizard, -#endif NULL }; @@ -146,7 +140,7 @@ int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri){ return -1; } -int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd){ +int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){ LinphoneAddress *from=linphone_address_new(uri); if (from==NULL) { ms_warning("Fail to parse %s",uri); @@ -156,7 +150,7 @@ int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, cons strncpy(ctx->username,linphone_address_get_username(from),sizeof(ctx->username)); linphone_address_destroy(from); if (ctx->funcs->login_account) - return ctx->funcs->login_account(ctx,uri,passwd); + return ctx->funcs->login_account(ctx,uri,passwd,userid); return -1; } diff --git a/coreapi/sipsetup.h b/coreapi/sipsetup.h index 2aefbee5c..63d71d5f1 100644 --- a/coreapi/sipsetup.h +++ b/coreapi/sipsetup.h @@ -23,14 +23,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mscommon.h" +#ifndef LINPHONE_PUBLIC +#define LINPHONE_PUBLIC MS2_PUBLIC +#endif + struct _SipSetup; struct _BuddyInfo; +struct _LinphoneXmlRpcSession; + struct _SipSetupContext{ struct _SipSetup *funcs; struct _LinphoneProxyConfig *cfg; + struct _LinphoneXmlRpcSession *xmlrpc_session; char domain[128]; char username[128]; void *data; @@ -98,7 +105,7 @@ struct _SipSetup{ void (*uninit_instance)(SipSetupContext *ctx); int (*account_exists)(SipSetupContext *ctx, const char *uri); int (*create_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe); - int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd); + int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *userid); int (*get_proxy)(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz); int (*get_stun_servers)(SipSetupContext *ctx, char *stun1, char *stun2, size_t size); int (*get_relay)(SipSetupContext *ctx, char *relay, size_t size); @@ -117,10 +124,10 @@ typedef struct _SipSetup SipSetup; extern "C"{ #endif -BuddyInfo *buddy_info_new(); +BuddyInfo *buddy_info_new(void); void buddy_info_free(BuddyInfo *info); -void buddy_lookup_request_set_key(BuddyLookupRequest *req, const char *key); +LINPHONE_PUBLIC void buddy_lookup_request_set_key(BuddyLookupRequest *req, const char *key); void buddy_lookup_request_set_max_results(BuddyLookupRequest *req, int ncount); @@ -128,28 +135,28 @@ void sip_setup_register(SipSetup *ss); void sip_setup_register_all(void); SipSetup *sip_setup_lookup(const char *type_name); void sip_setup_unregister_all(void); -unsigned int sip_setup_get_capabilities(SipSetup *s); +LINPHONE_PUBLIC unsigned int sip_setup_get_capabilities(SipSetup *s); SipSetupContext * sip_setup_context_new(SipSetup *s, struct _LinphoneProxyConfig *cfg); int sip_setup_context_account_exists(SipSetupContext *ctx, const char *uri); int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri); int sip_setup_context_create_account(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe); -int sip_setup_context_get_capabilities(SipSetupContext *ctx); -int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd); +LINPHONE_PUBLIC int sip_setup_context_get_capabilities(SipSetupContext *ctx); +LINPHONE_PUBLIC int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid); int sip_setup_context_get_proxy(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz); int sip_setup_context_get_stun_servers(SipSetupContext *ctx, char *stun1, char *stun2, size_t size); int sip_setup_context_get_relay(SipSetupContext *ctx, char *relay, size_t size); -BuddyLookupRequest *sip_setup_context_create_buddy_lookup_request(SipSetupContext *ctx); -int sip_setup_context_buddy_lookup_submit(SipSetupContext *ctx , BuddyLookupRequest *req); -int sip_setup_context_buddy_lookup_free(SipSetupContext *ctx , BuddyLookupRequest *req); +LINPHONE_PUBLIC BuddyLookupRequest *sip_setup_context_create_buddy_lookup_request(SipSetupContext *ctx); +LINPHONE_PUBLIC int sip_setup_context_buddy_lookup_submit(SipSetupContext *ctx , BuddyLookupRequest *req); +LINPHONE_PUBLIC int sip_setup_context_buddy_lookup_free(SipSetupContext *ctx , BuddyLookupRequest *req); const char * sip_setup_context_get_notice(SipSetupContext *ctx); const char ** sip_setup_context_get_domains(SipSetupContext *ctx); void sip_setup_context_free(SipSetupContext *ctx); -int sip_setup_context_logout(SipSetupContext *ctx); +LINPHONE_PUBLIC int sip_setup_context_logout(SipSetupContext *ctx); /*internal methods for use WITHIN plugins: do not use elsewhere*/ struct _LinphoneProxyConfig *sip_setup_context_get_proxy_config(const SipSetupContext *ctx); diff --git a/coreapi/sipwizard.c b/coreapi/sipwizard.c deleted file mode 100644 index ee268e50c..000000000 --- a/coreapi/sipwizard.c +++ /dev/null @@ -1,268 +0,0 @@ -/* -sipwizard.c -Copyright (C) 2011 Belledonne Communication, 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 "linphonecore.h" -#include "private.h" -#include -#include - -typedef struct _BLReq{ - int status; - int result; - SoupMessage *msg; - SoupSession *session; - ortp_thread_t th; -}BLReq; - -static const int XMLRPC_FAILED = -1; -static const int XMLRPC_OK = 0; -static const char *XMLRPC_URL = "https://www.linphone.org/wizard.php"; - -static void sip_wizard_init_instance(SipSetupContext *ctx){ - LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); - /*disable registration until the user logs in*/ - linphone_proxy_config_enable_register(cfg,FALSE); -} - -static const char ** sip_wizard_get_domains(SipSetupContext *ctx) { - LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); - const char **domains = (const char**) &cfg->reg_proxy; - return domains; -} - - -static int xml_rpc_parse_response(BLReq *blreq, SoupMessage *sm){ - SoupBuffer *sb; - GValue retval; - GError *error=NULL; - sb=soup_message_body_flatten(sm->response_body); - ms_message("This the xml-rpc response:\n%s\n",sb->data); - if (soup_xmlrpc_parse_method_response(sb->data,sb->length,&retval,&error)==FALSE){ - if (error!=NULL){ - ms_error("xmlrpc fault: %s",error->message); - g_error_free(error); - }else{ - ms_error("Could not parse xml-rpc response !"); - } - blreq->status=XMLRPC_FAILED; - }else{ - ms_message("Extracting values from return type..."); - blreq->result = g_value_get_int(&retval); - g_value_unset(&retval); - blreq->status=XMLRPC_OK; - } - soup_buffer_free(sb); - return blreq->status; -} - -static void got_headers(BLReq *blreq, SoupMessage*msg){ - ms_message("Got headers !"); - blreq->status=XMLRPC_OK; -} - -#if SERIALIZE_HTTPS -/*on windows libsoup support for threads with gnutls is not yet functionnal (only in git) -This will come in next release of libsoup, probably. -In the meantime, we are forced to serialize all soup https processing with a big -ugly global mutex...*/ - -static GStaticMutex big_mutex = G_STATIC_MUTEX_INIT; -#endif - -static void * process_xml_rpc_request(void *up){ - BLReq *blreq=(BLReq*)up; - SoupMessage *sm=blreq->msg; - int code; - g_signal_connect_swapped(G_OBJECT(sm),"got-headers",(GCallback)got_headers,blreq); - blreq->status=XMLRPC_OK; -#if SERIALIZE_HTTPS - g_static_mutex_lock(&big_mutex); -#endif - code=soup_session_send_message(blreq->session,sm); - if (code==200){ - xml_rpc_parse_response(blreq,sm); - }else{ - ms_error("request failed, error-code=%i (%s)",code,soup_status_get_phrase(code)); - blreq->status=XMLRPC_FAILED; - } -#if SERIALIZE_HTTPS - g_static_mutex_unlock(&big_mutex); -#endif - return NULL; -} - - -static int do_simple_xmlrpc_request(SoupMessage *msg) { - int ret=-1; - BLReq *req; - - if (!msg){ - ms_error("Fail to create SoupMessage !"); - return -1; - }else{ - SoupBuffer *sb=soup_message_body_flatten(msg->request_body); - ms_message("This is the XML-RPC request we are going to send:\n%s\n",sb->data); - soup_buffer_free(sb); - } - - req=ms_new0(BLReq, 1); - req->session=soup_session_sync_new(); - req->msg=msg; - - process_xml_rpc_request(req); - - if (req->status == XMLRPC_OK) { - ret=req->result; - } - - // Freeing allocated structures lead to a crash (why?) - //g_free(req->session); - //g_free(msg); - ms_free(req); - - return ret; -} - -/* - * Return 1 if account already exists - * 0 if account doesn't exists - * -1 if information isn't available - */ -static int sip_wizard_account_exists(SipSetupContext *ctx, const char *identity) { - SoupMessage *msg=soup_xmlrpc_request_new(XMLRPC_URL, - "check_account", - G_TYPE_STRING, identity, - G_TYPE_INVALID); - return do_simple_xmlrpc_request(msg); -} - -static int sip_wizard_account_validated(SipSetupContext *ctx, const char *identity) { - SoupMessage *msg=soup_xmlrpc_request_new(XMLRPC_URL, - "check_account_validated", - G_TYPE_STRING, identity, - G_TYPE_INVALID); - return do_simple_xmlrpc_request(msg); -} - -static int sip_wizard_create_account(SipSetupContext *ctx, const char *identity, const char *passwd, const char *email, int suscribe) { - SoupMessage *msg=soup_xmlrpc_request_new(XMLRPC_URL, - "create_account", - G_TYPE_STRING, identity, - G_TYPE_STRING, passwd, - G_TYPE_STRING, email, - G_TYPE_INT, suscribe, - G_TYPE_INVALID); - return do_simple_xmlrpc_request(msg); -} - -static void guess_display_name(LinphoneAddress *from){ - const char *username=linphone_address_get_username(from); - char *dn=(char*)ms_malloc(strlen(username)+1); - const char *it; - char *wptr=dn; - bool_t begin=TRUE; - bool_t surname=FALSE; - for(it=username;*it!='\0';++it){ - if (begin){ - *wptr=toupper(*it); - begin=FALSE; - }else if (*it=='.'){ - if (surname) break; - *wptr=' '; - begin=TRUE; - surname=TRUE; - }else { - *wptr=*it; - } - wptr++; - } - *wptr='\0'; - linphone_address_set_display_name(from,dn); - ms_free(dn); -} - -static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){ - LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); - LinphoneCore *lc=linphone_proxy_config_get_core(cfg); - LinphoneAuthInfo *auth; - LinphoneAddress *parsed_uri; - char *tmp; - - parsed_uri=linphone_address_new(uri); - if (parsed_uri==NULL){ - return -1; - } - if (linphone_address_get_display_name(parsed_uri)!=NULL){ - guess_display_name(parsed_uri); - } - 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); - linphone_core_add_auth_info(lc,auth); - } - linphone_proxy_config_enable_register(cfg,TRUE); - linphone_proxy_config_done(cfg); - ms_free(tmp); - linphone_address_destroy(parsed_uri); - return 0; -} - -/* a simple SipSetup built-in plugin to allow creating accounts at runtime*/ - -#ifndef _MSC_VER - -SipSetup linphone_sip_wizard={ - .name="SipWizard", - .capabilities=SIP_SETUP_CAP_ACCOUNT_MANAGER, - .init_instance=sip_wizard_init_instance, - .account_exists=sip_wizard_account_exists, - .create_account=sip_wizard_create_account, - .login_account=sip_wizard_do_login, - .get_domains=sip_wizard_get_domains, - .account_validated=sip_wizard_account_validated -}; - -#else -SipSetup linphone_sip_wizard={ - "SipWizard", - SIP_SETUP_CAP_ACCOUNT_MANAGER, - 0, - NULL, - NULL, - sip_wizard_init_instance, - NULL, - sip_wizard_account_exists, - sip_wizard_create_account, - sip_wizard_do_login, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - sip_wizard_get_domains, - NULL, - NULL, - sip_wizard_account_validated -}; - - - -#endif diff --git a/coreapi/test_ecc.c b/coreapi/test_ecc.c index a0baeea40..8d383b625 100644 --- a/coreapi/test_ecc.c +++ b/coreapi/test_ecc.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]){ linphone_core_enable_logs(NULL); - linphone_core_start_echo_calibration(lc,calibration_finished,NULL); + linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL); while(count++<1000){ linphone_core_iterate(lc); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 7fe543b4d..68b82e2ed 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -20,14 +20,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "upnp.h" #include "private.h" #include "lpconfig.h" +#include + +#define UPNP_STRINGIFY(x) #x +#define UPNP_TOSTRING(x) UPNP_STRINGIFY(x) #define UPNP_ADD_MAX_RETRY 4 #define UPNP_REMOVE_MAX_RETRY 4 #define UPNP_SECTION_NAME "uPnP" -#define UPNP_CORE_READY_CHECK 1 -#define UPNP_CORE_RETRY_DELAY 4 -#define UPNP_CALL_RETRY_DELAY 1 - +#define UPNP_CORE_READY_CHECK 1 +#define UPNP_CORE_RETRY_DELAY 10 +#define UPNP_CALL_RETRY_DELAY 3 +#define UPNP_UUID_LEN 128 +#define UPNP_UUID_LEN_STR UPNP_TOSTRING(UPNP_UUID_LEN) /* * uPnP Definitions */ @@ -36,6 +41,7 @@ typedef struct _UpnpPortBinding { ms_mutex_t mutex; LinphoneUpnpState state; upnp_igd_ip_protocol protocol; + char *device_id; char local_addr[LINPHONE_IPADDR_SIZE]; int local_port; char external_addr[LINPHONE_IPADDR_SIZE]; @@ -73,37 +79,95 @@ struct _UpnpContext { ms_mutex_t mutex; ms_cond_t empty_cond; - + time_t last_ready_check; LinphoneUpnpState last_ready_state; }; 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); -UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port); +UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port); UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port); +void linphone_upnp_port_binding_set_device_id(UpnpPortBinding *port, const char * device_id); bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2); UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port); UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port); -void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay); +void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay); void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port); void linphone_upnp_port_binding_release(UpnpPortBinding *port); void linphone_upnp_update_config(UpnpContext *lupnp); void linphone_upnp_update_proxy(UpnpContext *lupnp, bool_t force); // Configuration -MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc); +MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const char *device_id); void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port); -// uPnP +// uPnP int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry); int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry); +static int linphone_upnp_strncmpi(const char *str1, const char *str2, int len) { + int i = 0; + char char1, char2; + while(i < len) { + char1 = toupper(*str1); + char2 = toupper(*str2); + if(char1 == '\0' || char1 != char2) { + return char1 - char2; + } + str1++; + str2++; + i++; + } + return 0; +} + +static int linphone_upnp_str_min(const char *str1, const char *str2) { + int len1 = strlen(str1); + int len2 = strlen(str2); + if(len1 > len2) { + return len2; + } + return len1; +} + +char * linphone_upnp_format_device_id(const char *device_id) { + char *ret = NULL; + char *tmp; + char tchar; + bool_t copy; + if(device_id == NULL) { + return ret; + } + ret = ms_new0(char, UPNP_UUID_LEN + 1); + tmp = ret; + if(linphone_upnp_strncmpi(device_id, "uuid:", linphone_upnp_str_min(device_id, "uuid:")) == 0) { + device_id += strlen("uuid:"); + } + while(*device_id != '\0' && tmp - ret < UPNP_UUID_LEN) { + copy = FALSE; + tchar = *device_id; + if(tchar >= '0' && tchar <= '9') + copy = TRUE; + if(!copy && tchar >= 'A' && tchar <= 'Z') + copy = TRUE; + if(!copy && tchar >= 'a' && tchar <= 'z') + copy = TRUE; + if(copy) { + *tmp = *device_id; + tmp++; + } + device_id++; + } + *tmp = '\0'; + return ret; +} /** * uPnP Callbacks @@ -135,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) { @@ -154,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"); @@ -161,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); } } @@ -253,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); @@ -265,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; @@ -275,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, 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"); @@ -292,16 +366,18 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) { linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp); ms_mutex_lock(&lupnp->mutex); - - /* Send port binding removes */ - if(lupnp->sip_udp != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE); - } - if(lupnp->sip_tcp != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE); - } - if(lupnp->sip_tls != NULL) { - linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE); + + if(lupnp->lc->network_reachable) { + /* Send port binding removes */ + if(lupnp->sip_udp != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE); + } + if(lupnp->sip_tcp != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE); + } + if(lupnp->sip_tls != NULL) { + linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE); + } } /* Wait all pending bindings are done */ @@ -315,7 +391,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) { upnp_igd_destroy(lupnp->upnp_igd_ctxt); lupnp->upnp_igd_ctxt = NULL; } - + /* No more multi threading here */ /* Run one more time configuration update and proxy */ @@ -343,7 +419,7 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) { lupnp->removing_configs = ms_list_free(lupnp->removing_configs); ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release); lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings); - + ms_mutex_destroy(&lupnp->mutex); ms_cond_destroy(&lupnp->empty_cond); @@ -363,17 +439,17 @@ LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) { bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) { bool_t ready = TRUE; - + // 1 Check global uPnP state ready = (lupnp->state == LinphoneUpnpStateOk); - + // 2 Check external ip address if(ready) { if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) { ready = FALSE; } } - + // 3 Check sip ports bindings if(ready) { if(lupnp->sip_udp != NULL) { @@ -392,7 +468,7 @@ bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) { ready = FALSE; } } - + return ready; } @@ -410,7 +486,7 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { int port = -1; if(lupnp != NULL) { ms_mutex_lock(&lupnp->mutex); - + if(lupnp->sip_udp != NULL) { if(lupnp->sip_udp->state == LinphoneUpnpStateOk) { port = lupnp->sip_udp->external_port; @@ -424,12 +500,55 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { port = lupnp->sip_tls->external_port; } } - + ms_mutex_unlock(&lupnp->mutex); } 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); +} + const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *lupnp) { const char* addr = NULL; if(lupnp != NULL) { @@ -444,7 +563,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind upnp_igd_port_mapping mapping; char description[128]; int ret; - + if(lupnp->state != LinphoneUpnpStateOk) { return -2; } @@ -468,7 +587,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind return 0; } } - + // No retry if specified if(port->retry != 0 && !retry) { return -1; @@ -477,18 +596,18 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind if(port->retry >= UPNP_ADD_MAX_RETRY) { ret = -1; } else { + linphone_upnp_port_binding_set_device_id(port, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); mapping.cookie = linphone_upnp_port_binding_retain(port); lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie); mapping.local_port = port->local_port; mapping.local_host = port->local_addr; if(port->external_port == -1) - mapping.remote_port = rand()%(0xffff - 1024) + 1024; - else - mapping.remote_port = port->external_port; + port->external_port = rand()%(0xffff - 1024) + 1024; + mapping.remote_port = port->external_port; mapping.remote_host = ""; snprintf(description, 128, "%s %s at %s:%d", - LINPHONE_PACKAGE_NAME, + "Linphone", (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP": "UDP", port->local_addr, port->local_port); mapping.description = description; @@ -507,7 +626,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) { upnp_igd_port_mapping mapping; int ret; - + if(lupnp->state != LinphoneUpnpStateOk) { return -2; } @@ -530,7 +649,7 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB return 0; } } - + // No retry if specified if(port->retry != 0 && !retry) { return 1; @@ -539,6 +658,7 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB if(port->retry >= UPNP_REMOVE_MAX_RETRY) { ret = -1; } else { + linphone_upnp_port_binding_set_device_id(port, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); mapping.cookie = linphone_upnp_port_binding_retain(port); lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie); @@ -577,20 +697,20 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool /* * Audio part */ - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY); + linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtp_port:0, UPNP_CALL_RETRY_DELAY); + + linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtcp_port:0, UPNP_CALL_RETRY_DELAY); - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY); - /* * Video part */ - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY); + linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtp_port:0, UPNP_CALL_RETRY_DELAY); - linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY); + linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtcp_port:0, UPNP_CALL_RETRY_DELAY); } ms_mutex_unlock(&lupnp->mutex); @@ -611,7 +731,7 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, int i; const SalStreamDescription *stream; - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { stream = &md->streams[i]; if(stream->type == SalAudio) { audio = TRUE; @@ -636,16 +756,16 @@ void linphone_upnp_update_stream_state(UpnpStream *stream) { if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) && (stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) { stream->state = LinphoneUpnpStateOk; - } else if((stream->rtp != NULL && - (stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) || - (stream->rtcp != NULL && - (stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) { + } else if((stream->rtp != NULL && + (stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) || + (stream->rtcp != NULL && + (stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) { stream->state = LinphoneUpnpStatePending; } else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) || (stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) { stream->state = LinphoneUpnpStateKo; } else { - ms_error("Invalid stream %p state", stream); + ms_error("Invalid stream %p state", stream); } } @@ -679,7 +799,7 @@ int linphone_upnp_call_process(LinphoneCall *call) { * Update stat */ linphone_core_update_upnp_state_in_call_stats(call); - + /* * Update session state */ @@ -700,7 +820,7 @@ int linphone_upnp_call_process(LinphoneCall *call) { } ms_mutex_unlock(&lupnp->mutex); - + /* When change is done proceed update */ if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo && (newState == LinphoneUpnpStateOk || newState == LinphoneUpnpStateKo)) { @@ -714,12 +834,14 @@ int linphone_upnp_call_process(LinphoneCall *call) { linphone_core_start_update_call(lc, call); break; case LinphoneCallUpdatedByRemote: - linphone_core_start_accept_call_update(lc, call); + linphone_core_start_accept_call_update(lc, call,call->prevstate,linphone_call_state_to_string(call->prevstate)); break; case LinphoneCallOutgoingInit: linphone_core_proceed_with_invite_if_ready(lc, call, NULL); break; case LinphoneCallIdle: + linphone_call_update_local_media_description_from_ice_or_upnp(call); + sal_call_set_local_media_description(call->op,call->localdesc); linphone_core_notify_incoming_call(lc, call); break; default: @@ -730,13 +852,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) { @@ -769,7 +902,7 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) { list = list->next; } - list = linphone_upnp_config_list_port_bindings(lupnp->lc->config); + list = linphone_upnp_config_list_port_bindings(lupnp->lc->config, upnp_igd_get_device_id(lupnp->upnp_igd_ctxt)); for(item = list;item != NULL; item = item->next) { port_mapping = (UpnpPortBinding *)item->data; port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping); @@ -808,7 +941,7 @@ void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **por if(*port_mapping == NULL) { *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port); } - + // Get addresses local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt); external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); @@ -841,14 +974,15 @@ void linphone_upnp_update_config(UpnpContext* lupnp) { char key[64]; const MSList *item; UpnpPortBinding *port_mapping; - + /* Add configs */ for(item = lupnp->adding_configs;item!=NULL;item=item->next) { port_mapping = (UpnpPortBinding *)item->data; - snprintf(key, sizeof(key), "%s-%d-%d", + snprintf(key, sizeof(key), "%s-%s-%d-%d", + port_mapping->device_id, (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); + port_mapping->external_port, + port_mapping->local_port); lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP"); linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping); } @@ -858,10 +992,11 @@ void linphone_upnp_update_config(UpnpContext* lupnp) { /* Remove configs */ for(item = lupnp->removing_configs;item!=NULL;item=item->next) { port_mapping = (UpnpPortBinding *)item->data; - snprintf(key, sizeof(key), "%s-%d-%d", + snprintf(key, sizeof(key), "%s-%s-%d-%d", + port_mapping->device_id, (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", - port_mapping->external_port, - port_mapping->local_port); + port_mapping->external_port, + port_mapping->local_port); lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL); linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping); } @@ -873,7 +1008,7 @@ void linphone_upnp_update_proxy(UpnpContext* lupnp, bool_t force) { LinphoneUpnpState ready_state; const MSList *item; time_t now = (force)? (lupnp->last_ready_check + UPNP_CORE_READY_CHECK) : time(NULL); - + /* Refresh registers if we are ready */ if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) { lupnp->last_ready_check = now; @@ -913,7 +1048,7 @@ bool_t linphone_core_upnp_hook(void *data) { linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY); } - linphone_upnp_update_proxy(lupnp, FALSE); + linphone_upnp_update_proxy(lupnp, FALSE); linphone_upnp_update_config(lupnp); ms_mutex_unlock(&lupnp->mutex); @@ -925,8 +1060,9 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * SalStreamDescription *stream; UpnpStream *upnpStream; - for (i = 0; i < desc->n_active_streams; i++) { + for (i = 0; i < desc->nb_streams; i++) { stream = &desc->streams[i]; + if (!sal_stream_description_active(stream)) continue; upnpStream = NULL; if(stream->type == SalAudio) { upnpStream = session->audio; @@ -957,7 +1093,8 @@ UpnpPortBinding *linphone_upnp_port_binding_new() { port = ms_new0(UpnpPortBinding,1); ms_mutex_init(&port->mutex, NULL); port->state = LinphoneUpnpStateIdle; - port->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + port->protocol = UPNP_IGD_IP_PROTOCOL_UDP; + port->device_id = NULL; port->local_addr[0] = '\0'; port->local_port = -1; port->external_addr[0] = '\0'; @@ -980,24 +1117,46 @@ UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_prot UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) { UpnpPortBinding *tmp_binding; UpnpPortBinding *end_binding; - end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, external_port); + + // Seek an binding with same protocol and local port + end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, -1); tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding); - if(tmp_binding != NULL) { + + // Must be not attached to any struct + if(tmp_binding != NULL && tmp_binding->ref == 1) { linphone_upnp_port_binding_release(end_binding); - end_binding = tmp_binding; + end_binding = linphone_upnp_port_binding_retain(tmp_binding); + } else { + end_binding->external_port = external_port; } - return end_binding; -} + return end_binding; +} UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) { UpnpPortBinding *new_port = NULL; new_port = ms_new0(UpnpPortBinding,1); memcpy(new_port, port, sizeof(UpnpPortBinding)); + new_port->device_id = NULL; + linphone_upnp_port_binding_set_device_id(new_port, port->device_id); ms_mutex_init(&new_port->mutex, NULL); new_port->ref = 1; return new_port; } +void linphone_upnp_port_binding_set_device_id(UpnpPortBinding *port, const char *device_id) { + char *formated_device_id = linphone_upnp_format_device_id(device_id); + if(formated_device_id != NULL && port->device_id != NULL) { + if(strcmp(formated_device_id, port->device_id) == 0) { + ms_free(formated_device_id); + return; + } + } + if(port->device_id != NULL) { + ms_free(port->device_id); + } + port->device_id = formated_device_id; +} + void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port) { if(strlen(port->local_addr)) { ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d (retry %d)", msg, @@ -1015,10 +1174,11 @@ void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBi } } +// Return true if the binding are equivalent. (Note external_port == -1 means "don't care") bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) { return port1->protocol == port2->protocol && - port1->local_port == port2->local_port && - port1->external_port == port2->external_port; + port1->local_port == port2->local_port && + (port1->external_port == -1 || port2->external_port == -1 || port1->external_port == port2->external_port); } UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port) { @@ -1044,6 +1204,9 @@ UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port) { void linphone_upnp_port_binding_release(UpnpPortBinding *port) { ms_mutex_lock(&port->mutex); if(--port->ref == 0) { + if(port->device_id != NULL) { + ms_free(port->device_id); + } ms_mutex_unlock(&port->mutex); ms_mutex_destroy(&port->mutex); ms_free(port); @@ -1060,7 +1223,7 @@ void linphone_upnp_port_binding_release(UpnpPortBinding *port) { UpnpStream* linphone_upnp_stream_new() { UpnpStream *stream = ms_new0(UpnpStream,1); stream->state = LinphoneUpnpStateIdle; - stream->rtp = NULL; + stream->rtp = NULL; stream->rtcp = NULL; return stream; } @@ -1110,6 +1273,9 @@ void linphone_upnp_session_destroy(UpnpSession *session) { } } + session->call->stats[LINPHONE_CALL_STATS_AUDIO].upnp_state = LinphoneUpnpStateKo; + session->call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = LinphoneUpnpStateKo; + linphone_upnp_stream_destroy(session->audio); linphone_upnp_stream_destroy(session->video); ms_free(session); @@ -1127,25 +1293,35 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) { struct linphone_upnp_config_list_port_bindings_struct { struct _LpConfig *lpc; MSList *retList; + const char *device_id; }; static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct linphone_upnp_config_list_port_bindings_struct *cookie) { + char device_id[UPNP_UUID_LEN + 1]; char protocol_str[4]; // TCP or UDP upnp_igd_ip_protocol protocol; int external_port; int local_port; + int ret; bool_t valid = TRUE; UpnpPortBinding *port; - if(sscanf(entry, "%3s-%i-%i", protocol_str, &external_port, &local_port) == 3) { - if(strcasecmp(protocol_str, "TCP") == 0) { + + ret = sscanf(entry, "%"UPNP_UUID_LEN_STR"[^-]-%3s-%i-%i", device_id, protocol_str, &external_port, &local_port); + if(ret == 4) { + // Handle only wanted device bindings + if(device_id != NULL && strcmp(cookie->device_id, device_id) != 0) { + return; + } + if(linphone_upnp_strncmpi(protocol_str, "TCP", 3) == 0) { protocol = UPNP_IGD_IP_PROTOCOL_TCP; - } else if(strcasecmp(protocol_str, "UDP") == 0) { + } else if(linphone_upnp_strncmpi(protocol_str, "UDP", 3) == 0) { protocol = UPNP_IGD_IP_PROTOCOL_UDP; } else { valid = FALSE; } if(valid) { port = linphone_upnp_port_binding_new(); + linphone_upnp_port_binding_set_device_id(port, device_id); port->state = LinphoneUpnpStateOk; port->protocol = protocol; port->external_port = external_port; @@ -1160,9 +1336,11 @@ static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct } } -MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc) { - struct linphone_upnp_config_list_port_bindings_struct cookie = {lpc, NULL}; +MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc, const char *device_id) { + char *formated_device_id = linphone_upnp_format_device_id(device_id); + struct linphone_upnp_config_list_port_bindings_struct cookie = {lpc, NULL, formated_device_id}; lp_config_for_each_entry(lpc, UPNP_SECTION_NAME, (void(*)(const char *, void*))linphone_upnp_config_list_port_bindings_cb, &cookie); + ms_free(formated_device_id); return cookie.retList; } @@ -1170,6 +1348,11 @@ void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBin MSList *list; UpnpPortBinding *list_port; + if(port->device_id == NULL) { + ms_error("Can't remove port binding without device_id"); + return; + } + list = lupnp->removing_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; @@ -1198,6 +1381,11 @@ void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPort MSList *list; UpnpPortBinding *list_port; + if(port->device_id == NULL) { + ms_error("Can't remove port binding without device_id"); + return; + } + list = lupnp->adding_configs; while(list != NULL) { list_port = (UpnpPortBinding *)list->data; diff --git a/coreapi/upnp.h b/coreapi/upnp.h index 81edc5986..2239c896c 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -38,6 +38,7 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session); UpnpContext *linphone_upnp_context_new(LinphoneCore *lc); void linphone_upnp_context_destroy(UpnpContext *ctx); +void linphone_upnp_refresh(UpnpContext *ctx); LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx); const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx); int linphone_upnp_context_get_external_port(UpnpContext *ctx); diff --git a/coreapi/vtables.c b/coreapi/vtables.c new file mode 100644 index 000000000..3a5672509 --- /dev/null +++ b/coreapi/vtables.c @@ -0,0 +1,266 @@ +/* +linphone +Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) +Copyright (C) 2010 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" + + +LinphoneCoreVTable *linphone_core_v_table_new() { + return ms_new0(LinphoneCoreVTable,1); +} + +void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data) { + table->user_data = data; +} + +void* linphone_core_v_table_get_user_data(LinphoneCoreVTable *table) { + return table->user_data; +} + +void linphone_core_v_table_destroy(LinphoneCoreVTable* table) { + ms_free(table); +} + +LinphoneCoreVTable *linphone_core_get_current_vtable(LinphoneCore *lc) { + return lc->current_vtable; +} + +static void cleanup_dead_vtable_refs(LinphoneCore *lc){ + MSList *it,*next_it; + for(it=lc->vtable_refs; it!=NULL; ){ + VTableReference *ref=(VTableReference*)it->data; + next_it=it->next; + if (ref->valid==0){ + ref->valid=0; + lc->vtable_refs=ms_list_remove_link(lc->vtable_refs, it); + ms_free(ref); + } + it=next_it; + } +} + +#define NOTIFY_IF_EXIST(function_name) \ + MSList* iterator; \ + VTableReference *ref; \ + ms_message("Linphone core [%p] notifying [%s]",lc,#function_name);\ + for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next) \ + if ((ref=(VTableReference*)iterator->data)->valid && (lc->current_vtable=ref->vtable)->function_name)\ + lc->current_vtable->function_name + +void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) { + NOTIFY_IF_EXIST(global_state_changed)(lc,gstate,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message){ + NOTIFY_IF_EXIST(call_state_changed)(lc,call,cstate,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) { + NOTIFY_IF_EXIST(call_encryption_changed)(lc,call,on,authentication_token); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + NOTIFY_IF_EXIST(registration_state_changed)(lc,cfg,cstate,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_show_interface(LinphoneCore *lc){ + NOTIFY_IF_EXIST(show)(lc); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_display_status(LinphoneCore *lc, const char *message) { + NOTIFY_IF_EXIST(display_status)(lc,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_display_message(LinphoneCore *lc, const char *message){ + NOTIFY_IF_EXIST(display_message)(lc,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message){ + NOTIFY_IF_EXIST(display_warning)(lc,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url){ + NOTIFY_IF_EXIST(display_url)(lc,message,url); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf){ + NOTIFY_IF_EXIST(notify_presence_received)(lc,lf); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + NOTIFY_IF_EXIST(new_subscription_requested)(lc,lf,url); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ + NOTIFY_IF_EXIST(auth_info_requested)(lc,realm,username,domain); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl){ + NOTIFY_IF_EXIST(call_log_updated)(lc,newcl); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){ + NOTIFY_IF_EXIST(text_received)(lc,room,from,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message){ + NOTIFY_IF_EXIST(message_received)(lc,room,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) { + NOTIFY_IF_EXIST(file_transfer_recv)(lc,message,content,buff,size); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size) { + NOTIFY_IF_EXIST(file_transfer_send)(lc,message,content,buff,size); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { + NOTIFY_IF_EXIST(file_transfer_progress_indication)(lc,message,content,offset,total); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + NOTIFY_IF_EXIST(is_composing_received)(lc,room); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_dtmf_received(LinphoneCore* lc, LinphoneCall *call, int dtmf) { + NOTIFY_IF_EXIST(dtmf_received)(lc,call,dtmf); + cleanup_dead_vtable_refs(lc); +} + +bool_t linphone_core_dtmf_received_has_listener(const LinphoneCore* lc) { + MSList* iterator; + for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next){ + VTableReference *ref=(VTableReference*)iterator->data; + if (ref->valid && ref->vtable->dtmf_received) + return TRUE; + } + return FALSE; +} + +void linphone_core_notify_refer_received(LinphoneCore *lc, const char *refer_to) { + NOTIFY_IF_EXIST(refer_received)(lc,refer_to); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf) { + NOTIFY_IF_EXIST(buddy_info_updated)(lc,lf); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { + NOTIFY_IF_EXIST(transfer_state_changed)(lc,transfered,new_call_state); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats) { + NOTIFY_IF_EXIST(call_stats_updated)(lc,call,stats); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_info_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg) { + NOTIFY_IF_EXIST(info_received)(lc,call,msg); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + NOTIFY_IF_EXIST(configuring_status)(lc,status,message); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable) { + NOTIFY_IF_EXIST(network_reachable)(lc,reachable); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) { + NOTIFY_IF_EXIST(notify_received)(lc,lev,notified_event,body); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { + NOTIFY_IF_EXIST(subscription_state_changed)(lc,lev,state); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) { + NOTIFY_IF_EXIST(publish_state_changed)(lc,lev,state); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_log_collection_upload_state_changed(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) { + NOTIFY_IF_EXIST(log_collection_upload_state_changed)(lc, state, info); + cleanup_dead_vtable_refs(lc); +} + +void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset, size_t total) { + NOTIFY_IF_EXIST(log_collection_upload_progress_indication)(lc, offset, total); + cleanup_dead_vtable_refs(lc); +} + +static VTableReference * v_table_reference_new(LinphoneCoreVTable *vtable, bool_t autorelease){ + VTableReference *ref=ms_new0(VTableReference,1); + ref->valid=1; + ref->autorelease=autorelease; + ref->vtable=vtable; + return ref; +} + +void v_table_reference_destroy(VTableReference *ref){ + if (ref->autorelease) linphone_core_v_table_destroy(ref->vtable); + ms_free(ref); +} + +void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease) { + ms_message("Vtable [%p] registered on core [%p]",lc,vtable); + lc->vtable_refs=ms_list_append(lc->vtable_refs,v_table_reference_new(vtable, autorelease)); +} + +void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable){ + _linphone_core_add_listener(lc, vtable, FALSE); +} + +void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *vtable) { + MSList *it; + ms_message("Vtable [%p] unregistered on core [%p]",lc,vtable); + for(it=lc->vtable_refs; it!=NULL; it=it->next){ + VTableReference *ref=(VTableReference*)it->data; + if (ref->vtable==vtable) + ref->valid=0; + } +} diff --git a/coreapi/xml.c b/coreapi/xml.c new file mode 100644 index 000000000..b4b994174 --- /dev/null +++ b/coreapi/xml.c @@ -0,0 +1,98 @@ +/* +linphone +Copyright (C) 2010-2013 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "private.h" + +#include +#include +#include +#include + + +xmlparsing_context_t * linphone_xmlparsing_context_new(void) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); + if (xmlCtx != NULL) { + xmlCtx->doc = NULL; + xmlCtx->xpath_ctx = NULL; + xmlCtx->errorBuffer[0] = '\0'; + xmlCtx->warningBuffer[0] = '\0'; + } + return xmlCtx; +} + +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx) { + if (ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + if (ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(ctx->xpath_ctx); + ctx->xpath_ctx = NULL; + } + free(ctx); +} + +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); + va_end(args); +} + +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { + if (xml_ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(xml_ctx->xpath_ctx); + } + xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); + if (xml_ctx->xpath_ctx == NULL) return -1; + return 0; +} + +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + xmlXPathObjectPtr xpath_obj; + xmlChar *text = NULL; + int i; + + xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); + if (xpath_obj != NULL) { + if (xpath_obj->nodesetval != NULL) { + xmlNodeSetPtr nodes = xpath_obj->nodesetval; + for (i = 0; i < nodes->nodeNr; i++) { + xmlNodePtr node = nodes->nodeTab[i]; + if (node->children != NULL) { + text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); + } + } + } + xmlXPathFreeObject(xpath_obj); + } + + return (char *)text; +} + +void linphone_free_xml_text_content(const char *text) { + xmlFree((xmlChar *)text); +} + +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); +} diff --git a/tools/xml2lpc.c b/coreapi/xml2lpc.c similarity index 86% rename from tools/xml2lpc.c rename to coreapi/xml2lpc.c index c9a5c94e2..57380bcd2 100644 --- a/tools/xml2lpc.c +++ b/coreapi/xml2lpc.c @@ -29,7 +29,7 @@ struct _xml2lpc_context { LpConfig *lpc; xml2lpc_function cbf; void *ctx; - + xmlDoc *doc; xmlDoc *xsd; char errorBuffer[XML2LPC_BZ]; @@ -43,7 +43,7 @@ xml2lpc_context* xml2lpc_context_new(xml2lpc_function cbf, void *ctx) { xmlCtx->lpc = NULL; xmlCtx->cbf = cbf; xmlCtx->ctx = ctx; - + xmlCtx->doc = NULL; xmlCtx->xsd = NULL; xmlCtx->errorBuffer[0]='\0'; @@ -70,19 +70,19 @@ static void xml2lpc_context_clear_logs(xml2lpc_context *ctx) { } static void xml2lpc_log(xml2lpc_context *xmlCtx, int level, const char *fmt, ...) { - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); if(xmlCtx->cbf != NULL) { xmlCtx->cbf((xmlCtx)->ctx, level, fmt, args); } - va_end(args); + va_end(args); } static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; int sl = strlen(xmlCtx->errorBuffer); - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); vsnprintf(xmlCtx->errorBuffer + sl, XML2LPC_BZ-sl, fmt, args); va_end(args); } @@ -90,39 +90,42 @@ static void xml2lpc_genericxml_error(void *ctx, const char *fmt, ...) { static void xml2lpc_genericxml_warning(void *ctx, const char *fmt, ...) { xml2lpc_context *xmlCtx = (xml2lpc_context *)ctx; int sl = strlen(xmlCtx->warningBuffer); - va_list args; - va_start(args, fmt); + va_list args; + va_start(args, fmt); vsnprintf(xmlCtx->warningBuffer + sl, XML2LPC_BZ-sl, fmt, args); va_end(args); } #if 0 static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) { - xmlNode *cur_node = NULL; + xmlNode *cur_node = NULL; - for (cur_node = a_node; cur_node; cur_node = cur_node->next) { - if (cur_node->type == XML_ELEMENT_NODE) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name); - } else { - xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name); - } + for (cur_node = a_node; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: Element, name: %s", level, cur_node->name); + } else { + xml2lpc_log(ctx, XML2LPC_DEBUG, "node level: %d type: %d, name: %s", level, cur_node->type, cur_node->name); + } - dumpNodes(level + 1, cur_node->children, ctx); - } + dumpNodes(level + 1, cur_node->children, ctx); + } } #endif 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); @@ -156,7 +162,7 @@ static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_co } else { xml2lpc_log(ctx, XML2LPC_WARNING, "ignored entry with no \"name\" attribute line:%d",xmlGetLineNo((xmlNode*)element)); } - return 0; + return 0; } static int processSection(xmlElement *element, xml2lpc_context *ctx) { @@ -179,13 +185,13 @@ static int processSection(xmlElement *element, xml2lpc_context *ctx) { processEntry((xmlElement*)cur_node, name, ctx); } } - - } - } else { - xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element)); - } - return 0; + } + } else { + xml2lpc_log(ctx, XML2LPC_WARNING, "ignored section with no \"name\" attribute, line:%d", xmlGetLineNo((xmlNode*)element)); + } + + return 0; } static int processConfig(xmlElement *element, xml2lpc_context *ctx) { @@ -193,19 +199,19 @@ static int processConfig(xmlElement *element, xml2lpc_context *ctx) { for (cur_node = element->children; cur_node; cur_node = cur_node->next) { dumpNode(cur_node, ctx); - if (cur_node->type == XML_ELEMENT_NODE && + if (cur_node->type == XML_ELEMENT_NODE && strcmp((const char*)cur_node->name, "section") == 0 ) { processSection((xmlElement*)cur_node, ctx); - } - - } + } + + } return 0; } static int processDoc(xmlNode *node, xml2lpc_context *ctx) { dumpNode(node, ctx); - - if (node->type == XML_ELEMENT_NODE && + + if (node->type == XML_ELEMENT_NODE && strcmp((const char*)node->name, "config") == 0 ) { processConfig((xmlElement*)node, ctx); } else { @@ -215,21 +221,27 @@ static int processDoc(xmlNode *node, xml2lpc_context *ctx) { } static int internal_convert_xml2lpc(xml2lpc_context *ctx) { + xmlNode *rootNode; + int ret; + xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started"); - xmlNode *rootNode = xmlDocGetRootElement(ctx->doc); + rootNode = xmlDocGetRootElement(ctx->doc); //dumpNodes(0, rootNode, cbf, ctx); - int ret = processDoc(rootNode, ctx); + ret = processDoc(rootNode, ctx); xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret); return ret; } int xml2lpc_validate(xml2lpc_context *xmlCtx) { - xml2lpc_context_clear_logs(xmlCtx); xmlSchemaValidCtxtPtr validCtx; - xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd); + xmlSchemaParserCtxtPtr parserCtx; + int ret; + + xml2lpc_context_clear_logs(xmlCtx); + parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd); validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx)); xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx); - int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); + ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); if(ret > 0) { if(strlen(xmlCtx->warningBuffer) > 0) xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer); diff --git a/tools/xml2lpc.h b/coreapi/xml2lpc.h similarity index 100% rename from tools/xml2lpc.h rename to coreapi/xml2lpc.h diff --git a/coreapi/xmlrpc.c b/coreapi/xmlrpc.c new file mode 100644 index 000000000..c91ebfa4c --- /dev/null +++ b/coreapi/xmlrpc.c @@ -0,0 +1,420 @@ +/* +linphone +Copyright (C) 2010-2015 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "private.h" + +#include +#include +#include + + + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcRequestCbs); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcRequestCbs, belle_sip_object_t, + NULL, // destroy + NULL, // clone + NULL, // marshal + FALSE +); + +static LinphoneXmlRpcRequestCbs * linphone_xml_rpc_request_cbs_new(void) { + return belle_sip_object_new(LinphoneXmlRpcRequestCbs); +} + +LinphoneXmlRpcRequestCbs * linphone_xml_rpc_request_cbs_ref(LinphoneXmlRpcRequestCbs *cbs) { + belle_sip_object_ref(cbs); + return cbs; +} + +void linphone_xml_rpc_request_cbs_unref(LinphoneXmlRpcRequestCbs *cbs) { + belle_sip_object_unref(cbs); +} + +void *linphone_xml_rpc_request_cbs_get_user_data(const LinphoneXmlRpcRequestCbs *cbs) { + return cbs->user_data; +} + +void linphone_xml_rpc_request_cbs_set_user_data(LinphoneXmlRpcRequestCbs *cbs, void *ud) { + cbs->user_data = ud; +} + +LinphoneXmlRpcRequestCbsResponseCb linphone_xml_rpc_request_cbs_get_response(const LinphoneXmlRpcRequestCbs *cbs) { + return cbs->response; +} + +void linphone_xml_rpc_request_cbs_set_response(LinphoneXmlRpcRequestCbs *cbs, LinphoneXmlRpcRequestCbsResponseCb cb) { + cbs->response = cb; +} + + +static void format_request(LinphoneXmlRpcRequest *request) { + char si[64]; + belle_sip_list_t *arg_ptr = request->arg_list; + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + + if (request->content != NULL) { + belle_sip_free(request->content); + request->content = NULL; + } + + 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 = xmlTextWriterStartElement(writer, (const xmlChar *)"methodCall"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"methodName", (const xmlChar *)request->method); + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"params"); + } + while (arg_ptr != NULL) { + LinphoneXmlRpcArg *arg = (LinphoneXmlRpcArg *)arg_ptr->data; + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"param"); + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"value"); + } + switch (arg->type) { + case LinphoneXmlRpcArgNone: + break; + case LinphoneXmlRpcArgInt: + memset(si, 0, sizeof(si)); + snprintf(si, sizeof(si), "%i", arg->data.i); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"int", (const xmlChar *)si); + break; + case LinphoneXmlRpcArgString: + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"string", (const xmlChar *)arg->data.s); + break; + } + if (err >= 0) { + /* Close the "value" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + /* Close the "param" element. */ + err = xmlTextWriterEndElement(writer); + } + arg_ptr = arg_ptr->next; + } + if (err >= 0) { + /* Close the "params" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + /* Close the "methodCall" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + request->content = belle_sip_strdup((const char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); +} + +static void free_arg(LinphoneXmlRpcArg *arg) { + if ((arg->type == LinphoneXmlRpcArgString) && (arg->data.s != NULL)) { + belle_sip_free(arg->data.s); + } + belle_sip_free(arg); +} + +static void process_io_error_from_post_xml_rpc_request(void *data, const belle_sip_io_error_event_t *event) { + LinphoneXmlRpcRequest *request = (LinphoneXmlRpcRequest *)data; + ms_error("I/O Error during XML-RPC request sending"); + request->status = LinphoneXmlRpcStatusFailed; + if (request->callbacks->response != NULL) { + request->callbacks->response(request); + } + linphone_xml_rpc_request_unref(request); +} + +static void process_auth_requested_from_post_xml_rpc_request(void *data, belle_sip_auth_event_t *event) { + LinphoneXmlRpcRequest *request = (LinphoneXmlRpcRequest *)data; + ms_error("Authentication error during XML-RPC request sending"); + request->status = LinphoneXmlRpcStatusFailed; + if (request->callbacks->response != NULL) { + request->callbacks->response(request); + } + linphone_xml_rpc_request_unref(request); +} + +static void parse_valid_xml_rpc_response(LinphoneXmlRpcRequest *request, const char *response_body) { + xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); + request->status = LinphoneXmlRpcStatusFailed; + xml_ctx->doc = xmlReadDoc((const unsigned char*)response_body, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + const char *response_str = NULL; + if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end; + switch (request->response.type) { + case LinphoneXmlRpcArgInt: + response_str = linphone_get_xml_text_content(xml_ctx, "/methodResponse/params/param/value/int"); + if (response_str != NULL) { + request->response.data.i = atoi(response_str); + request->status = LinphoneXmlRpcStatusOk; + } + break; + case LinphoneXmlRpcArgString: + response_str = linphone_get_xml_text_content(xml_ctx, "/methodResponse/params/param/value/string"); + if (response_str != NULL) { + request->response.data.s = belle_sip_strdup(response_str); + request->status = LinphoneXmlRpcStatusOk; + } + break; + default: + break; + } + if (response_str) linphone_free_xml_text_content(response_str); + } else { + ms_warning("Wrongly formatted XML-RPC response: %s", xml_ctx->errorBuffer); + } +end: + linphone_xmlparsing_context_destroy(xml_ctx); + if (request->callbacks->response != NULL) { + request->callbacks->response(request); + } +} + +static void notify_xml_rpc_error(LinphoneXmlRpcRequest *request) { + request->status = LinphoneXmlRpcStatusOk; + if (request->callbacks->response != NULL) { + request->callbacks->response(request); + } +} + +static void process_response_from_post_xml_rpc_request(void *data, const belle_http_response_event_t *event) { + LinphoneXmlRpcRequest *request = (LinphoneXmlRpcRequest *)data; + + /* Check the answer code */ + if (event->response) { + int code = belle_http_response_get_status_code(event->response); + if (code == 200) { /* Valid response from the server. */ + parse_valid_xml_rpc_response(request, belle_sip_message_get_body((belle_sip_message_t *)event->response)); + } else { + notify_xml_rpc_error(request); + } + } + linphone_xml_rpc_request_unref(request); +} + + +static LinphoneXmlRpcRequest * _linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type) { + LinphoneXmlRpcRequest *request = belle_sip_object_new(LinphoneXmlRpcRequest); + request->callbacks = linphone_xml_rpc_request_cbs_new(); + request->status = LinphoneXmlRpcStatusPending; + request->response.type = return_type; + request->method = belle_sip_strdup(method); + return request; +} + +static void _linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value) { + LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); + arg->type = LinphoneXmlRpcArgInt; + arg->data.i = value; + request->arg_list = belle_sip_list_append(request->arg_list, arg); +} + +static void _linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value) { + LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); + arg->type = LinphoneXmlRpcArgString; + arg->data.s = belle_sip_strdup(value); + request->arg_list = belle_sip_list_append(request->arg_list, arg); +} + +static void _linphone_xml_rpc_request_destroy(LinphoneXmlRpcRequest *request) { + belle_sip_list_free_with_data(request->arg_list, (void (*)(void*))free_arg); + if ((request->response.type == LinphoneXmlRpcArgString) && (request->response.data.s != NULL)) { + belle_sip_free(request->response.data.s); + } + if (request->content) belle_sip_free(request->content); + belle_sip_free(request->method); + linphone_xml_rpc_request_cbs_unref(request->callbacks); +} + +static void _linphone_xml_rpc_session_destroy(LinphoneXmlRpcSession *session) { + belle_sip_free(session->url); +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcRequest); +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneXmlRpcSession); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcRequest, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_xml_rpc_request_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneXmlRpcSession, belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_xml_rpc_session_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + + +LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type) { + LinphoneXmlRpcRequest *request = _linphone_xml_rpc_request_new(method, return_type); + format_request(request); + return request; +} + +LinphoneXmlRpcRequest * linphone_xml_rpc_request_new_with_args(const char *method, LinphoneXmlRpcArgType return_type, ...) { + bool_t cont = TRUE; + va_list args; + LinphoneXmlRpcArgType arg_type; + LinphoneXmlRpcRequest *request = _linphone_xml_rpc_request_new(method, return_type); + va_start(args, return_type); + while (cont) { + arg_type = va_arg(args, LinphoneXmlRpcArgType); + switch (arg_type) { + case LinphoneXmlRpcArgNone: + cont = FALSE; + break; + case LinphoneXmlRpcArgInt: + _linphone_xml_rpc_request_add_int_arg(request, va_arg(args, int)); + break; + case LinphoneXmlRpcArgString: + _linphone_xml_rpc_request_add_string_arg(request, va_arg(args, char *)); + break; + } + } + va_end(args); + format_request(request); + return request; +} + +LinphoneXmlRpcRequest * linphone_xml_rpc_request_ref(LinphoneXmlRpcRequest *request) { + belle_sip_object_ref(request); + return request; +} + +void linphone_xml_rpc_request_unref(LinphoneXmlRpcRequest *request) { + belle_sip_object_unref(request); +} + +void *linphone_xml_rpc_request_get_user_data(const LinphoneXmlRpcRequest *request) { + return request->user_data; +} + +void linphone_xml_rpc_request_set_user_data(LinphoneXmlRpcRequest *request, void *ud) { + request->user_data = ud; +} + +void linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value) { + _linphone_xml_rpc_request_add_int_arg(request, value); + format_request(request); +} + +void linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value) { + _linphone_xml_rpc_request_add_string_arg(request, value); + format_request(request); +} + +LinphoneXmlRpcRequestCbs * linphone_xml_rpc_request_get_callbacks(const LinphoneXmlRpcRequest *request) { + return request->callbacks; +} + +const char * linphone_xml_rpc_request_get_content(const LinphoneXmlRpcRequest *request) { + return request->content; +} + +LinphoneXmlRpcStatus linphone_xml_rpc_request_get_status(const LinphoneXmlRpcRequest *request) { + return request->status; +} + +int linphone_xml_rpc_request_get_int_response(const LinphoneXmlRpcRequest *request) { + return request->response.data.i; +} + +const char * linphone_xml_rpc_request_get_string_response(const LinphoneXmlRpcRequest *request) { + return request->response.data.s; +} + + +LinphoneXmlRpcSession * linphone_xml_rpc_session_new(LinphoneCore *core, const char *url) { + LinphoneXmlRpcSession *session = belle_sip_object_new(LinphoneXmlRpcSession); + session->core = core; + session->url = belle_sip_strdup(url); + return session; +} + +LinphoneXmlRpcSession * linphone_xml_rpc_session_ref(LinphoneXmlRpcSession *session) { + belle_sip_object_ref(session); + return session; +} + +void linphone_xml_rpc_session_unref(LinphoneXmlRpcSession *session) { + belle_sip_object_unref(session); +} + +void *linphone_xml_rpc_session_get_user_data(const LinphoneXmlRpcSession *session) { + return session->user_data; +} + +void linphone_xml_rpc_session_set_user_data(LinphoneXmlRpcSession *session, void *ud) { + session->user_data = ud; +} + +void linphone_xml_rpc_session_send_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcRequest *request) { + belle_http_request_listener_callbacks_t cbs = { 0 }; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + belle_sip_memory_body_handler_t *bh; + const char *data; + LinphoneContent *content; + + linphone_xml_rpc_request_ref(request); + content = linphone_content_new(); + linphone_content_set_type(content, "text"); + linphone_content_set_subtype(content, "xml"); + linphone_content_set_string_buffer(content, linphone_xml_rpc_request_get_content(request)); + uri = belle_generic_uri_parse(session->url); + req = belle_http_request_create("POST", uri, belle_sip_header_content_type_create("text", "xml"), NULL); + data = linphone_xml_rpc_request_get_content(request); + bh = belle_sip_memory_body_handler_new_copy_from_buffer(data, strlen(data), NULL, NULL); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh)); + cbs.process_response = process_response_from_post_xml_rpc_request; + cbs.process_io_error = process_io_error_from_post_xml_rpc_request; + cbs.process_auth_requested = process_auth_requested_from_post_xml_rpc_request; + l = belle_http_request_listener_create_from_callbacks(&cbs, request); + belle_http_provider_send_request(session->core->http_provider, req, l); + linphone_content_unref(content); +} diff --git a/coreapi/xmlrpc.h b/coreapi/xmlrpc.h new file mode 100644 index 000000000..b985359c5 --- /dev/null +++ b/coreapi/xmlrpc.h @@ -0,0 +1,260 @@ +/* +xmlrpc.h +Copyright (C) 2010-2015 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 LINPHONE_XMLRPC_H_ +#define LINPHONE_XMLRPC_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup misc + * @{ + */ + +/** +* Enum describing the types of argument for LinphoneXmlRpcRequest. +**/ +typedef enum _LinphoneXmlRpcArgType { + LinphoneXmlRpcArgNone, + LinphoneXmlRpcArgInt, + LinphoneXmlRpcArgString +} LinphoneXmlRpcArgType; + +/** +* Enum describing the status of a LinphoneXmlRpcRequest. +**/ +typedef enum _LinphoneXmlRpcStatus { + LinphoneXmlRpcStatusPending, + LinphoneXmlRpcStatusOk, + LinphoneXmlRpcStatusFailed +} LinphoneXmlRpcStatus; + +/** + * The LinphoneXmlRpcRequest object representing a XML-RPC request to be sent. +**/ +typedef struct _LinphoneXmlRpcRequest LinphoneXmlRpcRequest; + +/** + * An object to handle the callbacks for handling the LinphoneXmlRpcRequest operations. +**/ +typedef struct _LinphoneXmlRpcRequestCbs LinphoneXmlRpcRequestCbs; + +/** + * The LinphoneXmlRpcSession object used to send XML-RPC requests and handle their responses. +**/ +typedef struct _LinphoneXmlRpcSession LinphoneXmlRpcSession; + +/** + * Callback used to notify the response to an XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object +**/ +typedef void (*LinphoneXmlRpcRequestCbsResponseCb)(LinphoneXmlRpcRequest *request); + + +/** + * Create a new LinphoneXmlRpcRequest object. + * @param[in] method The XML-RPC method to call. + * @param[in] return_type The expected XML-RPC response type. + * @return A new LinphoneXmlRpcRequest object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_new(const char *method, LinphoneXmlRpcArgType return_type); + +/** + * Create a new LinphoneXmlRpcRequest object giving the arguments to the method call. + * @param[in] method The XML-RPC method to call. + * @param[in] return_type The expected XML-RPC response type. + * @return A new LinphoneXmlRpcRequest object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_new_with_args(const char *method, LinphoneXmlRpcArgType return_type, ...); + +/** + * Acquire a reference to the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @return The same LinphoneXmlRpcRequest object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequest * linphone_xml_rpc_request_ref(LinphoneXmlRpcRequest *request); + +/** + * Release reference to the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_unref(LinphoneXmlRpcRequest *request); + +/** + * Retrieve the user pointer associated with the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @return The user pointer associated with the XML-RPC request. +**/ +LINPHONE_PUBLIC void *linphone_xml_rpc_request_get_user_data(const LinphoneXmlRpcRequest *request); + +/** + * Assign a user pointer to the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @param[in] ud The user pointer to associate with the XML-RPC request. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_set_user_data(LinphoneXmlRpcRequest *request, void *ud); + +/** + * Add an integer argument to an XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @param[in] value The integer value of the added argument. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value); + +/** + * Add a string argument to an XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @param[in] value The string value of the added argument. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value); + +/** + * Get the LinphoneXmlRpcRequestCbs object associated with a LinphoneXmlRpcRequest. + * @param[in] request LinphoneXmlRpcRequest object + * @return The LinphoneXmlRpcRequestCbs object associated with the LinphoneXmlRpcRequest. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequestCbs * linphone_xml_rpc_request_get_callbacks(const LinphoneXmlRpcRequest *request); + +/** + * Get the content of the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @return The string representation of the content of the XML-RPC request. + */ +LINPHONE_PUBLIC const char * linphone_xml_rpc_request_get_content(const LinphoneXmlRpcRequest *request); + +/** + * Get the status of the XML-RPC request. + * @param[in] request LinphoneXmlRpcRequest object. + * @return The status of the XML-RPC request. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcStatus linphone_xml_rpc_request_get_status(const LinphoneXmlRpcRequest *request); + +/** + * Get the response to an XML-RPC request sent with linphone_xml_rpc_session_send_request() and returning an integer response. + * @param[in] request LinphoneXmlRpcRequest object. + * @return The integer response to the XML-RPC request. +**/ +LINPHONE_PUBLIC int linphone_xml_rpc_request_get_int_response(const LinphoneXmlRpcRequest *request); + +/** +* Get the response to an XML-RPC request sent with linphone_xml_rpc_session_send_request() and returning a string response. +* @param[in] request LinphoneXmlRpcRequest object. +* @return The string response to the XML-RPC request. +**/ +LINPHONE_PUBLIC const char * linphone_xml_rpc_request_get_string_response(const LinphoneXmlRpcRequest *request); + + +/** + * Create a new LinphoneXmlRpcSession object. + * @param[in] core The LinphoneCore object used to send the XML-RPC requests. + * @param[in] url The URL of the XML-RPC server to send the XML-RPC requests to. + * @return A new LinphoneXmlRpcSession object. + */ +LINPHONE_PUBLIC LinphoneXmlRpcSession * linphone_xml_rpc_session_new(LinphoneCore *core, const char *url); + +/** + * Acquire a reference to the XML-RPC session. + * @param[in] session LinphoneXmlRpcSession object. + * @return The same LinphoneXmlRpcSession object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcSession * linphone_xml_rpc_session_ref(LinphoneXmlRpcSession *session); + +/** + * Release reference to the XML-RPC session. + * @param[in] session LinphoneXmlRpcSession object. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_session_unref(LinphoneXmlRpcSession *session); + +/** + * Retrieve the user pointer associated with the XML-RPC session. + * @param[in] session LinphoneXmlRpcSession object. + * @return The user pointer associated with the XML-RPC session. +**/ +LINPHONE_PUBLIC void *linphone_xml_rpc_session_get_user_data(const LinphoneXmlRpcSession *session); + +/** + * Assign a user pointer to the XML-RPC session. + * @param[in] session LinphoneXmlRpcSession object. + * @param[in] ud The user pointer to associate with the XML-RPC session. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_session_set_user_data(LinphoneXmlRpcSession *session, void *ud); + +/** + * Send an XML-RPC request. + * @param[in] session LinphoneXmlRpcSession object. + * @param[in] request The LinphoneXmlRpcRequest to be sent. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_session_send_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcRequest *request); + + +/** + * Acquire a reference to a LinphoneXmlRpcRequestCbs object. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. + * @return The same LinphoneXmlRpcRequestCbs object. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequestCbs * linphone_xml_rpc_request_cbs_ref(LinphoneXmlRpcRequestCbs *cbs); + +/** + * Release a reference to a LinphoneXmlRpcRequestCbs object. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_cbs_unref(LinphoneXmlRpcRequestCbs *cbs); + +/** + * Retrieve the user pointer associated with a LinphoneXmlRpcRequestCbs object. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. + * @return The user pointer associated with the LinphoneXmlRpcRequestCbs object. +**/ +LINPHONE_PUBLIC void *linphone_xml_rpc_request_cbs_get_user_data(const LinphoneXmlRpcRequestCbs *cbs); + +/** + * Assign a user pointer to a LinphoneXmlRpcRequestCbs object. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. + * @param[in] ud The user pointer to associate with the LinphoneXmlRpcRequestCbs object. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_cbs_set_user_data(LinphoneXmlRpcRequestCbs *cbs, void *ud); + +/** + * Get the response callback. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. + * @return The current response callback. +**/ +LINPHONE_PUBLIC LinphoneXmlRpcRequestCbsResponseCb linphone_xml_rpc_request_cbs_get_response(const LinphoneXmlRpcRequestCbs *cbs); + +/** + * Set the response callback. + * @param[in] cbs LinphoneXmlRpcRequestCbs object. + * @param[in] cb The response callback to be used. +**/ +LINPHONE_PUBLIC void linphone_xml_rpc_request_cbs_set_response(LinphoneXmlRpcRequestCbs *cbs, LinphoneXmlRpcRequestCbsResponseCb cb); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONE_XMLRPC_H_ */ diff --git a/gen-gtkfilelist.sh b/gen-gtkfilelist.sh index 4036201ba..095c4979c 100755 --- a/gen-gtkfilelist.sh +++ b/gen-gtkfilelist.sh @@ -7,17 +7,22 @@ echo bin find bin -name *.dll find lib/gtk-2.0 find etc -find share/locale/fr -find share/locale/de -find share/locale/sv find share/locale/cs +find share/locale/de find share/locale/es +find share/locale/fr +find share/locale/he find share/locale/hu find share/locale/it find share/locale/ja +find share/locale/nb find share/locale/nl find share/locale/pl -find share/locale/ru +find share/locale/pt find share/locale/pt_BR +find share/locale/ru +find share/locale/sr +find share/locale/sv +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..f893fafa0 --- /dev/null +++ b/gtk+-2.24.8.filelist @@ -0,0 +1,213 @@ +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/ar/LC_MESSAGES/atk10.mo +share/locale/ar/LC_MESSAGES/gdk-pixbuf.mo +share/locale/ar/LC_MESSAGES/glib20.mo +share/locale/ar/LC_MESSAGES/gtk20-properties.mo +share/locale/ar/LC_MESSAGES/gtk20.mo +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/tr/LC_MESSAGES/atk10.mo +share/locale/tr/LC_MESSAGES/gdk-pixbuf.mo +share/locale/tr/LC_MESSAGES/gettext-runtime.mo +share/locale/tr/LC_MESSAGES/glib20.mo +share/locale/tr/LC_MESSAGES/gtk20-properties.mo +share/locale/tr/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/.directory b/gtk/.directory new file mode 100644 index 000000000..40f7ba528 --- /dev/null +++ b/gtk/.directory @@ -0,0 +1,4 @@ +[Dolphin] +Timestamp=2015,8,9,21,25,40 +Version=3 +ViewMode=2 diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt new file mode 100644 index 000000000..5bd36140d --- /dev/null +++ b/gtk/CMakeLists.txt @@ -0,0 +1,114 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +set(UI_FILES + about.ui + audio_assistant.ui + buddylookup.ui + call_logs.ui + call_statistics.ui + config-uri.ui + contact.ui + dscp_settings.ui + keypad.ui + ldap.ui + log.ui + main.ui + parameters.ui + password.ui + provisioning-fetch.ui + sip_account.ui + tunnel_config.ui + waiting.ui + chatroom_frame.ui + in_call_frame.ui + conf_frame.ui + callee_frame.ui + login_frame.ui +) + +set(PIXMAPS stock_people.png) +set(LICENSE ../COPYING) + +set(SOURCE_FILES + audio_assistant.c + buddylookup.c + calllogs.c + chat.c + conference.c + config-fetching.c + friendlist.c + incall_view.c + logging.c + loginframe.c + main.c + propertybox.c + singleinstance.c + status_icon.c + status_notifier.c + support.c + update.c + utils.c + videowindow.c +) +if(ENABLE_ASSISTANT) + list(APPEND SOURCE_FILES setupwizard.c) +endif() +if(WIN32) + list(APPEND SOURCE_FILES linphone.rc) +endif() + +if(WIN32) + add_executable(linphone-gtk WIN32 ${SOURCE_FILES}) +else() + add_executable(linphone-gtk ${SOURCE_FILES}) +endif() +set_target_properties(linphone-gtk PROPERTIES OUTPUT_NAME linphone LINKER_LANGUAGE CXX) +target_include_directories(linphone-gtk PUBLIC ${GTK2_INCLUDE_DIRS} ${INTL_INCLUDE_DIRS}) +target_link_libraries(linphone-gtk linphone ${GTK2_LIBRARIES}) +if(INTL_FOUND) + target_link_libraries(linphone-gtk ${INTL_LIBRARIES}) +endif() + +if(WIN32) + target_link_libraries(linphone-gtk Wininet) +endif() +if(ENABLE_NOTIFY) + target_include_directories(linphone-gtk PUBLIC ${NOTIFY_INCLUDE_DIRS}) + target_link_libraries(linphone-gtk ${NOTIFY_LIBRARIES}) +endif() + +if (HAVE_LIBUDEV_H) + target_link_libraries(linphone-gtk udev) +endif() + +install(TARGETS linphone-gtk + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) + +install(FILES ${UI_FILES} ${PIXMAPS} ${LICENSE} + DESTINATION ${PACKAGE_DATA_DIR}/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 831c69a8c..086d51d61 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -11,21 +11,29 @@ UI_FILES= about.ui \ tunnel_config.ui \ waiting.ui \ dscp_settings.ui \ - call_statistics.ui + call_statistics.ui \ + ldap.ui \ + config-uri.ui \ + provisioning-fetch.ui \ + audio_assistant.ui \ + chatroom_frame.ui \ + in_call_frame.ui \ + conf_frame.ui \ + callee_frame.ui \ + login_frame.ui PIXMAPS= \ - stock_people.png + stock_people.png LINPHONE_ICO_RC_FILE=linphone.rc LINPHONE_ICO_FILE=linphone.ico -EXTRA_DIST= $(PIXMAPS) \ - $(UI_FILES) \ - linphone.iss \ - $(LINPHONE_ICO_RC_FILE) \ - $(LINPHONE_ICO_FILE) - gtkrc \ - gtkrc.mac +EXTRA_DIST= \ + linphone.iss \ + $(LINPHONE_ICO_RC_FILE) \ + $(LINPHONE_ICO_FILE) + gtkrc \ + gtkrc.mac if BUILD_GTK_UI @@ -48,20 +56,31 @@ linphone_SOURCES= \ loginframe.c \ singleinstance.c \ conference.c \ - linphone.h + config-fetching.c \ + audio_assistant.c \ + videowindow.c \ + status_icon.c status_icon.h \ + linphone.h + if BUILD_WIZARD -linphone_SOURCES+= \ - setupwizard.c +linphone_SOURCES+= \ + setupwizard.c +endif + +if BUILD_STATUS_NOTIFIER +linphone_SOURCES+= \ + status_notifier.c \ + status_notifier.h endif linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \ - $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) + $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) $(BELLESIP_LIBS) 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 @@ -70,16 +89,17 @@ linphone_LDFLAGS=-export-dynamic endif uidir=$(datadir)/linphone -ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING +dist_ui_DATA=$(UI_FILES) $(PIXMAPS) $(top_srcdir)/COPYING endif -AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \ +AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ -I$(top_builddir)/coreapi/ \ $(MEDIASTREAMER_CFLAGS) \ - $(ORTP_CFLAGS) \ - $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \ - $(TUNNEL_CFLAGS) + $(ORTP_CFLAGS) $(BELLESIP_CFLAGS) \ + $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \ + $(TUNNEL_CFLAGS) \ + $(SQLITE3_CFLAGS) version_date.h: $(top_srcdir)/configure.ac diff --git a/gtk/about.ui b/gtk/about.ui index 1d79dbf7e..d647724b2 100644 --- a/gtk/about.ui +++ b/gtk/about.ui @@ -5,14 +5,14 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 - About linphone + About Linphone False center-on-parent dialog False Linphone undef - (C) Belledonne Communications,2010 + (C) Belledonne Communications, 2010 An internet video phone using the standard SIP (rfc3261) protocol. http://www.linphone.org @@ -30,6 +30,7 @@ pt_BR: Rafael Caesar Lenzi <rc_lenzi@yahoo.com.br> pl: Robert Nasiadek <darkone@darkone.pl> cs: Petr Pisar <petr.pisar@atlas.cz> hu: anonymous +he: Eli Zaretskii <eliz@gnu.org> Icons by kerosine.fr diff --git a/gtk/audio_assistant.c b/gtk/audio_assistant.c new file mode 100644 index 000000000..d12327304 --- /dev/null +++ b/gtk/audio_assistant.c @@ -0,0 +1,548 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "linphone.h" +#include "linphonecore_utils.h" +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/msvolume.h" + +static GtkWidget *audio_assistant=NULL; +static void prepare(GtkAssistant *w); + +GtkWidget *get_widget_from_assistant(const char *name){ + return (GtkWidget *)g_object_get_data(G_OBJECT(audio_assistant),name); +} + +static void set_widget_to_assistant(const char *name,GtkWidget *w){ + g_object_set_data(G_OBJECT(audio_assistant),name,w); +} + +static void update_record_button(gboolean is_visible){ + GtkWidget *rec_button = get_widget_from_assistant("rec_button"); + gtk_widget_set_sensitive(rec_button,is_visible); +} + +#if 0 +static void activate_record_button(gboolean is_active){ + GtkWidget *rec_button = get_widget_from_assistant("rec_button"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_button),is_active); +} +#endif + +static void update_play_button(gboolean is_visible){ + GtkWidget *play_button = get_widget_from_assistant("play_button"); + gtk_widget_set_sensitive(play_button,is_visible); +} + +static void activate_play_button(gboolean is_active){ + GtkWidget *play_button = get_widget_from_assistant("play_button"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),is_active); +} + +static gboolean deactivate_play_button(void){ + activate_play_button(FALSE); + return FALSE; +} + +static gchar *get_record_file(){ + char filename[256]={0}; + char date[64]={0}; + time_t curtime=time(NULL); + struct tm loctime; + + #ifdef WIN32 + loctime=*localtime(&curtime); + #else + localtime_r(&curtime,&loctime); + #endif + snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i%2i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min, loctime.tm_sec); + + snprintf(filename,sizeof(filename)-1,"record-%s.wav",date); + return g_build_path(G_DIR_SEPARATOR_S,g_get_tmp_dir(),filename,NULL);; +} + +static float audio_stream_get_record_volume(AudioStream *st){ + if (st && st->volsend){ + float vol=0; + ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); + return vol; + } + return LINPHONE_VOLUME_DB_LOWEST; +} + +static float audio_stream_get_max_volume(AudioStream *st){ + if (st && st->volsend){ + float vol=0; + ms_filter_call_method(st->volsend,MS_VOLUME_GET_MAX,&vol); + return vol; + } + return LINPHONE_VOLUME_DB_LOWEST; +} + +static gboolean update_audio_label(volume_ctx_t *ctx){ + float volume_db=ctx->get_volume(ctx->data); + gchar *result; + if (volume_db < -20) result = _("No voice detected"); + else if (volume_db <= -10) result = _("Too low"); + else if (volume_db < -6) result = _("Good"); + else result = _("Too loud"); + g_message("volume_max_db=%f, text=%s",volume_db,result); + gtk_label_set_text(GTK_LABEL(ctx->widget),result); + return TRUE; +} + +static void on_audio_label_destroy(guint task_id){ + g_source_remove(task_id); +} + +void linphone_gtk_init_audio_label(GtkWidget *w, get_volume_t get_volume, void *data){ + guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t")); + if (task_id==0){ + volume_ctx_t *ctx=g_new(volume_ctx_t,1); + ctx->widget=w; + ctx->get_volume=get_volume; + ctx->data=data; + ctx->last_value=0; + g_object_set_data_full(G_OBJECT(w),"ctx_t",ctx,g_free); + task_id=g_timeout_add(200,(GSourceFunc)update_audio_label,ctx); + g_object_set_data_full(G_OBJECT(w),"task_id_t",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_label_destroy); + } +} + +void linphone_gtk_uninit_audio_label(GtkWidget *w){ + guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t")); + if (task_id!=0){ + g_object_set_data(G_OBJECT(w),"ctx_t",NULL); + g_object_set_data(G_OBJECT(w),"task_id_t",NULL); + } +} + +static void playback_device_changed(GtkWidget *w){ + gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + linphone_core_set_playback_device(linphone_gtk_get_core(),sel); + g_free(sel); +} + +static void capture_device_changed(GtkWidget *capture_device){ + gchar *sel; + GtkWidget *mic_audiolevel; + GtkWidget *label_audiolevel; + GtkWidget *assistant=gtk_widget_get_toplevel(capture_device); + AudioStream *audio_stream; + + mic_audiolevel = get_widget_from_assistant("mic_audiolevel"); + label_audiolevel = get_widget_from_assistant("label_audiolevel"); + audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(assistant),"stream"); + sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(capture_device)); + linphone_core_set_capture_device(linphone_gtk_get_core(),sel); + linphone_gtk_uninit_audio_meter(mic_audiolevel); + linphone_gtk_uninit_audio_label(label_audiolevel); + audio_stream_stop(audio_stream); + g_free(sel); + /*now restart the audio stream*/ + prepare(GTK_ASSISTANT(assistant)); +} + +static void dialog_click(GtkWidget *dialog, guint response_id, GtkWidget *page){ + switch(response_id){ + case GTK_RESPONSE_YES: + gtk_assistant_set_page_complete(GTK_ASSISTANT(audio_assistant),page,TRUE); + break; + default: + break; + } + gtk_widget_destroy(dialog); +} + +static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){ + GtkWidget * dialog; + GtkWidget *speaker_page; + ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure"); + if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay); + + speaker_page = get_widget_from_assistant("speaker_page"); + + dialog = gtk_message_dialog_new ( + GTK_WINDOW(audio_assistant), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + "%s",_("Did you hear three beeps ?")); + + g_signal_connect(G_OBJECT (dialog), "response", + G_CALLBACK (dialog_click),speaker_page); + gtk_widget_show(dialog); +} + +void linphone_gtk_start_sound(GtkWidget *w){ + LinphoneCore *lc = linphone_gtk_get_core(); + linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL); +} + +static gboolean linphone_gtk_stop_record(gpointer data){ + AudioStream *stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream"); + if(stream != NULL){ + audio_stream_stop(stream); + g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL); + } + update_record_button(FALSE); + update_play_button(TRUE); + return FALSE; +} + + +void linphone_gtk_start_record_sound(GtkWidget *w, gpointer data){ + LinphoneCore *lc = linphone_gtk_get_core(); + AudioStream *stream = NULL; + MSSndCardManager *manager = ms_snd_card_manager_get(); + gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); + gint timeout_id; + + if(active){ + gchar *path = get_record_file(); + stream=audio_stream_new(8888, 8889, FALSE); + if(stream != NULL){ + audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,NULL, + path,NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); + g_object_set_data(G_OBJECT(audio_assistant),"record_stream",stream); + } + timeout_id = gtk_timeout_add(6000,(GtkFunction)linphone_gtk_stop_record,NULL); + g_object_set_data(G_OBJECT(audio_assistant),"timeout_id",GINT_TO_POINTER(timeout_id)); + g_object_set_data(G_OBJECT(audio_assistant),"path",path); + } else { + stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream"); + timeout_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(audio_assistant),"timeout_id")); + gtk_timeout_remove(timeout_id); + if(stream != NULL){ + audio_stream_stop(stream); + g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL); + } + update_record_button(FALSE); + update_play_button(TRUE); + } +} + +static void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){ + switch (ev) { + case MS_PLAYER_EOF: { + ms_message("EndOfFile received"); + /*workaround for a mediastreamer2 bug. Don't deactivate the play button, because it will stop the graph from the end of file callback, + * which is sometimes crashing. On master branch it is fixed in mediastreamer2, the workaround is only valid in 3.8.x branch*/ + g_timeout_add(0, (GSourceFunc)deactivate_play_button, NULL); + break; + } + break; + } +} + +void linphone_gtk_start_play_record_sound(GtkWidget *w,gpointer data){ + LinphoneCore *lc = linphone_gtk_get_core(); + gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); + AudioStream *stream = NULL; + MSSndCardManager *manager = ms_snd_card_manager_get(); + + if(active){ + gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path"); + stream=audio_stream_new(8888, 8889, FALSE); + if(path != NULL){ + audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,path, + NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),NULL,FALSE); + ms_filter_add_notify_callback(stream->soundread,endoffile_cb,stream,FALSE); + g_object_set_data(G_OBJECT(audio_assistant),"play_stream",stream); + } + } else { + stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"play_stream"); + if(stream != NULL){ + audio_stream_stop(stream); + g_object_set_data(G_OBJECT(audio_assistant),"play_stream",NULL); + } + } +} + +void display_popup(GtkMessageType type,const gchar *message){ + GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(audio_assistant), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_CLOSE, + "%s", + (const gchar*)message); + /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + gtk_widget_show(dialog); +} + +static void open_mixer(){ + GError *error = NULL; + +#ifdef WIN32 + if(!g_spawn_command_line_async("control mmsys.cpl",&error)){ + display_popup(GTK_MESSAGE_WARNING,_("Sound preferences not found ")); + g_error_free(error); + } +#elif __APPLE__ + if(!g_spawn_command_line_async("open /System/Library/PreferencePanes/Sound.prefPane",&error)){ + display_popup(GTK_MESSAGE_WARNING,_("Sound preferences not found ")); + g_error_free(error); + } +#else + if(!g_spawn_command_line_async("gnome-volume-control",&error)){ + if(!g_spawn_command_line_async("gnome-control-center sound",&error)){ + if(!g_spawn_command_line_async("kmix",&error)){ + if(!g_spawn_command_line_async("mate-volume-control",&error)){ + if(!g_spawn_command_line_async("xterm alsamixer",&error)){ + display_popup(GTK_MESSAGE_WARNING,_("Cannot launch system sound control ")); + g_error_free(error); + } + } + } + } + } +#endif +} + +static GtkWidget *create_intro(){ + GtkWidget *vbox=gtk_vbox_new(FALSE,2); + GtkWidget *label=gtk_label_new(_("Welcome!\nThis assistant will help you to configure audio settings for Linphone")); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); + gtk_widget_show_all(vbox); + return vbox; +} + +static GtkWidget *create_mic_page(){ + GtkWidget *vbox=gtk_table_new(3,2,FALSE); + LinphoneCore *lc=linphone_gtk_get_core(); + const char **sound_devices; + GtkWidget *labelMicChoice=gtk_label_new(_("Capture device")); + GtkWidget *labelMicLevel=gtk_label_new(_("Recorded volume")); + GtkWidget *mic_audiolevel=gtk_progress_bar_new(); + GtkWidget *capture_device=gtk_combo_box_new(); + GtkWidget *box = gtk_vbox_new(FALSE,0); + GtkWidget *label_audiolevel=gtk_label_new(_("No voice")); + GtkWidget *mixer_button=gtk_button_new_with_label(_("System sound preferences")); + GtkWidget *image; + + image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU); + gtk_button_set_image(GTK_BUTTON(mixer_button),image); + + gtk_box_pack_start(GTK_BOX(box),mic_audiolevel,TRUE,TRUE,1); + gtk_box_pack_start(GTK_BOX(box),label_audiolevel,FALSE,FALSE,1); + + gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicChoice, 0, 1, 0, 1); + gtk_table_attach_defaults(GTK_TABLE(vbox), capture_device, 1, 2, 0, 1); + gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicLevel, 0, 1, 1, 2); + gtk_table_attach_defaults(GTK_TABLE(vbox), box, 1, 2, 1, 2); + gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0); + + gtk_table_set_row_spacings(GTK_TABLE(vbox),10); + + set_widget_to_assistant("mic_audiolevel",mic_audiolevel); + set_widget_to_assistant("label_audiolevel",label_audiolevel); + + sound_devices=linphone_core_get_sound_devices(lc); + linphone_gtk_fill_combo_box(capture_device, sound_devices, + linphone_core_get_capture_device(lc), CAP_CAPTURE); + gtk_widget_show_all(vbox); + + g_signal_connect(G_OBJECT(capture_device),"changed",(GCallback)capture_device_changed,capture_device); + g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox); + + return vbox; +} + +static GtkWidget *create_speaker_page(){ + GtkWidget *vbox=gtk_table_new(3,2,FALSE); + LinphoneCore *lc=linphone_gtk_get_core(); + + GtkWidget *labelSpeakerChoice=gtk_label_new(_("Playback device")); + GtkWidget *labelSpeakerLevel=gtk_label_new(_("Play three beeps")); + GtkWidget *spk_button=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY); + GtkWidget *playback_device=gtk_combo_box_new(); + GtkWidget *mixer_button=gtk_button_new_with_label(_("System sound preferences")); + GtkWidget *image; + const char **sound_devices; + + image=gtk_image_new_from_stock(GTK_STOCK_PREFERENCES,GTK_ICON_SIZE_MENU); + gtk_button_set_image(GTK_BUTTON(mixer_button),image); + + gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerChoice, 0, 1, 0, 1); + gtk_table_attach(GTK_TABLE(vbox), playback_device, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0); + gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerLevel, 0, 1, 1, 2); + gtk_table_attach(GTK_TABLE(vbox), spk_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0); + gtk_table_attach(GTK_TABLE(vbox), mixer_button, 0, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0,0); + + gtk_table_set_row_spacings(GTK_TABLE(vbox),10); + + sound_devices=linphone_core_get_sound_devices(lc); + linphone_gtk_fill_combo_box(playback_device, sound_devices, + linphone_core_get_playback_device(lc),CAP_PLAYBACK); + gtk_widget_show_all(vbox); + + set_widget_to_assistant("speaker_page",vbox); + g_signal_connect(G_OBJECT(playback_device),"changed",(GCallback)playback_device_changed,playback_device); + g_signal_connect(G_OBJECT(spk_button),"clicked",(GCallback)linphone_gtk_start_sound,vbox); + g_signal_connect(G_OBJECT(mixer_button),"clicked",(GCallback)open_mixer,vbox); + + return vbox; +} + +static GtkWidget *create_play_record_page(){ + GtkWidget *vbox=gtk_table_new(2,2,FALSE); + GtkWidget *labelRecord=gtk_label_new(_("Press the record button and say some words")); + GtkWidget *labelPlay=gtk_label_new(_("Listen to your record voice")); + GtkWidget *rec_button=gtk_toggle_button_new_with_label(_("Record")); + GtkWidget *play_button=gtk_toggle_button_new_with_label(_("Play")); + GtkWidget *image; + + image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_RECORD,GTK_ICON_SIZE_MENU); + gtk_button_set_image(GTK_BUTTON(rec_button),image); + + image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_MENU); + gtk_button_set_image(GTK_BUTTON(play_button),image); + gtk_widget_set_sensitive(play_button,FALSE); + + gtk_table_attach_defaults(GTK_TABLE(vbox), labelRecord, 0, 1, 0, 1); + gtk_table_attach(GTK_TABLE(vbox), rec_button, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0); + gtk_table_attach_defaults(GTK_TABLE(vbox), labelPlay, 0, 1, 1, 2); + gtk_table_attach(GTK_TABLE(vbox), play_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0); + + gtk_widget_show_all(vbox); + + set_widget_to_assistant("rec_button",rec_button); + set_widget_to_assistant("play_button",play_button); + g_signal_connect(G_OBJECT(rec_button),"toggled",(GCallback)linphone_gtk_start_record_sound,vbox); + g_signal_connect(G_OBJECT(play_button),"toggled",(GCallback)linphone_gtk_start_play_record_sound,vbox); + + return vbox; +} + +static GtkWidget *create_end_page(){ + GtkWidget *vbox=gtk_vbox_new(FALSE,2); + GtkWidget *label=gtk_label_new(_("Let's start Linphone now")); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); + gtk_widget_show_all(vbox); + return vbox; +} + +static void prepare(GtkAssistant *w){ + AudioStream *audio_stream = NULL; + LinphoneCore *lc=linphone_gtk_get_core(); + int page = gtk_assistant_get_current_page(w); + GtkWidget *mic_audiolevel = get_widget_from_assistant("mic_audiolevel"); + GtkWidget *label_audiolevel = get_widget_from_assistant("label_audiolevel"); + + //Speaker page + if(page == 1){ + MSSndCardManager *manager = ms_snd_card_manager_get(); + audio_stream = audio_stream_start_with_sndcards(&av_profile,9898,"127.0.0.1",19898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); + if (mic_audiolevel != NULL && audio_stream != NULL){ + g_object_set_data(G_OBJECT(audio_assistant),"stream",audio_stream); + linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream); + linphone_gtk_init_audio_label(label_audiolevel,(get_volume_t)audio_stream_get_max_volume,audio_stream); + } + } else if(page == 2 || page == 0){ + if(mic_audiolevel != NULL && label_audiolevel != NULL){ + audio_stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"stream"); + if(audio_stream != NULL){ + linphone_gtk_uninit_audio_meter(mic_audiolevel); + linphone_gtk_uninit_audio_label(label_audiolevel); + audio_stream_stop(audio_stream); + g_object_set_data(G_OBJECT(audio_assistant),"stream",NULL); + } + } + } +} + +void linphone_gtk_close_audio_assistant(GtkWidget *w){ + gchar *path; + AudioStream *stream; + + path = g_object_get_data(G_OBJECT(audio_assistant),"path"); + if(path != NULL){ + g_unlink(path); + } + stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant), "stream"); + if(stream) { + audio_stream_stop(stream); + } + gtk_widget_destroy(w); + if(linphone_gtk_get_audio_assistant_option()){ + gtk_main_quit(); + } + audio_assistant = NULL; +} + +void linphone_gtk_audio_assistant_apply(GtkWidget *w){ + linphone_gtk_close_audio_assistant(w); +} + +void linphone_gtk_show_audio_assistant(void){ + GtkWidget *w; + GtkWidget *welcome; + GtkWidget *mic_page; + GtkWidget *speaker_page; + GtkWidget *play_record_page; + GtkWidget *end_page; + if(audio_assistant!=NULL) + return; + w=audio_assistant=linphone_gtk_create_window("audio_assistant", linphone_gtk_get_main_window()); + + gtk_window_set_resizable (GTK_WINDOW(w), FALSE); + gtk_window_set_title(GTK_WINDOW(w),_("Audio Assistant")); + + welcome=create_intro(); + mic_page=create_mic_page(); + speaker_page=create_speaker_page(); + play_record_page=create_play_record_page(); + end_page=create_end_page(); + + gtk_assistant_append_page(GTK_ASSISTANT(w),welcome); + gtk_assistant_set_page_type(GTK_ASSISTANT(w),welcome,GTK_ASSISTANT_PAGE_INTRO); + gtk_assistant_set_page_title(GTK_ASSISTANT(w),welcome,_("Audio assistant")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w),welcome,TRUE); + + gtk_assistant_append_page(GTK_ASSISTANT(w),mic_page); + gtk_assistant_set_page_type(GTK_ASSISTANT(w),mic_page,GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_title(GTK_ASSISTANT(w),mic_page,_("Mic Gain calibration")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w),mic_page,TRUE); + + gtk_assistant_append_page(GTK_ASSISTANT(w),speaker_page); + gtk_assistant_set_page_type(GTK_ASSISTANT(w),speaker_page,GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w),speaker_page,FALSE); + gtk_assistant_set_page_title(GTK_ASSISTANT(w),speaker_page,_("Speaker volume calibration")); + + gtk_assistant_append_page(GTK_ASSISTANT(w),play_record_page); + gtk_assistant_set_page_type(GTK_ASSISTANT(w),play_record_page,GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w),play_record_page,TRUE); + gtk_assistant_set_page_title(GTK_ASSISTANT(w),play_record_page,_("Record and Play")); + + gtk_assistant_append_page(GTK_ASSISTANT(w),end_page); + gtk_assistant_set_page_type(GTK_ASSISTANT(w),end_page,GTK_ASSISTANT_PAGE_SUMMARY); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w),end_page,TRUE); + gtk_assistant_set_page_title(GTK_ASSISTANT(w),end_page,_("Terminating")); + + g_signal_connect(G_OBJECT(w),"close",(GCallback)linphone_gtk_close_audio_assistant,w); + g_signal_connect(G_OBJECT(w),"cancel",(GCallback)linphone_gtk_close_audio_assistant,w); + g_signal_connect(G_OBJECT(w),"prepare",(GCallback)prepare,NULL); + + gtk_widget_show(w); +} diff --git a/gtk/audio_assistant.ui b/gtk/audio_assistant.ui new file mode 100644 index 000000000..b8390f5d8 --- /dev/null +++ b/gtk/audio_assistant.ui @@ -0,0 +1,21 @@ + + + + + + False + 12 + + + + + + + + + + + + + + diff --git a/gtk/buddylookup.c b/gtk/buddylookup.c index 55c3f334e..3251611d2 100644 --- a/gtk/buddylookup.c +++ b/gtk/buddylookup.c @@ -71,7 +71,7 @@ GtkWidget * linphone_gtk_show_buddy_lookup_window(SipSetupContext *ctx){ GtkCellRenderer *renderer,*pbuf_renderer; GtkTreeViewColumn *column; GtkTreeSelection *select; - GtkWidget *w=linphone_gtk_create_window("buddylookup"); + GtkWidget *w=linphone_gtk_create_window("buddylookup", NULL); GtkWidget *results=linphone_gtk_get_widget(w,"search_results"); GtkProgressBar *pb=GTK_PROGRESS_BAR(linphone_gtk_get_widget(w,"progressbar")); @@ -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/call_logs.ui b/gtk/call_logs.ui index 34c6ba3b2..23184841a 100644 --- a/gtk/call_logs.ui +++ b/gtk/call_logs.ui @@ -82,7 +82,9 @@ True True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False + diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index c6f71deb6..d53c93a1f 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -1,115 +1,67 @@ - + - + - False 5 Call statistics dialog - + True - False 2 - - - True - False - end - - - - - - gtk-close - True - True - True - False - True - - - False - False - 1 - - - - - False - True - end - 0 - - True - False 0 none True - False 12 True - False - 7 + 10 2 True True - False Audio codec - + 1 + 2 + True - False Video codec - 1 - 2 - + 2 + 3 + True - False Audio IP bandwidth usage - 2 - 3 - + 3 + 4 + True - False - - - 1 - 2 - - - - - True - False 1 @@ -119,9 +71,8 @@ - + True - False 1 @@ -130,22 +81,53 @@ 3 + + + True + + + 1 + 2 + 3 + 4 + + True - False Audio Media connectivity - 4 - 5 - + 5 + 6 + True - False + + + 1 + 2 + 5 + 6 + + + + + True + Video IP bandwidth usage + + + 4 + 5 + + + + + + True 1 @@ -154,74 +136,106 @@ 5 - - - True - False - Video IP bandwidth usage - - - 3 - 4 - - - - - - True - False - - - 1 - 2 - 3 - 4 - - True - False Video Media connectivity - 5 - 6 + 6 + 7 True - False 1 2 - 5 - 6 + 6 + 7 True - False Round trip time - 6 - 7 + 7 + 8 True - False 1 2 - 6 - 7 + 7 + 8 + + + + + True + Video resolution received + + + 8 + 9 + + + + + True + + + 1 + 2 + 8 + 9 + + + + + True + Video resolution sent + + + 9 + 10 + + + + + True + + + 1 + 2 + 9 + 10 + + + + + True + RTP profile + + + + + + + + True + + + 1 + 2 @@ -231,7 +245,6 @@ True - False <b>Call statistics and information</b> True @@ -243,6 +256,34 @@ 1 + + + True + end + + + + + + gtk-close + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + diff --git a/gtk/callee_frame.ui b/gtk/callee_frame.ui new file mode 100644 index 000000000..4ae4d90ef --- /dev/null +++ b/gtk/callee_frame.ui @@ -0,0 +1,84 @@ + + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 12 + + + True + False + + + True + False + + + True + True + + + False + False + 0 + + + + + False + True + 0 + + + + + True + False + <b>Callee name</b> + True + right + end + + + True + True + 1 + + + + + 90 + 30 + True + False + + + False + True + 2 + + + + + + + + + + + + + diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 9e703a8ff..4d91c38bd 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -19,10 +19,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" - static void fill_renderers(GtkTreeView *v){ GtkTreeViewColumn *c; - GtkCellRenderer *r=gtk_cell_renderer_pixbuf_new (); + GtkCellRenderer *r; + r=gtk_cell_renderer_pixbuf_new(); c=gtk_tree_view_column_new_with_attributes("icon",r,"pixbuf",0,NULL); gtk_tree_view_append_column (v,c); @@ -32,35 +32,258 @@ static void fill_renderers(GtkTreeView *v){ gtk_tree_view_append_column (v,c); } +void call_log_selection_changed(GtkTreeView *v){ + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model=NULL; + + select = gtk_tree_view_get_selection(v); + if (select!=NULL){ + if (gtk_tree_selection_get_selected (select, &model, &iter)){ + GtkTreePath *path=gtk_tree_model_get_path(model,&iter); + gtk_tree_view_collapse_all(v); + gtk_tree_view_expand_row(v,path,TRUE); + gtk_tree_path_free(path); + } + } +} + +void linphone_gtk_call_log_chat_selected(GtkWidget *w){ + GtkTreeSelection *select; + GtkTreeIter iter; + + select=gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); + if (select!=NULL){ + GtkTreeModel *model=NULL; + if (gtk_tree_selection_get_selected (select,&model,&iter)){ + gpointer pcl; + LinphoneAddress *la; + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + if (la != NULL){ + linphone_gtk_friend_list_set_chat_conversation(la); + } + } + } +} + +void linphone_gtk_call_log_add_contact(GtkWidget *w){ + GtkWidget *main_window = gtk_widget_get_toplevel(w); + GtkTreeSelection *select; + GtkTreeIter iter; + + select=gtk_tree_view_get_selection(GTK_TREE_VIEW(w)); + if (select!=NULL){ + GtkTreeModel *model=NULL; + if (gtk_tree_selection_get_selected (select,&model,&iter)){ + gpointer pcl; + LinphoneAddress *la; + LinphoneCallLog *cl; + LinphoneFriend *lf; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + if (la != NULL){ + char *uri=linphone_address_as_string(la); + lf=linphone_friend_new_with_address(uri); + linphone_gtk_show_contact(lf, main_window); + ms_free(uri); + } + } + } +} + +static bool_t put_selection_to_uribar(GtkWidget *treeview){ + GtkTreeSelection *sel; + sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + if (sel!=NULL){ + GtkTreeModel *model=NULL; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (sel,&model,&iter)){ + char *tmp; + gpointer pcl; + LinphoneAddress *la; + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + tmp = linphone_address_as_string(la); + if(tmp!=NULL) + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp); + ms_free(tmp); + return TRUE; + } + } + return FALSE; +} + +static void linphone_gtk_call_selected(GtkTreeView *treeview){ + put_selection_to_uribar(GTK_WIDGET(treeview)); + linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), + "start_call")); +} + +static GtkWidget *linphone_gtk_create_call_log_menu(GtkWidget *call_log){ + GtkWidget *menu=gtk_menu_new(); + GtkWidget *menu_item; + gchar *call_label=NULL; + gchar *text_label=NULL; + gchar *name=NULL; + GtkWidget *image; + GtkTreeSelection *select; + GtkTreeIter iter; + + select=gtk_tree_view_get_selection(GTK_TREE_VIEW(call_log)); + if (select!=NULL){ + GtkTreeModel *model=NULL; + if (gtk_tree_selection_get_selected (select,&model,&iter)){ + gpointer pcl; + LinphoneAddress *la; + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + name=linphone_address_as_string(la); + call_label=g_strdup_printf(_("Call %s"),name); + text_label=g_strdup_printf(_("Send text to %s"),name); + ms_free(name); + } + } + if (call_label){ + menu_item=gtk_image_menu_item_new_with_label(call_label); + image=gtk_image_new_from_stock(GTK_STOCK_NETWORK,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); + gtk_widget_show(image); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_selected,call_log); + } + if (text_label){ + menu_item=gtk_image_menu_item_new_with_label(text_label); + image=gtk_image_new_from_stock(GTK_STOCK_NETWORK,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); + gtk_widget_show(image); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_log_chat_selected,call_log); + } + menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD,NULL); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_call_log_add_contact,call_log); + gtk_widget_show(menu); + gtk_menu_attach_to_widget(GTK_MENU(menu),call_log, NULL); + + if (call_label) g_free(call_label); + if (text_label) g_free(text_label); + return menu; +} + +gboolean linphone_gtk_call_log_popup_contact(GtkWidget *list, GdkEventButton *event){ + GtkWidget *m=linphone_gtk_create_call_log_menu(list); + gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL, + event ? event->button : 0, event ? event->time : gtk_get_current_event_time()); + return TRUE; +} + +gboolean linphone_gtk_call_log_button_pressed(GtkWidget *widget, GdkEventButton *event){ + if (event->button == 3 && event->type == GDK_BUTTON_PRESS){ + return linphone_gtk_call_log_popup_contact(widget, event); + } + return FALSE; +} + +void linphone_gtk_call_log_clear_missed_call(){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(mw,"viewswitch")); + GtkWidget *page=gtk_notebook_get_nth_page(notebook,0); + GtkWidget *box=gtk_hbox_new(FALSE,0); + GtkWidget *image=gtk_image_new_from_stock(GTK_STOCK_REFRESH,GTK_ICON_SIZE_MENU); + GtkWidget *l; + const gchar*text=gtk_label_get_text(GTK_LABEL(linphone_gtk_get_widget(mw,"label3"))); + + l=gtk_label_new(text); + gtk_box_pack_start(GTK_BOX(box),image,FALSE,FALSE,0); + gtk_box_pack_start(GTK_BOX(box),l,FALSE,FALSE,0); + gtk_notebook_set_tab_label(notebook,page,box); + gtk_widget_show_all(box); +} + +gboolean linphone_gtk_call_log_reset_missed_call(GtkWidget *w, GdkEvent *event,gpointer user_data){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(mw,"viewswitch")); + gtk_notebook_set_current_page(notebook,0); + linphone_core_reset_missed_calls_count(linphone_gtk_get_core()); + linphone_gtk_call_log_clear_missed_call(); + return TRUE; +} + +void linphone_gtk_call_log_display_missed_call(int nb){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(mw,"viewswitch")); + GtkWidget *page=gtk_notebook_get_nth_page(notebook,0); + GtkWidget *ebox=gtk_event_box_new(); + GtkWidget *box=gtk_hbox_new(FALSE,0); + GtkWidget *image=gtk_image_new_from_stock(GTK_STOCK_REFRESH,GTK_ICON_SIZE_MENU); + GtkWidget *l; + gchar *buf; + + buf=g_markup_printf_escaped(_("Recent calls (%i)"),nb); + l=gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(l),buf); + gtk_box_pack_start(GTK_BOX(box),image,FALSE,FALSE,0); + gtk_box_pack_start(GTK_BOX(box),l,FALSE,FALSE,0); + gtk_container_add(GTK_CONTAINER(ebox),box); + gtk_notebook_set_tab_label(notebook,page,ebox); + gtk_widget_add_events(ebox,GDK_BUTTON_PRESS_MASK); + g_signal_connect(G_OBJECT(ebox),"button_press_event",(GCallback)linphone_gtk_call_log_reset_missed_call,NULL); + gtk_widget_show_all(ebox); +} + void linphone_gtk_call_log_update(GtkWidget *w){ GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view")); - GtkListStore *store; + GtkTreeStore *store; const MSList *logs; + GtkTreeSelection *select; + GtkWidget *notebook=linphone_gtk_get_widget(w,"viewswitch"); + gint nb; - store=(GtkListStore*)gtk_tree_view_get_model(v); + store=(GtkTreeStore*)gtk_tree_view_get_model(v); if (store==NULL){ - store=gtk_list_store_new(3,GDK_TYPE_PIXBUF,G_TYPE_STRING,G_TYPE_POINTER); + store=gtk_tree_store_new(3,GDK_TYPE_PIXBUF,G_TYPE_STRING,G_TYPE_POINTER,G_TYPE_STRING); gtk_tree_view_set_model(v,GTK_TREE_MODEL(store)); g_object_unref(G_OBJECT(store)); fill_renderers(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view"))); + select=gtk_tree_view_get_selection(v); + gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); + g_signal_connect_swapped(G_OBJECT(select),"changed",(GCallback)call_log_selection_changed,v); + g_signal_connect(G_OBJECT(notebook),"focus-tab",(GCallback)linphone_gtk_call_log_reset_missed_call,NULL); + g_signal_connect(G_OBJECT(v),"button-press-event",(GCallback)linphone_gtk_call_log_button_pressed,NULL); // gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"call_back_button")), // create_pixmap (linphone_gtk_get_ui_config("callback_button","status-green.png"))); } - gtk_list_store_clear (store); + nb=linphone_core_get_missed_calls_count(linphone_gtk_get_core()); + if(nb > 0) + linphone_gtk_call_log_display_missed_call(nb); + gtk_tree_store_clear (store); for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){ LinphoneCallLog *cl=(LinphoneCallLog*)logs->data; - GtkTreeIter iter; + GtkTreeIter iter, iter2; LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); - char *addr= linphone_address_as_string_uri_only (la); + char *addr= linphone_address_as_string(la); const char *display; - gchar *logtxt, *minutes, *seconds; + gchar *logtxt, *headtxt, *minutes, *seconds; gchar quality[20]; const char *status=NULL; gchar *start_date=NULL; + LinphoneFriend *lf=NULL; int duration=linphone_call_log_get_duration(cl); time_t start_date_time=linphone_call_log_get_start_date(cl); - + GdkPixbuf *pbuf; + #if GLIB_CHECK_VERSION(2,26,0) if (start_date_time){ GDateTime *dt=g_date_time_new_from_unix_local(start_date_time); @@ -70,13 +293,22 @@ void linphone_gtk_call_log_update(GtkWidget *w){ #else start_date=g_strdup(ctime(&start_date_time)); #endif - - display=linphone_address_get_display_name (la); + lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr); + if(lf != NULL){ + if ((display=linphone_address_get_display_name(linphone_friend_get_address(lf)))) { + /*update display name from friend*/ + linphone_address_set_display_name(la,display); + } + } else { + display=linphone_address_get_display_name(la); + } if (display==NULL){ display=linphone_address_get_username (la); - if (display==NULL) + if (display==NULL){ display=linphone_address_get_domain (la); + } } + if (linphone_call_log_get_quality(cl)!=-1){ snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl)); }else snprintf(quality,sizeof(quality)-1,"%s",_("n/a")); @@ -99,52 +331,33 @@ void linphone_gtk_call_log_update(GtkWidget *w){ seconds=g_markup_printf_escaped( ngettext("%i second", "%i seconds", duration%60), duration%60); - if (status==NULL) logtxt=g_markup_printf_escaped( - _("%s\t%s\t" - "Quality: %s\n%s\t%s %s\t"), - display, addr, quality , - start_date ? start_date : "", minutes, seconds); - else logtxt=g_markup_printf_escaped( - _("%s\t%s\t" - "\n%s\t%s"), - display, addr, - start_date ? start_date : "", status); + if (status==NULL) { + headtxt=g_markup_printf_escaped("%s\t%s",display,start_date ? start_date : ""); + logtxt=g_markup_printf_escaped( + _("%s\t" + "Quality: %s\n%s\t%s\t"), + addr, quality, minutes, seconds); + } else { + headtxt=g_markup_printf_escaped(_("%s\t%s"),display,start_date ? start_date : ""); + logtxt=g_markup_printf_escaped( + "%s\t" + "\n%s",addr, status); + } g_free(minutes); g_free(seconds); if (start_date) g_free(start_date); - gtk_list_store_append (store,&iter); - - GdkPixbuf *incoming = create_pixbuf("call_status_incoming.png"); - GdkPixbuf *outgoing = create_pixbuf("call_status_outgoing.png"); - gtk_list_store_set (store,&iter, - 0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming, - 1, logtxt,2,la,-1); + gtk_tree_store_append (store,&iter,NULL); + pbuf = linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? create_pixbuf("call_status_outgoing.png") : create_pixbuf("call_status_incoming.png"); + gtk_tree_store_set (store,&iter, + 0, pbuf, + 1, headtxt,2,cl,-1); + gtk_tree_store_append (store,&iter2,&iter); + gtk_tree_store_set (store,&iter2,1,logtxt,-1); + g_object_unref(pbuf); ms_free(addr); g_free(logtxt); + g_free(headtxt); } - -} - -static bool_t put_selection_to_uribar(GtkWidget *treeview){ - GtkTreeSelection *sel; - - sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if (sel!=NULL){ - GtkTreeModel *model=NULL; - GtkTreeIter iter; - if (gtk_tree_selection_get_selected (sel,&model,&iter)){ - gpointer pla; - LinphoneAddress *la; - char *tmp; - gtk_tree_model_get(model,&iter,2,&pla,-1); - la=(LinphoneAddress*)pla; - tmp=linphone_address_as_string (la); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp); - ms_free(tmp); - return TRUE; - } - } - return FALSE; } void linphone_gtk_history_row_activated(GtkWidget *treeview){ @@ -160,6 +373,7 @@ void linphone_gtk_history_row_selected(GtkWidget *treeview){ void linphone_gtk_clear_call_logs(GtkWidget *button){ linphone_core_clear_call_logs (linphone_gtk_get_core()); + linphone_gtk_call_log_clear_missed_call(); linphone_gtk_call_log_update(gtk_widget_get_toplevel(button)); } @@ -183,21 +397,18 @@ void linphone_gtk_call_log_response(GtkWidget *w, guint response_id){ gtk_widget_destroy(w); } - - -GtkWidget * linphone_gtk_show_call_logs(void){ - GtkWidget *mw=linphone_gtk_get_main_window(); - - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); - if (w==NULL){ - w=linphone_gtk_create_window("call_logs"); -// gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"call_back_button")), -// create_pixmap (linphone_gtk_get_ui_config("callback_button","status-green.png"))); - g_object_set_data(G_OBJECT(mw),"call_logs",w); - g_signal_connect(G_OBJECT(w),"response",(GCallback)linphone_gtk_call_log_response,NULL); - gtk_widget_show(w); - linphone_gtk_call_log_update(w); - }else gtk_window_present(GTK_WINDOW(w)); - return w; -} - +// GtkWidget * linphone_gtk_show_call_logs(void){ +// GtkWidget *mw=linphone_gtk_get_main_window(); +// +// GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); +// if (w==NULL){ +// w=linphone_gtk_create_window("call_logs"); +// // gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"call_back_button")), +// // create_pixmap (linphone_gtk_get_ui_config("callback_button","status-green.png"))); +// g_object_set_data(G_OBJECT(mw),"call_logs",w); +// g_signal_connect(G_OBJECT(w),"response",(GCallback)linphone_gtk_call_log_response,NULL); +// gtk_widget_show(w); +// linphone_gtk_call_log_update(w); +// }else gtk_window_present(GTK_WINDOW(w)); +// return w; +// } diff --git a/gtk/chat.c b/gtk/chat.c index 76d34c2ff..ac4fac23c 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -23,38 +23,84 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif +#if defined(WIN32) && !defined(F_OK) +#define F_OK 00 /*visual studio does not define F_OK*/ +#endif + +#define NB_MSG_HIST 250 + +#define CONFIG_FILE ".linphone-history.db" + +char *linphone_gtk_message_storage_get_db_file(const char *filename){ + const int path_max=1024; + char *db_file=NULL; + + db_file=(char *)g_malloc(path_max*sizeof(char)); + if (filename==NULL) filename=CONFIG_FILE; + /*try accessing a local file first if exists*/ + if (access(CONFIG_FILE,F_OK)==0){ + snprintf(db_file,path_max,"%s",filename); + }else{ +#ifdef WIN32 + const char *appdata=getenv("APPDATA"); + if (appdata){ + snprintf(db_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); + CreateDirectory(db_file,NULL); + snprintf(db_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); + } +#else + const char *home=getenv("HOME"); + if (home==NULL) home="."; + snprintf(db_file,path_max,"%s/%s",home,filename); +#endif + } + return db_file; +} + + void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { GtkWidget *main_window=linphone_gtk_get_main_window (); GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); GtkWidget *w=g_object_get_data(G_OBJECT(friendlist),"chatview"); - int idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"idx")); + gchar *from; + g_return_if_fail(w!=NULL); - gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx); - linphone_gtk_create_chat_picture(FALSE); + gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); + linphone_chat_room_mark_as_read(cr); + linphone_gtk_friend_list_update_chat_picture(); g_object_set_data(G_OBJECT(friendlist),"chatview",NULL); - g_object_set_data(G_OBJECT(w),"from_message",NULL); + from=g_object_get_data(G_OBJECT(w),"from_message"); + if (from){ + g_object_set_data(G_OBJECT(w),"from_message",NULL); + g_free(from); + } g_object_set_data(G_OBJECT(w),"cr",NULL); + linphone_gtk_friend_list_set_active_address(NULL); gtk_widget_destroy(w); } +const char* get_display_name(const LinphoneAddress *from){ + const char *display; + display=linphone_address_get_display_name(from); + if (display==NULL || display[0]=='\0') { + display=linphone_address_get_username(from); + } + return display; +} + GtkWidget *create_tab_chat_header(LinphoneChatRoom *cr,const LinphoneAddress *uri){ GtkWidget *w=gtk_hbox_new (FALSE,0); GtkWidget *i=create_pixmap ("chat.png"); GtkWidget *l; GtkWidget *image=gtk_image_new_from_stock(GTK_STOCK_CLOSE,GTK_ICON_SIZE_MENU); GtkWidget *b=gtk_button_new(); - + gtk_button_set_image(GTK_BUTTON(b),image); gtk_button_set_relief(GTK_BUTTON(b),GTK_RELIEF_NONE); gtk_widget_set_size_request(b,25,20); g_signal_connect_swapped(G_OBJECT(b),"clicked",G_CALLBACK(linphone_gtk_quit_chatroom),cr); - - const char *display=linphone_address_get_display_name(uri); - if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(uri); - } - l=gtk_label_new (display); + l=gtk_label_new(get_display_name(uri)); gtk_box_pack_start (GTK_BOX(w),i,FALSE,FALSE,0); gtk_box_pack_start (GTK_BOX(w),l,FALSE,FALSE,0); gtk_box_pack_end(GTK_BOX(w),b,TRUE,TRUE,0); @@ -75,124 +121,155 @@ void udpate_tab_chat_header(GtkWidget *chat_view,const LinphoneAddress *uri,Linp gtk_button_set_relief(GTK_BUTTON(b),GTK_RELIEF_NONE); gtk_widget_set_size_request(b,25,20); g_signal_connect_swapped(G_OBJECT(b),"clicked",G_CALLBACK(linphone_gtk_quit_chatroom),cr); - - const char *display=linphone_address_get_display_name(uri); - if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(uri); - } - l=gtk_label_new (display); + l=gtk_label_new (get_display_name(uri)); gtk_box_pack_start (GTK_BOX(w),i,FALSE,FALSE,0); gtk_box_pack_start (GTK_BOX(w),l,FALSE,FALSE,0); gtk_box_pack_end(GTK_BOX(w),b,TRUE,TRUE,0); - gtk_notebook_set_tab_label(notebook,chat_view,w); gtk_widget_show_all(w); - } -void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, - const char *message, gboolean me,LinphoneChatRoom *cr, time_t t){ - GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview")); - GtkTextBuffer *buffer=gtk_text_view_get_buffer(text); - GtkTextIter iter,begin,end; - gtk_text_buffer_get_start_iter(buffer,&begin); - int off; +static gboolean scroll_to_end(GtkTextView *w){ + GtkTextBuffer *buffer=gtk_text_view_get_buffer(w); + GtkTextMark *mark; + GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer,&iter); - off=gtk_text_iter_get_offset(&iter); - GList *list=g_object_get_data(G_OBJECT(w),"list"); + mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); + gtk_text_view_scroll_mark_onscreen(w,mark); + return FALSE; +} - if(g_strcmp0((char *)g_object_get_data(G_OBJECT(w),"from_message"),linphone_address_as_string(from))!=0){ - gtk_text_buffer_get_iter_at_offset(buffer,&iter,off); - const char *display=linphone_address_get_display_name(from); - if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(from); +static gboolean word_starts_with(const GtkTextIter *word_start, const char *prefix) { + gboolean res; + gchar *schema = NULL; + GtkTextIter end = *word_start; + gtk_text_iter_forward_chars(&end, strlen(prefix)); + schema = gtk_text_iter_get_slice(word_start, &end); + res = ( g_strcmp0(schema, prefix) == 0 ); + g_free(schema); + return res; +} + +static gboolean is_space(gunichar ch, gpointer user_data) { + return g_unichar_isspace(ch); +} + +static void insert_link_tags(GtkTextBuffer *buffer, const GtkTextIter *begin, const GtkTextIter *end) { + GtkTextIter iter = *begin; + while(gtk_text_iter_compare(&iter, end) < 0) { + if(gtk_text_iter_starts_word(&iter) && ( + word_starts_with(&iter, "http://") || + word_starts_with(&iter, "https://") || + word_starts_with(&iter, "ftp://") || + word_starts_with(&iter, "ftps://"))) { + GtkTextIter uri_begin = iter; + if(gtk_text_iter_forward_find_char(&iter, is_space, NULL, end)) { + gtk_text_buffer_apply_tag_by_name(buffer, "link", &uri_begin, &iter); + } } - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,display,-1,"bold",me ? "bg":NULL,NULL); - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter," : ",-1,"bold",me ? "bg":NULL,NULL); - gtk_text_buffer_get_end_iter(buffer,&iter); + gtk_text_iter_forward_char(&iter); + } +} + +void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, + gboolean me,LinphoneChatRoom *cr,LinphoneChatMessage *msg, gboolean hist){ + GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview")); + GtkTextBuffer *buffer=gtk_text_view_get_buffer(text); + GtkTextIter iter, link_start; + GtkTextMark *link_start_mark = NULL; + char *from_str=linphone_address_as_string_uri_only(from); + gchar *from_message=(gchar *)g_object_get_data(G_OBJECT(w),"from_message"); + GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(w),"table"); + time_t t; + char buf[80]; + time_t tnow; + struct tm *tm; + int tnow_day; + int tnow_year; + + gtk_text_buffer_get_end_iter(buffer, &iter); + if (g_strcmp0(from_message,from_str)!=0){ + gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, get_display_name(from), -1, + "from", me ? "me" : NULL, NULL); + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter, " : ", -1, + "from", me ? "me" : NULL, NULL); gtk_text_buffer_insert(buffer,&iter,"\n",-1); - g_object_set_data(G_OBJECT(w),"from_message",linphone_address_as_string(from)); + g_free(from_message); + g_object_set_data(G_OBJECT(w),"from_message",g_strdup(from_str)); } - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_get_iter_at_offset(buffer,&begin,off); - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,message,-1,"margin",me ? "bg":NULL,NULL); - gtk_text_buffer_get_end_iter(buffer,&iter); - gtk_text_buffer_insert(buffer,&iter,"\n",-1); - gtk_text_buffer_get_bounds (buffer, &begin, &end); - GHashTable *hash=(GHashTable *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"history"); - if(me){ - g_hash_table_insert(hash,linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), - (gpointer)gtk_text_buffer_get_text(buffer,&begin,&end,FALSE)); - } else { - g_hash_table_insert(hash,linphone_address_as_string_uri_only(from), - (gpointer)gtk_text_buffer_get_text(buffer,&begin,&end,FALSE)); - } - g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"history",hash); - + ms_free(from_str); - gtk_text_buffer_get_end_iter(buffer,&iter); - if(me){ - list=g_list_append(list,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending .. ",-1, - "italic","right","small","font_grey","bg",NULL); - g_object_set_data(G_OBJECT(w),"list",list); - } else { - struct tm *tm=localtime(&t); - char buf[80]; - strftime(buf,80,"Send at %H:%M",tm); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,buf,-1, - "italic","right","small","font_grey",NULL); - } - gtk_text_buffer_get_end_iter(buffer,&iter); + link_start_mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); + gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, linphone_chat_message_get_text(msg), -1, + "body", me ? "me" : NULL, NULL); gtk_text_buffer_insert(buffer,&iter,"\n",-1); - GtkTextMark *mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); - gtk_text_view_scroll_mark_onscreen(text,mark); + gtk_text_buffer_get_iter_at_mark(buffer, &link_start, link_start_mark); + insert_link_tags(buffer, &link_start, &iter); + gtk_text_buffer_delete_mark(buffer, link_start_mark); + + t=linphone_chat_message_get_time(msg); + switch (linphone_chat_message_get_state (msg)){ + 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, + "status", me ? "me" : NULL, NULL); + //g_object_set_data(G_OBJECT(w),"table",table); + break; + case LinphoneChatMessageStateDelivered: + tnow=time(NULL); + tm=localtime(&tnow); + tnow_day=tm->tm_yday; + tnow_year=tm->tm_year; + tm=localtime(&t); + if(tnow_day != tm->tm_yday || (tnow_day == tm->tm_yday && tnow_year != tm->tm_year)) { + strftime(buf,80,"%a %x, %H:%M",tm); + } else { + strftime(buf,80,"%H:%M",tm); + } + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,buf,-1, + "status", me ? "me" : NULL, NULL); + break; + case LinphoneChatMessageStateNotDelivered: + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Message not sent",-1, + "status", me ? "me" : NULL, NULL); + break; + default : gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1, + "status", me ? "me" : NULL, NULL); + } + gtk_text_buffer_insert(buffer,&iter,"\n",-1); + g_idle_add((GSourceFunc)scroll_to_end,text); } -const LinphoneAddress* linphone_gtk_get_used_identity(){ - LinphoneCore *lc=linphone_gtk_get_core(); - LinphoneProxyConfig *cfg; - linphone_core_get_default_proxy(lc,&cfg); - if (cfg) return linphone_address_new(linphone_proxy_config_get_identity(cfg)); - else return linphone_core_get_primary_contact_parsed(lc); -} - - -/* function in dev for displaying ack*/ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessage *msg){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); + GtkWidget *main_window=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); GtkWidget *page=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - GList *list=g_object_get_data(G_OBJECT(page),"list"); - + GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(page),"table"); + if(page!=NULL){ GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(page,"textview")); GtkTextBuffer *b=gtk_text_view_get_buffer(text); GtkTextIter iter; GtkTextIter end; GtkTextIter start; - - gtk_text_buffer_get_iter_at_line(b,&iter, - GPOINTER_TO_INT(g_list_nth_data(list,0))); - if(gtk_text_iter_get_chars_in_line(&iter) >0) { - gtk_text_buffer_get_iter_at_line_offset(b,&start, - GPOINTER_TO_INT(g_list_nth_data(list,0)), - gtk_text_iter_get_chars_in_line(&iter)-1); - }else { - gtk_text_buffer_get_iter_at_line_offset(b,&start, - GPOINTER_TO_INT(g_list_nth_data(list,0)),0); - } - gtk_text_buffer_get_iter_at_line_offset(b,&end, - GPOINTER_TO_INT(g_list_nth_data(list,0)),0); - gtk_text_buffer_delete(b,&start,&end); - gtk_text_buffer_get_iter_at_line(b,&iter,GPOINTER_TO_INT(g_list_nth_data(list,0))); gchar *result; + gint line; + line=GPOINTER_TO_INT(g_hash_table_lookup(table,msg)); + + gtk_text_buffer_get_iter_at_line(b,&iter,line); + if(gtk_text_iter_get_chars_in_line(&iter) >0) { + gtk_text_buffer_get_iter_at_line_offset(b,&start,line, + gtk_text_iter_get_chars_in_line(&iter)-1); + }else{ + gtk_text_buffer_get_iter_at_line_offset(b,&start,line,0); + } + gtk_text_buffer_get_iter_at_line_offset(b,&end,line,0); + gtk_text_buffer_delete(b,&start,&end); + gtk_text_buffer_get_iter_at_line(b,&iter,line); + switch (state) { case LinphoneChatMessageStateInProgress: - result="Sending "; + result="Sending .."; break; case LinphoneChatMessageStateDelivered: { @@ -201,198 +278,381 @@ 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="Error "; + { + 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, - "italic","right","small","font_grey","bg",NULL); - list=g_list_remove(list,g_list_nth_data(list,0)); - g_object_set_data(G_OBJECT(page),"list",list); - } + "status", "me", NULL); + //g_object_set_data(G_OBJECT(page),"table",table); + } } -static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state, void *user_pointer){ +static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state){ update_chat_state_message(state,msg); } -void linphone_gtk_send_text(){ - GtkWidget *main_window=linphone_gtk_get_main_window(); +void linphone_gtk_compose_text(void) { + GtkWidget *main_window=linphone_gtk_get_main_window(); GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); + LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); + if (cr) { + linphone_chat_room_compose(cr); + linphone_chat_room_mark_as_read(cr); + linphone_gtk_friend_list_update_chat_picture(); + } +} + +void linphone_gtk_send_text(){ + GtkWidget *main_window=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry"); const gchar *entered; LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); entered=gtk_entry_get_text(GTK_ENTRY(entry)); if (strlen(entered)>0) { LinphoneChatMessage *msg; + LinphoneChatMessageCbs *cbs; msg=linphone_chat_room_create_message(cr,entered); - linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL); - linphone_gtk_push_text(w, - linphone_gtk_get_used_identity(), - entered,TRUE,cr,linphone_chat_message_get_time(msg)); + cbs=linphone_chat_message_get_callbacks(msg); + linphone_chat_message_cbs_set_msg_state_changed(cbs,on_chat_state_changed); + linphone_chat_room_send_chat_message(cr,msg); + linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), + TRUE,cr,msg,FALSE); + + // Disconnect and reconnect the "changed" signal to prevent triggering it when clearing the text entry. + g_signal_handlers_disconnect_by_func(G_OBJECT(entry),(GCallback)linphone_gtk_compose_text,NULL); gtk_entry_set_text(GTK_ENTRY(entry),""); + g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); } } +static void linphone_gtk_chat_message_destroy(LinphoneChatMessage *msg){ + linphone_chat_message_destroy(msg); +} + +void linphone_gtk_free_list(MSList *messages){ + ms_list_for_each(messages,(void (*)(void*))linphone_gtk_chat_message_destroy); + ms_list_free(messages); +} + +void display_history_message(GtkWidget *chat_view,MSList *messages,const LinphoneAddress *with){ + if (messages != NULL){ + MSList *it; + char *from_str; + char *with_str; + gchar *tmp; + for(it=messages;it!=NULL;it=it->next){ + LinphoneChatMessage *msg=(LinphoneChatMessage *)it->data; + from_str=linphone_address_as_string_uri_only(linphone_chat_message_get_from(msg)); + with_str=linphone_address_as_string_uri_only(with); + linphone_gtk_push_text(chat_view,strcmp(from_str,with_str)==0? with : + linphone_chat_message_get_from(msg), + strcmp(from_str,with_str)==0? FALSE : TRUE, + linphone_chat_message_get_chat_room(msg),msg,TRUE); + ms_free(from_str); + ms_free(with_str); + } + tmp=g_object_get_data(G_OBJECT(chat_view),"from_message"); + if (tmp){ + g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); + g_free(tmp); + } + + linphone_gtk_free_list(messages); + } +} + +static void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ + LinphoneFriend *lf=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,LinphoneSPWait); + linphone_friend_send_subscribe(lf,show_presence); + + linphone_friend_set_address(lf,addr); + linphone_core_add_friend(linphone_gtk_get_core(),lf); + linphone_gtk_show_friends(); +} + +static GdkColor *_linphone_gtk_chatroom_get_link_color(GtkWidget *chatview) { + GValue color_value = {0}; + g_value_init(&color_value, GDK_TYPE_COLOR); + gtk_style_get_style_property( + gtk_widget_get_style(chatview), + G_OBJECT_TYPE(chatview), + "link-color", &color_value); + + return (GdkColor *)g_value_get_boxed(&color_value); +} + +static gboolean link_event_handler(GtkTextTag *tag, GObject *text_view,GdkEvent *event, GtkTextIter *iter, gpointer user_data) { + if(event->type == GDK_BUTTON_PRESS) { + GtkTextIter uri_begin = *iter; + GtkTextIter uri_end = *iter; + gchar *uri = NULL; + gtk_text_iter_backward_to_tag_toggle(&uri_begin, tag); + gtk_text_iter_forward_to_tag_toggle(&uri_end, tag); + uri = gtk_text_iter_get_slice(&uri_begin, &uri_end); + if(((GdkEventButton *)event)->button == 1) { + linphone_gtk_open_browser(uri); + } else if(((GdkEventButton *)event)->button == 3) { + GtkMenu *menu = GTK_MENU(g_object_get_data(text_view, "link_ctx_menu")); + g_object_set_data_full(G_OBJECT(menu), "uri", g_strdup(uri), g_free); + gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 3, gdk_event_get_time(event)); + } + g_free(uri); + return TRUE; + } + return FALSE; +} + +static void chatroom_enable_hand_cursor(GdkWindow *window, gboolean hand_cursor_enabled) { +#if GTK_CHECK_VERSION(2,22,0) + GdkCursor *cursor = gdk_window_get_cursor(window); + GdkCursor *new_cursor = NULL; + if(!hand_cursor_enabled && gdk_cursor_get_cursor_type(cursor) != GDK_XTERM) { + new_cursor = gdk_cursor_new(GDK_XTERM); + } else if(hand_cursor_enabled && gdk_cursor_get_cursor_type(cursor) != GDK_HAND1) { + new_cursor = gdk_cursor_new(GDK_HAND1); + } + if(new_cursor) { + gdk_window_set_cursor(window, new_cursor); + gdk_cursor_unref(new_cursor); + } +#endif +} + +static gboolean chatroom_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { + gint wx, wy, bx, by; + GtkTextView *chatroom = GTK_TEXT_VIEW(widget); + GtkTextBuffer *buffer = gtk_text_view_get_buffer(chatroom); + GtkTextTag *link_tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "link"); + GdkWindow *window = gtk_text_view_get_window(chatroom, GTK_TEXT_WINDOW_TEXT); + GtkTextIter iter; + if(event->type == GDK_MOTION_NOTIFY) { + GdkEventMotion *motion_ev = (GdkEventMotion *)event; + wx = motion_ev->x; + wy = motion_ev->y; + gtk_text_view_window_to_buffer_coords(chatroom, GTK_TEXT_WINDOW_TEXT, wx, wy, &bx, &by); + gtk_text_view_get_iter_at_location(chatroom, &iter, bx, by); + if(gtk_text_iter_has_tag(&iter, link_tag)) { + chatroom_enable_hand_cursor(window, TRUE); + } else { + chatroom_enable_hand_cursor(window, FALSE); + } + } + return FALSE; +} + +static gboolean copy_uri_into_clipboard_handler(GtkMenuItem *menuitem, gpointer user_data) { + GtkWidget *menu = gtk_widget_get_parent(GTK_WIDGET(menuitem)); + const gchar *uri = (const gchar *)g_object_get_data(G_OBJECT(menu), "uri"); + GtkClipboard *clipboard = NULL; + GdkAtom clipboard_atom = gdk_atom_intern("CLIPBOARD", TRUE); + if(clipboard_atom == GDK_NONE) { + g_warning("Could not find CLIPBOARD atom"); + return FALSE; + } + clipboard = gtk_clipboard_get(clipboard_atom); + if(uri) gtk_clipboard_set_text(clipboard, uri, -1); + return FALSE; +} + GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){ - GtkWidget *chat_view=linphone_gtk_create_widget("main","chatroom_frame"); - GtkWidget *main_window=linphone_gtk_get_main_window (); - GHashTable *hash=g_object_get_data(G_OBJECT(main_window),"history"); + GtkWidget *chat_view=linphone_gtk_create_widget("chatroom_frame"); + GtkWidget *main_window=linphone_gtk_get_main_window(); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview"); - GdkColor color; + GdkColor color_grey = {0, 32512, 32512, 32512}; + GdkColor color_light_grey = {0, 56832, 60928, 61952}; + GdkColor color_black = {0}; int idx; - - color.red = 32512; - color.green = 32512; - color.blue = 32512; + GtkWidget *button; + GtkWidget *entry = linphone_gtk_get_widget(chat_view,"text_entry"); + MSList *messages; + GHashTable *table; + GtkTextTag *tmp_tag; + GtkWidget *link_ctx_menu = gtk_menu_new(); + GtkWidget *link_ctx_menu_copy_item = gtk_menu_item_new_with_label(_("Copy")); - GdkColor colorb; - - colorb.red = 56832; - colorb.green = 60928; - colorb.blue = 61952; - - gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW(text),GTK_WRAP_WORD); - gtk_text_view_set_editable (GTK_TEXT_VIEW(text),FALSE); - gtk_notebook_append_page (notebook,chat_view,create_tab_chat_header(cr,with)); + gtk_notebook_append_page(notebook,chat_view,create_tab_chat_header(cr,with)); idx = gtk_notebook_page_num(notebook, chat_view); gtk_notebook_set_current_page(notebook, idx); gtk_widget_show(chat_view); - + table=g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL); g_object_set_data(G_OBJECT(chat_view),"cr",cr); - g_object_set_data(G_OBJECT(chat_view),"idx",GINT_TO_POINTER(idx)); g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); - g_object_set_data(G_OBJECT(chat_view),"from_chatroom",(gpointer) with); + g_object_set_data_full(G_OBJECT(chat_view),"table",table,(GDestroyNotify)g_hash_table_destroy); - GList *list=NULL; - g_object_set_data(G_OBJECT(chat_view),"list",list); + gtk_text_buffer_create_tag( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), + "me", + "foreground_gdk", &color_black, + "paragraph-background-gdk", &color_light_grey, + NULL); - gchar *buf=g_hash_table_lookup(hash,linphone_address_as_string_uri_only(with)); - if(buf != NULL){ - GtkTextIter start; - GtkTextIter end; - - GtkTextBuffer *text_buffer; - text_buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); - gtk_text_buffer_get_bounds(text_buffer, &start, &end); - gtk_text_buffer_delete (text_buffer, &start, &end); - gtk_text_buffer_insert(text_buffer,&start,buf,-1); - } + gtk_text_buffer_create_tag( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), + "from", + "weight", PANGO_WEIGHT_BOLD, + NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "right","justification", GTK_JUSTIFY_RIGHT,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "left","justification", GTK_JUSTIFY_LEFT,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "bold","weight", PANGO_WEIGHT_BOLD,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "italic","style", PANGO_STYLE_ITALIC,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "small","size",9*PANGO_SCALE,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "font_grey","foreground-gdk",&color,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "margin","indent",10,NULL); - gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), - "bg","paragraph-background-gdk",&colorb,NULL); - - GtkWidget *button = linphone_gtk_get_widget(chat_view,"send"); + gtk_text_buffer_create_tag( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), + "body", + "indent", 10, + NULL); + + gtk_text_buffer_create_tag( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), + "status", + "size-points", 9.0, + "foreground_gdk", &color_grey, + "style", PANGO_STYLE_ITALIC, + "justification", GTK_JUSTIFY_RIGHT, + NULL); + + tmp_tag = gtk_text_buffer_create_tag( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), + "link", + "underline", PANGO_UNDERLINE_SINGLE, + "foreground_gdk", _linphone_gtk_chatroom_get_link_color(chat_view), + NULL); + g_signal_connect(G_OBJECT(tmp_tag), "event", G_CALLBACK(link_event_handler), NULL); + g_signal_connect(G_OBJECT(text), "event", G_CALLBACK(chatroom_event), NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(link_ctx_menu), link_ctx_menu_copy_item); + g_signal_connect(G_OBJECT(link_ctx_menu_copy_item), "activate", G_CALLBACK(copy_uri_into_clipboard_handler), NULL); + gtk_widget_show_all(link_ctx_menu); + g_object_set_data_full(G_OBJECT(text), "link_ctx_menu", link_ctx_menu, g_object_unref); + g_object_ref_sink(G_OBJECT(link_ctx_menu)); + + messages = linphone_chat_room_get_history(cr,NB_MSG_HIST); + display_history_message(chat_view,messages,with); + button = linphone_gtk_get_widget(chat_view,"send"); g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); - GtkWidget *entry = linphone_gtk_get_widget(chat_view,"text_entry"); g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL); - + g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); + g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL); return chat_view; } LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){ - LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),linphone_address_as_string(with)); - if (!cr) return NULL; + LinphoneChatRoom *cr=linphone_core_get_chat_room(linphone_gtk_get_core(), with); return cr; } void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri,GtkWidget *chat_view){ GtkWidget *main_window=linphone_gtk_get_main_window (); - GHashTable *hash=g_object_get_data(G_OBJECT(main_window),"history"); - LinphoneAddress *from=(LinphoneAddress *)g_object_get_data(G_OBJECT(chat_view),"from_chatroom"); - if(g_strcmp0(linphone_address_as_string(from),linphone_address_as_string(uri))!=0) - { - GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); - GtkTextIter start; - GtkTextIter end; - gchar *buf=g_hash_table_lookup(hash,linphone_address_as_string_uri_only(uri)); - GtkTextBuffer *text_buffer; - text_buffer=gtk_text_view_get_buffer(text_view); - gtk_text_buffer_get_bounds(text_buffer, &start, &end); - g_object_set_data(G_OBJECT(chat_view),"cr",cr); - gtk_text_buffer_delete (text_buffer, &start, &end); - if(buf!=NULL){ - gtk_text_buffer_insert_with_tags_by_name(text_buffer,&start,buf,-1,"font_grey",NULL); - GtkTextMark *mark=gtk_text_buffer_create_mark(text_buffer, NULL, &start, FALSE); - gtk_text_view_scroll_to_mark(text_view,mark, 0, FALSE, 0, 0); - } + LinphoneChatRoom *cr2=(LinphoneChatRoom *)g_object_get_data(G_OBJECT(chat_view),"cr"); + const LinphoneAddress *from=linphone_chat_room_get_peer_address(cr2); + char *from_str=linphone_address_as_string_uri_only(from); + char *uri_str=linphone_address_as_string(uri); + char *uri_only=linphone_address_as_string_uri_only(uri); + MSList *messages=NULL; + if(g_strcmp0(from_str,uri_only)!=0){ + GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); + GtkTextIter start; + GtkTextIter end; + GtkTextBuffer *text_buffer; + + text_buffer=gtk_text_view_get_buffer(text_view); + gtk_text_buffer_get_bounds(text_buffer, &start, &end); + gtk_text_buffer_delete (text_buffer, &start, &end); udpate_tab_chat_header(chat_view,uri,cr); g_object_set_data(G_OBJECT(chat_view),"cr",cr); - g_object_set_data(G_OBJECT(chat_view),"from_chatroom",(gpointer) uri); - g_object_set_data(G_OBJECT(chat_view),"from_message",linphone_address_as_string_uri_only(uri)); g_object_set_data(G_OBJECT(linphone_gtk_get_widget(main_window,"contact_list")),"chatview",(gpointer)chat_view); + messages=linphone_chat_room_get_history(cr,NB_MSG_HIST); + g_object_set_data(G_OBJECT(chat_view),"from_message",g_strdup(uri_str)); + display_history_message(chat_view,messages,uri); + gtk_text_buffer_get_end_iter(text_buffer,&end); + gtk_text_view_scroll_to_iter(text_view,&end,0,FALSE,1.0,0); } + ms_free(from_str); + ms_free(uri_str); + ms_free(uri_only); } void linphone_gtk_chat_destroyed(GtkWidget *w){ + /* LinphoneChatRoom *cr=(LinphoneChatRoom*)g_object_get_data(G_OBJECT(w),"cr"); - linphone_chat_room_destroy(cr); -} - -void linphone_gtk_chat_close(GtkWidget *button){ - GtkWidget *w=gtk_widget_get_toplevel(button); - gtk_widget_destroy(w); + */ } -void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, - LinphoneChatMessage *msg){ +void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, + LinphoneChatMessage *msg ) { GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); - GtkWidget *w; - + GtkWidget *friendlist=linphone_gtk_get_widget ( main_window,"contact_list" ); + GtkWidget *w; + gboolean send=TRUE; + /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ + const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); - w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - if(w!=NULL){ - linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); - } else { - 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",(gpointer)linphone_chat_message_get_from(msg)); - } - - const char *display=linphone_address_get_display_name(linphone_chat_message_get_from(msg)); - if (display==NULL || display[0]=='\0') { - display=linphone_address_get_username(linphone_chat_message_get_from(msg)); - } - - #ifdef HAVE_GTK_OSXs - /* Notified when a new message is sent */ - linphone_gtk_status_icon_set_blinking(TRUE); - #else - if(!gtk_window_is_active(GTK_WINDOW(main_window))){ - if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_notified"))){ - linphone_gtk_notify(NULL,linphone_chat_message_get_text(msg)); - g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(TRUE)); + w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); + if ( w!=NULL ) { + /* Chat window opened */ + const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); + if (linphone_address_weak_equal(from,from_chatview)) { + send=TRUE; } else { - g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE)); + if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { + linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); + } + send=FALSE; + } + } else { + /* Chat window closed */ +#ifdef MSG_STORAGE_ENABLED + send=FALSE; +#else + send=TRUE; +#endif + if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { + linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); + } + w=linphone_gtk_init_chatroom ( room,linphone_chat_message_get_from ( msg ) ); + g_object_set_data ( G_OBJECT ( friendlist ),"chatview", ( gpointer ) w ); + linphone_gtk_friend_list_set_active_address(from); + } + +#ifdef HAVE_GTK_OSX + /* Notified when a new message is sent */ + linphone_gtk_status_icon_set_blinking ( TRUE ); +#else + if ( !gtk_window_is_active ( GTK_WINDOW ( main_window ) ) ) { + if ( !GPOINTER_TO_INT ( g_object_get_data ( G_OBJECT ( w ),"is_notified" ) ) ) { + linphone_gtk_notify ( NULL,linphone_chat_message_get_text ( msg ) ); + g_object_set_data ( G_OBJECT ( w ),"is_notified",GINT_TO_POINTER ( TRUE ) ); + } else { + g_object_set_data ( G_OBJECT ( w ),"is_notified",GINT_TO_POINTER ( FALSE ) ); } } - #endif - linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), - linphone_chat_message_get_text(msg),FALSE,room,linphone_chat_message_get_time(msg)); - linphone_gtk_update_chat_picture(); - //gtk_window_present(GTK_WINDOW(w)); - /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ +#endif + if ( send ) { + linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), + FALSE,room,msg,FALSE ); + } + linphone_core_play_local(lc,linphone_gtk_get_sound_path("incoming_chat.wav")); + linphone_gtk_show_friends(); + +} + +void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + linphone_gtk_friend_list_update_chat_picture(); } diff --git a/gtk/chatroom_frame.ui b/gtk/chatroom_frame.ui new file mode 100644 index 000000000..8d3b46c4a --- /dev/null +++ b/gtk/chatroom_frame.ui @@ -0,0 +1,113 @@ + + + + + + True + False + 0 + none + + + True + False + + + True + True + never + + + True + True + 4 + False + word-char + False + + + + + True + True + 0 + + + + + True + False + + + True + True + + True + False + False + True + True + + + True + True + 0 + + + + + True + True + True + + + True + False + + + True + False + gtk-ok + + + True + True + 0 + + + + + True + False + Send + + + True + True + 7 + 1 + + + + + + + False + False + 1 + + + + + False + False + 1 + + + + + + + + + diff --git a/gtk/conf_frame.ui b/gtk/conf_frame.ui new file mode 100644 index 000000000..1012efa88 --- /dev/null +++ b/gtk/conf_frame.ui @@ -0,0 +1,86 @@ + + + + + + True + False + 0 + none + + + True + False + + + True + False + + + End conference + True + True + True + + + False + False + end + 0 + + + + + True + True + end + 0 + + + + + True + False + + + gtk-media-record + True + True + True + True + + + + False + False + 0 + + + + + True + False + True + char + + + True + True + 1 + + + + + False + False + end + 1 + + + + + + + + + diff --git a/gtk/conference.c b/gtk/conference.c index 08262c771..75a36cbdd 100644 --- a/gtk/conference.c +++ b/gtk/conference.c @@ -61,9 +61,9 @@ static GtkWidget *find_conferencee_from_call(LinphoneCall *call){ GtkWidget *conferencee_box=get_conferencee_box(mw); GList *elem; GtkWidget *ret=NULL; - + if (conferencee_box==NULL) return NULL; - + if (call!=NULL){ GList *l=gtk_container_get_children(GTK_CONTAINER(conferencee_box)); for(elem=l;elem!=NULL;elem=elem->next){ @@ -81,19 +81,20 @@ static GtkWidget *find_conferencee_from_call(LinphoneCall *call){ static GtkWidget * create_conference_panel(void){ GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *conf_frame=linphone_gtk_create_widget("main","conf_frame"); + GtkWidget *conf_frame=linphone_gtk_create_widget("conf_frame"); GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box"); GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf"); GtkWidget *image=create_pixmap("stopcall-small.png"); GtkWidget *box; GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch"); - + GtkWidget *participant; + gtk_button_set_image(GTK_BUTTON(button_conf),image); g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL); g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame); - + box=gtk_vbox_new(FALSE,0); - GtkWidget *participant=linphone_gtk_create_widget("main","callee_frame"); + participant=linphone_gtk_create_widget("callee_frame"); gtk_widget_show(participant); gtk_box_set_homogeneous(GTK_BOX(box),TRUE); init_local_participant(participant); @@ -101,7 +102,7 @@ static GtkWidget * create_conference_panel(void){ gtk_widget_show(box); g_object_set_data(G_OBJECT(mw),"conferencee_box",box); gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS); - + gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame, create_conference_label()); return conf_frame; @@ -111,20 +112,21 @@ void linphone_gtk_set_in_conference(LinphoneCall *call){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch"); - + GtkWidget *participant; + if(conf_frame==NULL){ conf_frame=create_conference_panel(); } - GtkWidget *participant=find_conferencee_from_call(call); - + participant=find_conferencee_from_call(call); + if (participant==NULL){ /*create and add it */ GtkWidget *conferencee_box=get_conferencee_box(mw); GtkWidget *sound_meter; const LinphoneAddress *addr=linphone_call_get_remote_address(call); gchar *markup; - - participant=linphone_gtk_create_widget("main","callee_frame"); + + participant=linphone_gtk_create_widget("callee_frame"); gtk_widget_show(participant); if (linphone_address_get_display_name(addr)!=NULL){ markup=g_strdup_printf("%s",linphone_address_get_display_name(addr)); @@ -140,7 +142,7 @@ void linphone_gtk_set_in_conference(LinphoneCall *call){ gtk_box_pack_start(GTK_BOX(conferencee_box),participant,FALSE,FALSE,PADDING_PIXELS); g_object_set_data_full(G_OBJECT(participant),"call",linphone_call_ref(call),(GDestroyNotify)linphone_call_unref); gtk_notebook_set_current_page(GTK_NOTEBOOK(viewswitch), - gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame)); + gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame)); } } @@ -153,13 +155,13 @@ void linphone_gtk_terminate_conference_participant(LinphoneCall *call){ void linphone_gtk_unset_from_conference(LinphoneCall *call){ GtkWidget *frame=find_conferencee_from_call(call); - + if (frame){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); GtkWidget *conferencee_box=g_object_get_data(G_OBJECT(mw),"conferencee_box"); GList *children; - + g_message("Removing a participant from conference"); gtk_widget_destroy(frame); children=gtk_container_get_children(GTK_CONTAINER(conferencee_box)); diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c new file mode 100644 index 000000000..b1794eea9 --- /dev/null +++ b/gtk/config-fetching.c @@ -0,0 +1,79 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" +#include "lpconfig.h" + + +void linphone_gtk_set_configuration_uri(void){ + GtkWidget *w=linphone_gtk_create_window("config-uri", linphone_gtk_get_main_window()); + GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); + const char *uri=linphone_core_get_provisioning_uri(linphone_gtk_get_core()); + if (uri) gtk_entry_set_text(GTK_ENTRY(entry),uri); + gtk_widget_show(w); +} + +void linphone_gtk_config_uri_changed(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); + const char *uri=gtk_entry_get_text(GTK_ENTRY(entry)); + + if (uri && (strlen(uri)==0 || strcmp(uri,"https://")==0)) uri=NULL; + + linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri); + gtk_widget_destroy(w); + + if (uri){ + linphone_gtk_schedule_restart(); + gtk_main_quit(); + } +} + +void linphone_gtk_config_uri_cancel(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + gtk_widget_destroy(w); +} + +GtkWidget * linphone_gtk_show_config_fetching(void){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *w=linphone_gtk_create_window("provisioning-fetch", linphone_gtk_get_main_window()); + g_message("Fetching started"); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(w),_("fetching from %s"),linphone_core_get_provisioning_uri(lc)); +#if GTK_CHECK_VERSION(2,20,0) + { + GtkWidget *spinner=gtk_spinner_new(); + gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(w),spinner); + } +#endif + gtk_widget_show(w); + return w; +} + +void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state){ + LinphoneCore *lc=linphone_gtk_get_core(); + gtk_widget_destroy(w); + g_message("Fetching finished"); + if (state==LinphoneConfiguringFailed){ + GtkWidget *msg=gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,_("Downloading of remote configuration from %s failed."), + linphone_core_get_provisioning_uri(lc)); + g_signal_connect(G_OBJECT(msg),"response",(GCallback)gtk_widget_destroy,NULL); + gtk_widget_show(msg); + } +} + diff --git a/gtk/config-uri.ui b/gtk/config-uri.ui new file mode 100644 index 000000000..cc99c40db --- /dev/null +++ b/gtk/config-uri.ui @@ -0,0 +1,99 @@ + + + + + + False + 5 + Specifying a remote configuration URI + dialog + + + True + False + 2 + + + True + False + end + + + gtk-undo + True + True + True + False + True + + + + False + False + 0 + + + + + gtk-ok + True + True + True + False + True + + + + False + False + 1 + + + + + False + True + end + 0 + + + + + True + False + This dialog allows to set an http or https address when configuration is to be fetched at startup. +Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. + True + 80 + + + True + True + 1 + + + + + True + True + + https:// + False + False + True + True + + + True + True + 2 + + + + + + button2 + button1 + + + diff --git a/gtk/dscp_settings.ui b/gtk/dscp_settings.ui index 22679a49b..7f5061f72 100644 --- a/gtk/dscp_settings.ui +++ b/gtk/dscp_settings.ui @@ -5,7 +5,7 @@ False 5 - Dscp settings + DSCP settings True dialog diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 5ce869b46..6cd6c8581 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -32,7 +32,6 @@ enum{ FRIEND_ICON, FRIEND_CALL, FRIEND_CHAT, - FRIEND_CHAT_CONVERSATION, FRIEND_LIST_NCOL }; @@ -76,17 +75,30 @@ static GdkPixbuf *create_call_picture(){ return pixbuf; } +static GdkPixbuf *create_unread_msg(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("active_chat.png"); + return pixbuf; +} + static GdkPixbuf *create_chat_picture(){ GdkPixbuf *pixbuf; pixbuf = create_pixbuf("chat.png"); return pixbuf; } -static GdkPixbuf *create_active_chat_picture(){ +static GdkPixbuf *create_composing_unread_msg(){ GdkPixbuf *pixbuf; - pixbuf = create_pixbuf("active_chat.png"); + pixbuf = create_pixbuf("composing_active_chat.png"); return pixbuf; } + +static GdkPixbuf *create_composing_chat_picture(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("composing_chat.png"); + return pixbuf; +} + /* void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ GtkTreeIter iter; @@ -110,6 +122,16 @@ void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid } } */ + +gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr){ + LinphoneFriend *lf; + char *addr_str=linphone_address_as_string(addr); + lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr_str); + if(lf == NULL){ + return FALSE; + } return TRUE; +} + static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){ GtkTreeSelection *select; GtkTreeIter iter; @@ -126,8 +148,8 @@ static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){ } } -void linphone_gtk_add_contact(){ - GtkWidget *w=linphone_gtk_create_window("contact"); +void linphone_gtk_add_contact(void){ + GtkWidget *w=linphone_gtk_create_window("contact", linphone_gtk_get_main_window()); int presence_enabled=linphone_gtk_get_ui_config_int("use_subscribe_notify",1); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")),presence_enabled); @@ -146,7 +168,7 @@ void linphone_gtk_edit_contact(GtkWidget *button){ if (gtk_tree_selection_get_selected (select, &model, &iter)) { gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - linphone_gtk_show_contact(lf); + linphone_gtk_show_contact(lf, w); } } @@ -156,11 +178,51 @@ void linphone_gtk_remove_contact(GtkWidget *button){ GtkTreeIter iter; GtkTreeModel *model; LinphoneFriend *lf=NULL; + LinphoneChatRoom *cr=NULL; select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); if (gtk_tree_selection_get_selected (select, &model, &iter)) { gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); linphone_core_remove_friend(linphone_gtk_get_core(),lf); + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + linphone_chat_room_delete_history(cr); + linphone_gtk_show_friends(); + } +} + +void linphone_gtk_delete_history(GtkWidget *button){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *chat_view; + LinphoneFriend *lf=NULL; + GtkWidget *friendlist; + + friendlist=linphone_gtk_get_widget(w,"contact_list"); + chat_view=(GtkWidget *)g_object_get_data(G_OBJECT(friendlist),"chatview"); + select = gtk_tree_view_get_selection(GTK_TREE_VIEW(friendlist)); + if (gtk_tree_selection_get_selected (select, &model, &iter)) + { + LinphoneChatRoom *cr; + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + linphone_chat_room_delete_history(cr); + if(chat_view!=NULL){ + 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; + GtkTextBuffer *text_buffer; + + text_buffer=gtk_text_view_get_buffer(text_view); + gtk_text_buffer_get_bounds(text_buffer, &start, &end); + gtk_text_buffer_delete (text_buffer, &start, &end); + g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); + } + } linphone_gtk_show_friends(); } } @@ -171,45 +233,33 @@ static void linphone_gtk_call_selected(GtkTreeView *treeview){ "start_call")); } -void linphone_gtk_create_chat_picture(gboolean active){ +void linphone_gtk_friend_list_update_chat_picture(){ GtkTreeIter iter; GtkWidget *w = linphone_gtk_get_main_window(); GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); + LinphoneChatRoom *cr=NULL; + bool_t is_composing; + int nbmsg=0; if (gtk_tree_model_get_iter_first(model,&iter)) { do{ - if(!active){ - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); + GdkPixbuf *pbuf = NULL; + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + nbmsg=linphone_chat_room_get_unread_messages_count(cr); + is_composing=linphone_chat_room_is_remote_composing(cr); + if(nbmsg != 0){ + if (is_composing == TRUE) + pbuf = create_composing_unread_msg(); + else + pbuf = create_unread_msg(); } else { - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_active_chat_picture(),-1); - } - }while(gtk_tree_model_iter_next(model,&iter)); - } -} - -void linphone_gtk_update_chat_picture(){ - GtkTreeIter iter; - GtkListStore *store=NULL; - GtkWidget *w = linphone_gtk_get_main_window(); - GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); - GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); - GtkWidget *chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - LinphoneFriend *lf=NULL; - LinphoneAddress *uri=(LinphoneAddress *)g_object_get_data(G_OBJECT(friendlist),"from"); - store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); - if (gtk_tree_model_get_iter_first(model,&iter)) { - do{ - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - if(chat_view!=NULL){ - if(uri !=NULL) { - if(g_strcmp0(linphone_address_as_string(linphone_friend_get_address(lf)), - linphone_address_as_string(uri))==0){ - gtk_list_store_set(store,&iter,FRIEND_CHAT,create_active_chat_picture(),-1); - } else { - gtk_list_store_set(store,&iter,FRIEND_CHAT,create_chat_picture(),-1); - } - } + if (is_composing == TRUE) + pbuf = create_composing_chat_picture(); + else + pbuf = create_chat_picture(); } + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,pbuf,-1); + if (pbuf) g_object_unref(pbuf); }while(gtk_tree_model_iter_next(model,&iter)); } } @@ -219,6 +269,90 @@ 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"); + g_object_set_data_full(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL, (GDestroyNotify)linphone_address_destroy); +} + +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; + GtkWidget *w = linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); + GtkWidget *chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); + LinphoneFriend *lf=NULL; + LinphoneChatRoom *cr=NULL; + GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); + + lf=linphone_core_find_friend(linphone_gtk_get_core(),la); + if(lf==NULL){ + cr=linphone_gtk_create_chatroom(la); + 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); + } else { + linphone_gtk_load_chatroom(cr,la,chat_view); + } + gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); + linphone_gtk_friend_list_update_chat_picture(); + g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); + } else { + store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); + if (gtk_tree_model_get_iter_first(model,&iter)) { + do{ + const LinphoneAddress *uri; + gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1); + uri=linphone_friend_get_address(lf); + 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); + } + 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); + } else { + linphone_gtk_load_chatroom(cr,uri,chat_view); + } + gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); + linphone_gtk_friend_list_update_chat_picture(); + g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); + break; + } + }while(gtk_tree_model_iter_next(model,&iter)); + } + } +} + +void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + GtkWidget *chat_view; + LinphoneChatRoom *cr=NULL; + chat_view=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); + if(page != NULL){ + notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); + if(gtk_notebook_page_num(notebook,page)==gtk_notebook_page_num(notebook,chat_view)){ + cr=g_object_get_data(G_OBJECT(chat_view),"cr"); + if(cr!=NULL){ + linphone_chat_room_mark_as_read(cr); + linphone_gtk_show_friends(); + } + } + } +} + void linphone_gtk_chat_selected(GtkWidget *item){ GtkWidget *w=gtk_widget_get_toplevel(item); GtkTreeSelection *select; @@ -236,22 +370,24 @@ void linphone_gtk_chat_selected(GtkWidget *item){ GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); const LinphoneAddress *uri; gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); uri=linphone_friend_get_address(lf); - if(cr == NULL){ + if(cr==NULL){ cr=linphone_gtk_create_chatroom(uri); + 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",(gpointer)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); } else { linphone_gtk_load_chatroom(cr,uri,page); } + linphone_chat_room_mark_as_read(cr); gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,page)); - linphone_gtk_create_chat_picture(FALSE); + linphone_gtk_friend_list_update_chat_picture(); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry")); - gtk_list_store_set(store,&iter,FRIEND_CHAT,create_active_chat_picture(),-1); } } @@ -336,21 +472,26 @@ void linphone_gtk_my_presence_clicked(GtkWidget *button){ } static void icon_press_handler(GtkEntry *entry){ + GtkWidget *w = gtk_widget_get_toplevel(GTK_WIDGET(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); - if (lf==NULL) - lf=linphone_friend_new_with_addr(uri); - if (lf!=NULL){ - linphone_gtk_show_contact(lf); - } ms_free(uri); + if (lf==NULL) + lf=linphone_friend_new(); + if (lf!=NULL){ + linphone_friend_set_address(lf,addr); + linphone_gtk_show_contact(lf, w); + } + linphone_address_destroy(addr); } } @@ -372,11 +513,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); @@ -410,7 +552,11 @@ static gboolean friend_search_func(GtkTreeModel *model, gint column, gboolean ret=TRUE; gtk_tree_model_get(model,iter,FRIEND_NAME,&name,-1); if (name!=NULL){ - ret=strstr(name,key)==NULL; + gchar *uname=g_utf8_casefold(name,-1); /* need that to perform case-insensitive search in utf8 */ + gchar *ukey=g_utf8_casefold(key,-1); + ret=strstr(uname,ukey)==NULL; + g_free(uname); + g_free(ukey); g_free(name); } return ret; @@ -449,6 +595,13 @@ static void on_name_column_clicked(GtkTreeModel *model){ static int get_friend_weight(const LinphoneFriend *lf){ int w=0; + LinphoneCore *lc=linphone_gtk_get_core(); + LinphoneChatRoom *cr=linphone_core_get_chat_room(lc,linphone_friend_get_address(lf)); + + if (cr && linphone_chat_room_get_unread_messages_count(cr)>0){ + w+=2000; + } + switch(linphone_friend_get_status(lf)){ case LinphoneStatusOnline: w+=1000; @@ -524,7 +677,7 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ linphone_gtk_init_bookmark_icon(); store = gtk_list_store_new(FRIEND_LIST_NCOL,GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, - G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, G_TYPE_STRING); + G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF); gtk_tree_view_set_model(GTK_TREE_VIEW(friendlist),GTK_TREE_MODEL(store)); g_object_unref(G_OBJECT(store)); @@ -545,6 +698,7 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ g_signal_connect_swapped(G_OBJECT(column),"clicked",(GCallback)on_presence_column_clicked,GTK_TREE_MODEL(store)); gtk_tree_view_column_set_clickable(column,TRUE); gtk_tree_view_column_set_visible(column,linphone_gtk_get_ui_config_int("friendlist_status",1)); + gtk_tree_view_column_set_min_width(column,50); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column,renderer,TRUE); @@ -569,7 +723,7 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ column = gtk_tree_view_column_new_with_attributes (_("Call"),renderer,"pixbuf",FRIEND_CALL,NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); - /* chat column*/ + /* Chat column*/ renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes (_("Chat"),renderer,"pixbuf",FRIEND_CHAT,NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); @@ -582,7 +736,7 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(friendlist),FRIEND_SIP_ADDRESS); #endif - gtk_widget_set_size_request(friendlist,200,100); + gtk_widget_set_size_request(friendlist,200,120); /*gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget( gtk_widget_get_toplevel(friendlist),"show_category")),0);*/ } @@ -629,8 +783,9 @@ gboolean linphone_gtk_directory_search_focus_in(GtkWidget *entry){ void linphone_gtk_directory_search_activate(GtkWidget *entry){ LinphoneProxyConfig *cfg; + GtkWidget *w; linphone_core_get_default_proxy(linphone_gtk_get_core(),&cfg); - GtkWidget *w=linphone_gtk_show_buddy_lookup_window(linphone_proxy_config_get_sip_setup_context(cfg)); + w=linphone_gtk_show_buddy_lookup_window(linphone_proxy_config_get_sip_setup_context(cfg)); if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(entry),"active"))==1) linphone_gtk_buddy_lookup_set_keyword(w,gtk_entry_get_text(GTK_ENTRY(entry))); } @@ -651,13 +806,13 @@ void linphone_gtk_show_friends(void){ //const gchar *search=NULL; //gboolean lookup=FALSE; MSList *sorted; + LinphoneChatRoom *cr=NULL; linphone_gtk_show_directory_search(); - if (gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))==NULL){ linphone_gtk_friend_list_init(friendlist); } - + store=GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist))); gtk_list_store_clear(store); @@ -675,6 +830,10 @@ void linphone_gtk_show_friends(void){ const char *name=linphone_address_get_display_name(f_uri); const char *display=name; char *escaped=NULL; + //char buf[26]={0}; + int nbmsg=0; + GdkPixbuf *pbuf, *pbuf2, *pbuf3; + /*if (lookup){ if (strstr(uri,search)==NULL){ ms_free(uri); @@ -687,17 +846,26 @@ void linphone_gtk_show_friends(void){ display=linphone_address_get_username(f_uri); } gtk_list_store_append(store,&iter); + pbuf = create_chat_picture(); + pbuf2 = create_call_picture(); + pbuf3 = send_subscribe ? create_status_picture(linphone_friend_get_status(lf)) : NULL; gtk_list_store_set(store,&iter,FRIEND_NAME, display,FRIEND_ID,lf, - FRIEND_PRESENCE_IMG, send_subscribe ? create_status_picture(linphone_friend_get_status(lf)) : NULL, - -1); - - gtk_list_store_set(store,&iter,FRIEND_CALL,create_call_picture(),-1); - gtk_list_store_set(store,&iter,FRIEND_CHAT,create_chat_picture(),-1); - + FRIEND_PRESENCE_IMG, pbuf3, + FRIEND_CHAT,pbuf,FRIEND_CALL,pbuf2,-1); + g_object_unref(pbuf); + g_object_unref(pbuf2); + if (pbuf3) g_object_unref(pbuf3); + cr=linphone_gtk_create_chatroom(f_uri); + gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); + nbmsg=linphone_chat_room_get_unread_messages_count(cr); + if(nbmsg != 0){ + pbuf = create_unread_msg(); + gtk_list_store_set(store,&iter,FRIEND_CHAT,pbuf,-1); + g_object_unref(pbuf); + } escaped=g_markup_escape_text(uri,-1); gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1); g_free(escaped); - linphone_gtk_update_chat_picture(); //bi=linphone_friend_get_info(lf); /*if (bi!=NULL && bi->image_data!=NULL){ GdkPixbuf *pbuf= @@ -712,8 +880,8 @@ void linphone_gtk_show_friends(void){ ms_list_free(sorted); } -void linphone_gtk_show_contact(LinphoneFriend *lf){ - GtkWidget *w=linphone_gtk_create_window("contact"); +void linphone_gtk_show_contact(LinphoneFriend *lf, GtkWidget *parent){ + GtkWidget *w=linphone_gtk_create_window("contact", parent); char *uri; const char *name; const LinphoneAddress *f_uri=linphone_friend_get_address(lf); @@ -731,6 +899,7 @@ void linphone_gtk_show_contact(LinphoneFriend *lf){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")), linphone_friend_get_inc_subscribe_policy(lf)==LinphoneSPAccept); g_object_set_data(G_OBJECT(w),"friend_ref",(gpointer)lf); + gtk_widget_show(w); } @@ -741,9 +910,10 @@ void linphone_gtk_contact_cancel(GtkWidget *button){ 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"); - char *fixed_uri=NULL; + LinphoneFriend *lf2; gboolean show_presence=FALSE,allow_presence=FALSE; const gchar *name,*uri; + LinphoneAddress* friend_address; if (lf==NULL){ lf=linphone_friend_new(); if (linphone_gtk_get_ui_config_int("use_subscribe_notify",1)==1){ @@ -753,28 +923,36 @@ void linphone_gtk_contact_ok(GtkWidget *button){ linphone_friend_set_inc_subscribe_policy(lf,allow_presence ? LinphoneSPAccept : LinphoneSPDeny); linphone_friend_send_subscribe(lf,show_presence); } - name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); + + name = NULL; + if(gtk_entry_get_text_length(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))) != 0){ + name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); + } uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address"))); show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence"))); allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence"))); - 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 ; } - LinphoneAddress* friend_address = linphone_address_new(fixed_uri); - linphone_address_set_display_name(friend_address,name); - linphone_friend_set_addr(lf,friend_address); - ms_free(fixed_uri); - linphone_address_destroy(friend_address); + linphone_address_set_display_name(friend_address,name); + linphone_friend_set_name(lf,name); + linphone_friend_set_address(lf,friend_address); linphone_friend_send_subscribe(lf,show_presence); linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny); if (linphone_friend_in_list(lf)) { linphone_friend_done(lf); - }else{ - linphone_core_add_friend(linphone_gtk_get_core(),lf); + } else { + 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_core_add_friend(linphone_gtk_get_core(),lf); + } } + linphone_address_destroy(friend_address); linphone_gtk_show_friends(); gtk_widget_destroy(w); } @@ -786,6 +964,7 @@ static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){ gchar *text_label=NULL; gchar *edit_label=NULL; gchar *delete_label=NULL; + gchar *delete_hist_label=NULL; gchar *name=NULL; GtkTreeSelection *select; GtkTreeIter iter; @@ -808,6 +987,7 @@ static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){ text_label=g_strdup_printf(_("Send text to %s"),name); edit_label=g_strdup_printf(_("Edit contact '%s'"),name); delete_label=g_strdup_printf(_("Delete contact '%s'"),name); + delete_hist_label=g_strdup_printf(_("Delete chat history of '%s'"),name); g_free(name); } if (call_label){ @@ -847,6 +1027,15 @@ static GtkWidget *linphone_gtk_create_contact_menu(GtkWidget *contact_list){ g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_remove_contact,contact_list); } + if (delete_hist_label){ + menu_item=gtk_image_menu_item_new_with_label(delete_hist_label); + image=gtk_image_new_from_stock(GTK_STOCK_CLEAR,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image); + gtk_widget_show(image); + gtk_widget_show(menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); + g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_delete_history,contact_list); + } if (ssc && (sip_setup_context_get_capabilities(ssc) & SIP_SETUP_CAP_BUDDY_LOOKUP)) { gchar *tmp=g_strdup_printf(_("Add new contact from %s directory"),linphone_proxy_config_get_domain(cfg)); @@ -883,52 +1072,40 @@ gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event) } gint get_col_number_from_tree_view_column (GtkTreeViewColumn *col){ - GList *cols; - gint num; - g_return_val_if_fail ( col != NULL, -1 ); - g_return_val_if_fail ( col->tree_view != NULL, -1 ); - cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view)); - num = g_list_index(cols, (gpointer) col); - g_list_free(cols); + GList *cols; + gint num; + g_return_val_if_fail ( col != NULL, -1 ); + g_return_val_if_fail ( col->tree_view != NULL, -1 ); + cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view)); + num = g_list_index(cols, (gpointer) col); + g_list_free(cols); - return num; -} - -int longueur_list (GtkTreeView *tree_view){ - GtkTreeIter iter; - int i=0; - GtkTreeModel *model=gtk_tree_view_get_model(tree_view); - if (gtk_tree_model_get_iter_first(model,&iter)) { - do{ - i++; - }while(gtk_tree_model_iter_next(model,&iter)); - } - return i; + return num; } static gint tree_view_get_cell_from_pos(GtkTreeView *view, guint x, guint y){ GtkTreeViewColumn *col = NULL; GList *node, *columns; gint colx = 0; - gint coly = longueur_list(view); - gint height=0; - + GtkTreePath *path; + GtkTreeViewDropPosition pos; + g_return_val_if_fail ( view != NULL, 0 ); columns = gtk_tree_view_get_columns(view); - for (node = columns; node != NULL && col == NULL; node = node->next){ - GtkTreeViewColumn *checkcol = (GtkTreeViewColumn*) node->data; - gtk_tree_view_column_cell_get_size(checkcol,NULL,NULL,NULL,NULL,&height); - if (x >= colx && x < (colx + checkcol->width) && y < (height+2)*coly){ - col = checkcol; - gint num = get_col_number_from_tree_view_column(col); - return num; - } - else { - colx += checkcol->width; + gtk_tree_view_get_dest_row_at_pos(view,x,y,&path,&pos); + if(path != NULL){ + for (node = columns; node != NULL && col == NULL; node = node->next){ + GtkTreeViewColumn *checkcol = (GtkTreeViewColumn*) node->data; + if (x >= colx && x < (colx + checkcol->width)){ + col = checkcol; + return get_col_number_from_tree_view_column(col); + } else { + colx += checkcol->width; } - } - g_list_free(columns); + } + } + g_list_free(columns); return 0; } @@ -952,5 +1129,3 @@ void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf){ /*refresh the entire list*/ linphone_gtk_show_friends(); } - - diff --git a/gtk/in_call_frame.ui b/gtk/in_call_frame.ui new file mode 100644 index 000000000..5721081b6 --- /dev/null +++ b/gtk/in_call_frame.ui @@ -0,0 +1,426 @@ + + + + + + False + cursor + 0.5 + none + + + True + False + 12 + 12 + + + True + False + + + True + False + center + + + True + True + 0 + + + + + True + False + + + + + + False + False + 1 + + + + + False + + + True + False + gtk-dialog-authentication + 1 + + + False + False + 0 + + + + + True + False + gtk-apply + + + False + False + 1 + + + + + True + False + + + True + True + 2 + 2 + + + + + Set verified + True + True + True + + + + False + False + 3 + + + + + False + True + 2 + + + + + True + False + + + True + False + + + True + True + True + True + none + False + vertical + linphone-micro-enabled + + + False + False + 5 + 0 + + + + + True + False + + + False + False + 5 + 1 + + + + + True + False + 10 + 0 + + + + + True + False + + + True + True + True + True + Click here to set the speakers volume + none + False + vertical + linphone-speaker-enabled + + + False + False + 5 + 0 + + + + + True + False + + + False + False + 5 + 1 + + + + + True + False + 10 + 1 + + + + + False + False + 5 + 3 + + + + + False + spread + + + Answer + True + True + True + + + + False + False + 0 + + + + + Decline + True + True + True + + + + False + False + 1 + + + + + False + False + 4 + + + + + False + + + gtk-media-record + True + True + True + Record this call to an audio file + True + + + + False + False + 0 + + + + + True + False + True + char + + + True + True + 1 + + + + + False + False + 5 + + + + + True + False + 2 + 3 + True + + + Video + True + True + True + + + + + Pause + True + True + True + + + + 1 + 2 + + + + + Mute + True + True + True + + + + 2 + 3 + + + + + Transfer + True + True + True + + + 1 + 2 + + + + + Hang up + True + True + True + + + + 1 + 2 + 1 + 2 + + + + + Conference + True + True + True + + + 2 + 3 + 1 + 2 + + + + + False + False + 7 + 6 + + + + + + + + + True + False + True + + + True + False + In call + True + center + + + True + True + 0 + + + + + True + False + Duration + center + + + True + True + 1 + + + + + 90 + 10 + True + False + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK + Call quality rating + + + False + False + 2 + + + + + + diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 0a64a1041..9aaefff91 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -75,7 +75,7 @@ static GtkWidget *make_tab_header(int number){ return w; } -void update_tab_header(LinphoneCall *call,gboolean pause){ +void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){ GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *main_window=linphone_gtk_get_main_window(); GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch")); @@ -84,13 +84,13 @@ void update_tab_header(LinphoneCall *call,gboolean pause){ GtkWidget *i=NULL; GtkWidget *l; gchar *text; - + if(pause){ i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR); } else { i=create_pixmap ("startcall-small.png"); } - + text=g_strdup_printf(_("Call #%i"),call_index); l=gtk_label_new (text); gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0); @@ -98,6 +98,7 @@ void update_tab_header(LinphoneCall *call,gboolean pause){ gtk_notebook_set_tab_label(notebook,w,new_label); gtk_widget_show_all(new_label); + g_free(text); } static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){ @@ -181,7 +182,7 @@ static void conference_button_clicked(GtkWidget *button, gpointer call_ref){ gtk_widget_set_sensitive(button,FALSE); g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame",NULL); linphone_core_add_all_to_conference(linphone_gtk_get_core()); - + } void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){ @@ -255,15 +256,32 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ const LinphoneCallStats *vs=linphone_call_get_video_stats(call); const char *audio_media_connectivity = _("Direct or through server"); const char *video_media_connectivity = _("Direct or through server"); - gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call)); - gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), + const LinphoneCallParams *curparams=linphone_call_get_current_params(call); + gboolean has_video=linphone_call_params_video_enabled(curparams); + MSVideoSize size_received = linphone_call_params_get_received_video_size(curparams); + MSVideoSize size_sent = linphone_call_params_get_sent_video_size(curparams); + const char *rtp_profile = linphone_call_params_get_rtp_profile(curparams); + gchar *tmp = g_strdup_printf("%s", rtp_profile); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"rtp_profile")),tmp); + g_free(tmp); + tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), as->download_bandwidth,as->upload_bandwidth); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp); g_free(tmp); - if (has_video) + if (has_video){ + gchar *size_r=g_strdup_printf(_("%ix%i @ %f fps"),size_received.width,size_received.height, + linphone_call_params_get_received_framerate(curparams)); + gchar *size_s=g_strdup_printf(_("%ix%i @ %f fps"),size_sent.width,size_sent.height, + linphone_call_params_get_sent_framerate(curparams)); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s); + tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth); - else tmp=NULL; + g_free(size_r); + g_free(size_s); + } else { + tmp=NULL; + } gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp); if (tmp) g_free(tmp); if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) { @@ -272,7 +290,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ audio_media_connectivity = ice_state_to_string(as->ice_state); } gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity); - + if (has_video){ if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) { video_media_connectivity = upnp_state_to_string(vs->upnp_state); @@ -281,7 +299,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ } }else video_media_connectivity=NULL; gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity); - + if (as->round_trip_delay>0){ tmp=g_strdup_printf(_("%.3f seconds"),as->round_trip_delay); gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp); @@ -320,7 +338,7 @@ static void linphone_gtk_show_call_stats(LinphoneCall *call){ GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(w),"call_stats"); if (call_stats==NULL){ guint tid; - call_stats=linphone_gtk_create_window("call_statistics"); + call_stats=linphone_gtk_create_window("call_statistics", NULL); g_object_set_data(G_OBJECT(w),"call_stats",call_stats); g_object_set_data(G_OBJECT(call_stats),"call",linphone_call_ref(call)); tid=g_timeout_add(1000,(GSourceFunc)refresh_call_stats,call_stats); @@ -343,11 +361,15 @@ void linphone_gtk_enable_video_button(LinphoneCall *call, gboolean sensitive, gb } void linphone_gtk_create_in_call_view(LinphoneCall *call){ - GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame"); + GtkWidget *call_view=linphone_gtk_create_widget("in_call_frame"); GtkWidget *main_window=linphone_gtk_get_main_window (); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); static int call_index=1; int idx; + GtkWidget *transfer; + GtkWidget *conf; + GtkWidget *button; + GtkWidget *image; if (ms_list_size(linphone_core_get_calls(linphone_gtk_get_core()))==1){ /*this is the only call at this time */ @@ -368,19 +390,19 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(call_view,"incall_mute")),FALSE); - GtkWidget *transfer = linphone_gtk_get_widget(call_view,"transfer_button"); + transfer = linphone_gtk_get_widget(call_view,"transfer_button"); gtk_button_set_image(GTK_BUTTON(transfer),gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,GTK_ICON_SIZE_BUTTON)); g_signal_connect(G_OBJECT(transfer),"clicked",(GCallback)transfer_button_clicked,call); gtk_widget_hide(transfer); - GtkWidget *conf = linphone_gtk_get_widget(call_view,"conference_button"); + conf = linphone_gtk_get_widget(call_view,"conference_button"); gtk_button_set_image(GTK_BUTTON(conf),gtk_image_new_from_stock (GTK_STOCK_ADD,GTK_ICON_SIZE_BUTTON)); g_signal_connect(G_OBJECT(conf),"clicked",(GCallback)conference_button_clicked,call); gtk_widget_hide(conf); - GtkWidget *button=linphone_gtk_get_widget(call_view,"terminate_call"); - GtkWidget *image=create_pixmap("stopcall-small.png"); + button=linphone_gtk_get_widget(call_view,"terminate_call"); + image=create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png")); gtk_button_set_label(GTK_BUTTON(button),_("Hang up")); gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); @@ -400,9 +422,12 @@ static void video_button_clicked(GtkWidget *button, LinphoneCall *call){ void linphone_gtk_update_video_button(LinphoneCall *call){ GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *button; + GtkWidget *conf_frame; const LinphoneCallParams *params=linphone_call_get_current_params(call); gboolean has_video=linphone_call_params_video_enabled(params); + gboolean button_sensitive=FALSE; if (call_view==NULL) return; + button=linphone_gtk_get_widget(call_view,"video_button"); gtk_button_set_image(GTK_BUTTON(button), @@ -412,12 +437,20 @@ void linphone_gtk_update_video_button(LinphoneCall *call){ gtk_widget_set_sensitive(button,FALSE); return; } + switch(linphone_call_get_state(call)){ + case LinphoneCallStreamsRunning: + button_sensitive=!linphone_call_media_in_progress(call); + break; + default: + button_sensitive=FALSE; + break; + } + gtk_widget_set_sensitive(button,button_sensitive); if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"signal_connected"))==0){ g_signal_connect(G_OBJECT(button),"clicked",(GCallback)video_button_clicked,call); g_object_set_data(G_OBJECT(button),"signal_connected",GINT_TO_POINTER(1)); } - GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame"); - gtk_widget_set_sensitive(button,linphone_call_get_state(call)==LinphoneCallStreamsRunning); + conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame"); if(conf_frame!=NULL){ gtk_widget_set_sensitive(button,FALSE); } @@ -427,12 +460,10 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){ GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call); GtkWidget *main_window=linphone_gtk_get_main_window (); GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); int idx; g_return_if_fail(w!=NULL); idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w); - gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx); - gtk_widget_destroy(w); if (in_conf){ linphone_gtk_unset_from_conference(call); } @@ -444,17 +475,18 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){ /*show the conference*/ gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb), g_object_get_data(G_OBJECT(main_window),"conf_frame"))); - }else gtk_notebook_set_current_page(GTK_NOTEBOOK(nb), 0); + }else gtk_notebook_prev_page(GTK_NOTEBOOK(nb)); }else{ /*show the active call*/ - gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb), - linphone_call_get_user_pointer(call))); + gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb), linphone_call_get_user_pointer(call))); } + gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx); + gtk_widget_destroy(w); } static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){ const char *displayname=NULL; - const char *id; + char *id; char *uri_label; displayname=linphone_address_get_display_name(from); id=linphone_address_as_string_uri_only(from); @@ -466,6 +498,7 @@ static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress * uri_label=g_markup_printf_escaped("%s\n",id); gtk_label_set_markup(GTK_LABEL(label),uri_label); g_free(uri_label); + ms_free(id); } void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){ @@ -477,7 +510,7 @@ void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){ gtk_label_set_markup(GTK_LABEL(status),_("Calling...")); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); + gtk_label_set_text(GTK_LABEL(duration),_("00:00:00")); linphone_gtk_in_call_set_animation_spinner(callview); } @@ -557,19 +590,12 @@ static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){ return TRUE; } -typedef struct _volume_ctx{ - GtkWidget *widget; - get_volume_t get_volume; - void *data; - float last_value; -}volume_ctx_t; - -#define UNSIGNIFICANT_VOLUME (-26) +#define UNSIGNIFICANT_VOLUME (-23) #define SMOOTH 0.15 static gboolean update_audio_meter(volume_ctx_t *ctx){ float volume_db=ctx->get_volume(ctx->data); - float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME+3.0); + float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME-3.0); if (frac<0) frac=0; if (frac>1.0) frac=1.0; if (fraclast_value){ @@ -581,10 +607,12 @@ static gboolean update_audio_meter(volume_ctx_t *ctx){ return TRUE; } -static void on_audio_meter_destroy(guint task_id){ +static void on_audio_meter_destroy(GtkWidget *w, gpointer data){ + guint task_id = GPOINTER_TO_INT(data); g_source_remove(task_id); } + void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data){ guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id")); if (task_id==0){ @@ -595,7 +623,8 @@ void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void * ctx->last_value=0; g_object_set_data_full(G_OBJECT(w),"ctx",ctx,g_free); task_id=g_timeout_add(50,(GSourceFunc)update_audio_meter,ctx); - g_object_set_data_full(G_OBJECT(w),"task_id",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_meter_destroy); + g_object_set_data(G_OBJECT(w), "task_id", GINT_TO_POINTER(task_id)); + g_signal_connect(G_OBJECT(w), "destroy", (GCallback)on_audio_meter_destroy, GINT_TO_POINTER(task_id)); } } @@ -604,25 +633,59 @@ void linphone_gtk_uninit_audio_meter(GtkWidget *w){ if (task_id!=0){ g_object_set_data(G_OBJECT(w),"ctx",NULL); g_object_set_data(G_OBJECT(w),"task_id",NULL); + g_source_remove(task_id); } } +typedef enum { VOLUME_CTRL_PLAYBACK, VOLUME_CTRL_RECORD } VolumeControlType; + +static void volume_control_value_changed(GtkScaleButton *button, gdouble value, gpointer user_data) { + LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(button), "call"); + VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(button), "type"); + + if(type == VOLUME_CTRL_PLAYBACK) { + linphone_call_set_speaker_volume_gain(call, value); + } else if(type == VOLUME_CTRL_RECORD) { + linphone_call_set_microphone_volume_gain(call, value); + } +} + +static void volume_control_button_update_value(GtkWidget *widget) { + LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(widget), "call"); + VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(widget), "type"); + + if(type == VOLUME_CTRL_PLAYBACK) { + gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_speaker_volume_gain(call)); + } else if(type == VOLUME_CTRL_RECORD) { + gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_microphone_volume_gain(call)); + } +} + +static gboolean volume_control_button_enter_event_handler(GtkWidget *widget) { + volume_control_button_update_value(widget); + return FALSE; +} + +static void volume_control_init(GtkWidget *vol_ctrl, VolumeControlType type, LinphoneCall *call) { + g_object_set_data(G_OBJECT(vol_ctrl), "call", call); + g_object_set_data(G_OBJECT(vol_ctrl), "type", (gpointer)type); + g_signal_connect(G_OBJECT(vol_ctrl), "enter-notify-event", G_CALLBACK(volume_control_button_enter_event_handler), NULL); + g_signal_connect(G_OBJECT(vol_ctrl), "value-changed", G_CALLBACK(volume_control_value_changed), NULL); +} + void linphone_gtk_in_call_view_enable_audio_view(LinphoneCall *call, gboolean val){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *audio_view=linphone_gtk_get_widget(callview,"incall_audioview"); - GtkWidget *mic=linphone_gtk_get_widget(callview,"incall_mic_icon"); - GtkWidget *spk=linphone_gtk_get_widget(callview,"incall_spk_icon"); GtkWidget *mic_level=linphone_gtk_get_widget(callview,"mic_audiolevel"); GtkWidget *spk_level=linphone_gtk_get_widget(callview,"spk_audiolevel"); - GdkPixbuf *pbuf; + GtkWidget *spk_vol_ctrl = linphone_gtk_get_widget(callview, "incall_spk_vol_ctrl_button"); + GtkWidget *mic_vol_ctrl = linphone_gtk_get_widget(callview, "incall_mic_vol_ctrl_button"); - gtk_image_set_from_pixbuf(GTK_IMAGE(mic),(pbuf=create_pixbuf("mic_active.png"))); - g_object_unref(pbuf); if (val){ - gtk_image_set_from_pixbuf(GTK_IMAGE(spk),(pbuf=create_pixbuf("speaker.png"))); - g_object_unref(pbuf); linphone_gtk_init_audio_meter(mic_level,(get_volume_t)linphone_call_get_record_volume,call); linphone_gtk_init_audio_meter(spk_level,(get_volume_t)linphone_call_get_play_volume,call); + volume_control_init(spk_vol_ctrl, VOLUME_CTRL_PLAYBACK, call); + volume_control_init(mic_vol_ctrl, VOLUME_CTRL_RECORD, call); gtk_widget_show_all(audio_view); }else{ linphone_gtk_uninit_audio_meter(mic_level); @@ -653,6 +716,12 @@ void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){ gtk_widget_hide(status_icon); gtk_widget_hide(verify_button); break; + case LinphoneMediaEncryptionDTLS: + gtk_widget_show_all(encryption_box); + gtk_label_set_markup(GTK_LABEL(label),_("Secured by DTLS")); + gtk_widget_hide(status_icon); + gtk_widget_hide(verify_button); + break; case LinphoneMediaEncryptionZRTP: { gchar *text=g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"),linphone_call_get_authentication_token(call)); @@ -670,29 +739,37 @@ void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){ } } +char *linphone_gtk_address(const LinphoneAddress *addr){ + const char *displayname=linphone_address_get_display_name(addr); + if (!displayname) return linphone_address_as_string_uri_only(addr); + return ms_strdup(displayname); +} + void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats"); + linphone_gtk_in_call_show_video(call); + display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - + gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("In call")); - + gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf); gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf); - gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); + gtk_label_set_text(GTK_LABEL(duration),_("00:00:00")); linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PLAY,TRUE); - update_tab_header(call,FALSE); + linphone_gtk_call_update_tab_header(call,FALSE); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE); - + if (taskid==0){ taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call); g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid)); @@ -702,9 +779,11 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ if (in_conf){ linphone_gtk_set_in_conference(call); gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),FALSE); + gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"hold_call"),FALSE); }else{ linphone_gtk_unset_from_conference(call); /*in case it was previously*/ gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),TRUE); + gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"hold_call"),TRUE); } gtk_widget_show_all(linphone_gtk_get_widget(callview,"buttons_panel")); if (!in_conf) gtk_widget_show_all(linphone_gtk_get_widget(callview,"record_hbox")); @@ -717,7 +796,7 @@ void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){ GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),_("Paused call")); - + linphone_gtk_in_call_show_video(call); linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PAUSE,TRUE); } @@ -729,7 +808,7 @@ void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){ int seconds=duration%60; int minutes=(duration/60)%60; int hours=duration/3600; - snprintf(tmp,sizeof(tmp)-1,_("%02i::%02i::%02i"),hours,minutes,seconds); + snprintf(tmp,sizeof(tmp)-1,"%02i::%02i::%02i",hours,minutes,seconds); gtk_label_set_text(GTK_LABEL(duration_label),tmp); } @@ -740,11 +819,17 @@ static gboolean in_call_view_terminated(LinphoneCall *call){ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); - GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); - guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); - - if ((callview==NULL) || (status==NULL)) return; + GtkWidget *status; + GtkWidget *video_window; + gboolean in_conf; + guint taskid; + if(callview==NULL) return; + video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); + status=linphone_gtk_get_widget(callview,"in_call_status"); + taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); + in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); + if (video_window) gtk_widget_destroy(video_window); + if (status==NULL) return; if (error_msg==NULL) gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); else{ @@ -759,6 +844,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m gtk_widget_hide(linphone_gtk_get_widget(callview,"record_hbox")); gtk_widget_hide(linphone_gtk_get_widget(callview,"buttons_panel")); gtk_widget_hide(linphone_gtk_get_widget(callview,"incall_audioview")); + gtk_widget_hide(linphone_gtk_get_widget(callview,"quality_indicator")); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button(call,FALSE,TRUE); @@ -792,22 +878,11 @@ void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCa } void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){ + const char *icon_name = active ? "linphone-micro-muted" : "linphone-micro-enabled"; + GtkWidget *image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON); + gtk_button_set_image(button, image); + gtk_widget_show(image); g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active)); - if (active){ - GtkWidget *image=create_pixmap("mic_muted.png"); - /*gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));*/ - if (image!=NULL) { - gtk_button_set_image(GTK_BUTTON(button),image); - gtk_widget_show(image); - } - }else{ - GtkWidget *image=create_pixmap("mic_active.png"); - /*gtk_button_set_label(GTK_BUTTON(button),_("Mute"));*/ - if (image!=NULL) { - gtk_button_set_image(GTK_BUTTON(button),image); - gtk_widget_show(image); - } - } } void linphone_gtk_mute_clicked(GtkButton *button){ @@ -844,7 +919,7 @@ void linphone_gtk_draw_hold_button(GtkButton *button, gboolean active){ void linphone_gtk_hold_clicked(GtkButton *button){ int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active")); LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL); - update_tab_header(call,active); + linphone_gtk_call_update_tab_header(call,active); if (!call) return; if(!active) { @@ -860,7 +935,7 @@ void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gbo GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call); GtkWidget *button; g_return_if_fail(callview!=NULL); - update_tab_header(call,!holdon); + linphone_gtk_call_update_tab_header(call,!holdon); button=linphone_gtk_get_widget(callview,"hold_call"); gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); gtk_widget_set_visible(GTK_WIDGET(button),sensitive); @@ -881,8 +956,9 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){ GtkWidget *callview; GtkWidget *label; if (call){ + const LinphoneCallParams *params; callview=(GtkWidget*)linphone_call_get_user_pointer (call); - const LinphoneCallParams *params=linphone_call_get_current_params(call); + params=linphone_call_get_current_params(call); filepath=linphone_call_params_get_record_file(params); label=linphone_gtk_get_widget(callview,"record_status"); }else if (is_conf){ @@ -899,7 +975,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){ return; } message=g_strdup_printf(_("Recording into\n%s %s"),filepath,active ? "" : _("(Paused)")); - + if (active){ if (call) linphone_call_start_recording(call); @@ -910,7 +986,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){ linphone_call_stop_recording(call); else linphone_core_stop_conference_recording(lc); - + } gtk_label_set_markup(GTK_LABEL(label),message); g_free(message); diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 6b5376762..86c957531 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -1,6 +1,6 @@ - + False @@ -8,8 +8,11 @@ True False + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK 0.5 none + + True @@ -26,7 +29,7 @@ True - D + D True True True @@ -42,7 +45,7 @@ - # + # True True True @@ -58,7 +61,7 @@ - 0 + 0 True True True @@ -74,7 +77,7 @@ - * + * True True True @@ -88,7 +91,7 @@ - C + C True True True @@ -104,7 +107,7 @@ - 9 + 9 True True True @@ -120,7 +123,7 @@ - 8 + 8 True True True @@ -136,7 +139,7 @@ - 7 + 7 True True True @@ -150,7 +153,7 @@ - B + B True True True @@ -166,7 +169,7 @@ - 6 + 6 True True True @@ -182,7 +185,7 @@ - 5 + 5 True True True @@ -198,7 +201,7 @@ - 4 + 4 True True True @@ -212,7 +215,7 @@ - A + A True True True @@ -226,7 +229,7 @@ - 3 + 3 True True True @@ -240,7 +243,7 @@ - 2 + 2 True True True @@ -254,7 +257,7 @@ - 1 + 1 40 40 True diff --git a/gtk/ldap.ui b/gtk/ldap.ui new file mode 100644 index 000000000..a5df241d1 --- /dev/null +++ b/gtk/ldap.ui @@ -0,0 +1,669 @@ + + + + + + False + LDAP Settings + + + True + False + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + 1 + Server address: + + + + + True + False + Authentication method: + + + 1 + 2 + + + + + True + False + Username: + + + 2 + 3 + + + + + True + False + Password: + + + 3 + 4 + + + + + Use TLS Connection + True + False + True + False + Not yet available + False + True + + + 1 + 2 + 4 + 5 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + True + False + liststore2 + 0 + + + + 0 + + + + + 1 + 2 + 1 + 2 + + + + + + + + + + + + True + False + <b>Connection</b> + True + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 3 + 2 + + + True + False + Bind DN + + + + + True + False + Authname + + + 1 + 2 + + + + + True + False + Realm + + + 2 + 3 + + + + + True + True + + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + + + + + True + False + <b>SASL</b> + True + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + Base object: + + + + + True + False + Filter (%s for name): + + + 1 + 2 + + + + + True + False + Name Attribute: + + + 2 + 3 + + + + + True + False + SIP address attribute: + + + 3 + 4 + + + + + True + False + Attributes to query: + + + 4 + 5 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 4 + 5 + + + + + + + + + True + False + <b>Search</b> + True + + + + + True + True + 2 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 3 + 2 + + + True + False + Timeout for search: + + + + + True + False + Max results: + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + timeout_adjustment + + + 1 + 2 + + + + + True + True + 3 + + True + False + False + True + True + result_adjustment + True + + + 1 + 2 + 1 + 2 + + + + + Follow Aliases + True + True + False + False + True + + + 1 + 2 + 2 + 3 + + + + + + + + + + + + True + False + <b>Miscellaneous</b> + True + + + + + True + True + 3 + + + + + True + False + 2 + + + + + + gtk-apply + True + True + True + False + True + + + + False + False + end + 1 + + + + + gtk-cancel + True + True + True + False + True + + + + False + False + end + 2 + + + + + False + True + 4 + + + + + + + + + + + + + ANONYMOUS + + + SIMPLE + + + DIGEST-MD5 + + + NTLM + + + + + 1 + 100 + 50 + 1 + 10 + + + 1 + 100 + 10 + 1 + 10 + + diff --git a/gtk/linphone.h b/gtk/linphone.h index f9597849d..618f1590e 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -28,14 +28,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "linphonecore.h" +#include "ldap/ldapprovider.h" + #ifdef ENABLE_NLS + +#ifdef _MSC_VER +// prevent libintl.h from re-defining fprintf and vfprintf +#ifndef fprintf +#define fprintf fprintf +#endif +#ifndef vfprintf +#define vfprintf vfprintf +#endif +#define _GL_STDIO_H +#endif + # include # undef _ -# define _(String) gettext (String) +# define _(String) dgettext (GETTEXT_PACKAGE,String) #else # define _(String) (String) # define ngettext(singular,plural,number) ((number>1) ? (plural) : (singular) ) -#endif +#endif // ENABLE_NLS #undef N_ #define N_(str) (str) @@ -46,6 +60,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define LINPHONE_VERSION LINPHONE_VERSION_DATE #endif +#define LINPHONE_ICON "linphone.png" + +enum { + COMPLETION_HISTORY, + COMPLETION_LDAP +}; + +typedef float (*get_volume_t)(void *data); + +typedef struct _volume_ctx{ + GtkWidget *widget; + get_volume_t get_volume; + void *data; + float last_value; +}volume_ctx_t; + +typedef enum { + CAP_IGNORE, + CAP_PLAYBACK, + CAP_CAPTURE +}DeviceCap; + +enum { + START_LINPHONE, + START_AUDIO_ASSISTANT, + START_LINPHONE_WITH_CALL +}; + GdkPixbuf * create_pixbuf(const gchar *filename); GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename); void add_pixmap_directory(const gchar *directory); @@ -53,101 +95,245 @@ GtkWidget*create_pixmap(const gchar *filename); GtkWidget *_gtk_image_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio); GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint w, gint h, gboolean preserve_ratio); -void linphone_gtk_destroy_window(GtkWidget *window); -GtkWidget *linphone_gtk_create_window(const char *window_name); -GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name); -GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name); +LINPHONE_PUBLIC void linphone_gtk_destroy_window(GtkWidget *window); +LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent); +LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name); +LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_widget(const char* widget_name); -void linphone_gtk_show_assistant(void); -void linphone_gtk_close_assistant(void); +char *linphone_gtk_message_storage_get_db_file(const char *filename); +LINPHONE_PUBLIC void linphone_gtk_show_assistant(GtkWidget* parent); +LINPHONE_PUBLIC void linphone_gtk_close_assistant(void); -LinphoneCore *linphone_gtk_get_core(void); -GtkWidget *linphone_gtk_get_main_window(); -void linphone_gtk_display_something(GtkMessageType type,const gchar *message); -void linphone_gtk_start_call(GtkWidget *button); -void linphone_gtk_call_terminated(); -void linphone_gtk_show_friends(void); -void linphone_gtk_show_contact(LinphoneFriend *lf); -void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss); -void linphone_gtk_show_parameters(void); -void linphone_gtk_fill_soundcards(GtkWidget *pb); -void linphone_gtk_fill_webcams(GtkWidget *pb); -void linphone_gtk_load_identities(void); -LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); -void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); -void linphone_gtk_call_log_update(GtkWidget *w); -void linphone_gtk_create_log_window(void); -void linphone_gtk_log_show(void); -void linphone_gtk_show_main_window(void); -void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args); -void linphone_gtk_destroy_log_window(void); -void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); -gboolean linphone_gtk_check_logs(); -void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); -const gchar *linphone_gtk_get_ui_config(const char *key, const char *def); -int linphone_gtk_get_ui_config_int(const char *key, int def); -void linphone_gtk_set_ui_config_int(const char *key , int val); -void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); +LINPHONE_PUBLIC LinphoneCore *linphone_gtk_get_core(void); +LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_main_window(); +LINPHONE_PUBLIC void linphone_gtk_display_something(GtkMessageType type, const gchar *message); +LINPHONE_PUBLIC void linphone_gtk_call_terminated(); +LINPHONE_PUBLIC void linphone_gtk_set_my_presence(LinphoneOnlineStatus ss); +LINPHONE_PUBLIC void linphone_gtk_show_parameters(void); +LINPHONE_PUBLIC void linphone_gtk_fill_soundcards(GtkWidget *pb); +LINPHONE_PUBLIC void linphone_gtk_fill_webcams(GtkWidget *pb); +LINPHONE_PUBLIC void linphone_gtk_load_identities(void); +LINPHONE_PUBLIC void linphone_gtk_call_log_update(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_create_log_window(void); +LINPHONE_PUBLIC void linphone_gtk_log_show(void); +LINPHONE_PUBLIC void linphone_gtk_show_main_window(void); +LINPHONE_PUBLIC void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args); +LINPHONE_PUBLIC void linphone_gtk_destroy_log_window(void); +LINPHONE_PUBLIC void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); +LINPHONE_PUBLIC gboolean linphone_gtk_check_logs(); +LINPHONE_PUBLIC const gchar *linphone_gtk_get_ui_config(const char *key, const char *def); +LINPHONE_PUBLIC int linphone_gtk_get_ui_config_int(const char *key, int def); +LINPHONE_PUBLIC void linphone_gtk_set_ui_config_int(const char *key, int val); +LINPHONE_PUBLIC void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); -void linphone_gtk_open_browser(const char *url); -void linphone_gtk_check_for_new_version(void); -const char *linphone_gtk_get_lang(const char *config_file); -void linphone_gtk_set_lang(const char *code); -SipSetupContext* linphone_gtk_get_default_sip_setup_context(void); -GtkWidget * linphone_gtk_show_buddy_lookup_window(SipSetupContext *ctx); -void linphone_gtk_buddy_lookup_set_keyword(GtkWidget *w, const char *kw); -void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, const char *purpose, float progress); +LINPHONE_PUBLIC LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); +LINPHONE_PUBLIC void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); +LINPHONE_PUBLIC int linphone_gtk_is_ldap_supported(void); -void linphone_gtk_terminate_call(GtkWidget *button); -void update_tab_header(LinphoneCall *call,gboolean pause); +LINPHONE_PUBLIC void linphone_gtk_open_browser(const char *url); +LINPHONE_PUBLIC void linphone_gtk_check_for_new_version(void); +LINPHONE_PUBLIC const char *linphone_gtk_get_lang(const char *config_file); +LINPHONE_PUBLIC void linphone_gtk_set_lang(const char *code); +LINPHONE_PUBLIC SipSetupContext* linphone_gtk_get_default_sip_setup_context(void); +LINPHONE_PUBLIC GtkWidget * linphone_gtk_show_buddy_lookup_window(SipSetupContext *ctx); +LINPHONE_PUBLIC void linphone_gtk_buddy_lookup_set_keyword(GtkWidget *w, const char *kw); +LINPHONE_PUBLIC void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, const char *purpose, float progress); +LINPHONE_PUBLIC void linphone_gtk_terminate_call(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_call_update_tab_header(LinphoneCall *call, gboolean pause); +LINPHONE_PUBLIC void linphone_gtk_show_directory_search(void); +LINPHONE_PUBLIC void linphone_gtk_status_icon_set_blinking(gboolean val); +LINPHONE_PUBLIC void linphone_gtk_notify(LinphoneCall *call, const char *msg); -void linphone_gtk_show_directory_search(void); -void linphone_gtk_status_icon_set_blinking(gboolean val); -void linphone_gtk_notify(LinphoneCall *call, const char *msg); -LinphoneChatRoom *linphone_gtk_start_chat(GtkTreeView* t); -void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri,GtkWidget *chat_view); -void linphone_gtk_send_text(); -GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with); -void linphone_gtk_create_chat_picture(gboolean active); -void linphone_gtk_update_chat_picture(); -void linphone_gtk_chat_set_conversation(const LinphoneAddress *uri,gchar *conversation); -gchar * linphone_gtk_chat_get_conversation(const LinphoneAddress *uri); +LINPHONE_PUBLIC void linphone_gtk_load_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *uri, GtkWidget *chat_view); +LINPHONE_PUBLIC void linphone_gtk_send_text(); +LINPHONE_PUBLIC GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); +LINPHONE_PUBLIC void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); +LINPHONE_PUBLIC void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); + +LINPHONE_PUBLIC void linphone_gtk_friend_list_update_chat_picture(); +LINPHONE_PUBLIC void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); +LINPHONE_PUBLIC gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr); +LINPHONE_PUBLIC const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void); +LINPHONE_PUBLIC void linphone_gtk_notebook_tab_select(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data); +LINPHONE_PUBLIC void linphone_gtk_show_friends(void); +LINPHONE_PUBLIC void linphone_gtk_show_contact(LinphoneFriend *lf, GtkWidget *parent); +LINPHONE_PUBLIC void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); /*functions controlling the different views*/ -gboolean linphone_gtk_use_in_call_view(); -LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf); -void linphone_gtk_create_in_call_view(LinphoneCall *call); -void linphone_gtk_in_call_view_set_calling(LinphoneCall *call); -void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call); -void linphone_gtk_in_call_view_update_duration(LinphoneCall *call); -void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg); -void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call); -void linphone_gtk_in_call_view_set_paused(LinphoneCall *call); -void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate); -void linphone_gtk_mute_clicked(GtkButton *button); -void transfer_button_clicked(GtkWidget *button, gpointer call_ref); -void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive); -void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon); -void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gboolean value); -void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value); -void linphone_gtk_set_in_conference(LinphoneCall *call); -void linphone_gtk_unset_from_conference(LinphoneCall *call); -void linphone_gtk_terminate_conference_participant(LinphoneCall *call); -void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call); -void linphone_gtk_update_video_button(LinphoneCall *call); -typedef float (*get_volume_t)(void *data); -void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data); +LINPHONE_PUBLIC gboolean linphone_gtk_use_in_call_view(); +LINPHONE_PUBLIC LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf); +LINPHONE_PUBLIC void linphone_gtk_create_in_call_view(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_calling(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_update_duration(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_paused(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call, LinphoneCallState cstate); +LINPHONE_PUBLIC void linphone_gtk_mute_clicked(GtkButton *button); +LINPHONE_PUBLIC void transfer_button_clicked(GtkWidget *button, gpointer call_ref); +LINPHONE_PUBLIC void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive); +LINPHONE_PUBLIC void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon); +LINPHONE_PUBLIC void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gboolean value); +LINPHONE_PUBLIC void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value); +LINPHONE_PUBLIC void linphone_gtk_set_in_conference(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_unset_from_conference(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_terminate_conference_participant(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_update_video_button(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data); +LINPHONE_PUBLIC void linphone_gtk_uninit_audio_meter(GtkWidget *w); -void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg); -void linphone_gtk_exit_login_frame(void); -void linphone_gtk_set_ui_config(const char *key, const char *value); +LINPHONE_PUBLIC void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login); +LINPHONE_PUBLIC void linphone_gtk_exit_login_frame(void); +LINPHONE_PUBLIC void linphone_gtk_set_ui_config(const char *key, const char *value); -void linphone_gtk_log_uninit(); +LINPHONE_PUBLIC void linphone_gtk_log_uninit(); -bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call); -void linphone_gtk_uninit_instance(void); -void linphone_gtk_monitor_usb(void); -void linphone_gtk_unmonitor_usb(void); +LINPHONE_PUBLIC bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call); +LINPHONE_PUBLIC void linphone_gtk_uninit_instance(void); +LINPHONE_PUBLIC void linphone_gtk_monitor_usb(void); +LINPHONE_PUBLIC void linphone_gtk_unmonitor_usb(void); -gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); +LINPHONE_PUBLIC void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap); +LINPHONE_PUBLIC gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); +LINPHONE_PUBLIC void linphone_gtk_schedule_restart(void); +LINPHONE_PUBLIC void linphone_gtk_show_audio_assistant(void); +LINPHONE_PUBLIC gboolean linphone_gtk_get_audio_assistant_option(void); + +LINPHONE_PUBLIC void linphone_gtk_set_configuration_uri(void); +LINPHONE_PUBLIC GtkWidget * linphone_gtk_show_config_fetching(void); +LINPHONE_PUBLIC void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); +LINPHONE_PUBLIC const char *linphone_gtk_get_sound_path(const char *file); +LINPHONE_PUBLIC void linphone_gtk_in_call_show_video(LinphoneCall *call); +LINPHONE_PUBLIC char *linphone_gtk_address(const LinphoneAddress *addr);/*return human readable identifier for a LinphoneAddress */ +LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_camera_preview_window(void); + +LINPHONE_PUBLIC void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame); + +LINPHONE_PUBLIC gboolean linphone_gtk_call_log_reset_missed_call(GtkWidget *w, GdkEvent *event, gpointer user_data); +LINPHONE_PUBLIC void linphone_gtk_history_row_activated(GtkWidget *treeview); +LINPHONE_PUBLIC void linphone_gtk_history_row_selected(GtkWidget *treeview); +LINPHONE_PUBLIC void linphone_gtk_clear_call_logs(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_add_contact(void); +LINPHONE_PUBLIC void linphone_gtk_contact_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data); +LINPHONE_PUBLIC void linphone_gtk_contact_clicked(GtkTreeView *treeview); +LINPHONE_PUBLIC void linphone_gtk_add_button_clicked(void); +LINPHONE_PUBLIC void linphone_gtk_edit_button_clicked(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_remove_button_clicked(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_my_presence_clicked(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_directory_search_button_clicked(GtkWidget *button); +LINPHONE_PUBLIC gboolean linphone_gtk_popup_contact_menu(GtkWidget *list, GdkEventButton *event); +LINPHONE_PUBLIC gboolean linphone_gtk_contact_list_button_pressed(GtkWidget *widget, GdkEventButton *event); +LINPHONE_PUBLIC void linphone_gtk_auth_token_verified_clicked(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_hold_clicked(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_record_call_toggled(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_log_hide(void); +LINPHONE_PUBLIC void linphone_gtk_log_scroll_to_end(GtkToggleButton *button); +LINPHONE_PUBLIC void linphone_gtk_log_clear(void); +LINPHONE_PUBLIC void linphone_gtk_logout_clicked(void); + +LINPHONE_PUBLIC void linphone_gtk_about_response(GtkDialog *dialog, gint id); +LINPHONE_PUBLIC void linphone_gtk_show_about(void); +LINPHONE_PUBLIC void linphone_gtk_start_call(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_start_chat(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_uri_bar_activate(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_terminate_call(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_decline_clicked(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_answer_clicked(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_enable_video(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_enable_self_view(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_used_identity_changed(GtkWidget *w); +LINPHONE_PUBLIC void on_proxy_refresh_button_clicked(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_link_to_website(GtkWidget *item); +LINPHONE_PUBLIC void linphone_gtk_options_activate(GtkWidget *item); +LINPHONE_PUBLIC void linphone_gtk_create_keypad(GtkWidget *button); + +LINPHONE_PUBLIC void linphone_gtk_keyword_changed(GtkEditable *e); +LINPHONE_PUBLIC void linphone_gtk_buddy_lookup_contact_activated(GtkWidget *treeview); +LINPHONE_PUBLIC void linphone_gtk_add_buddy_from_database(GtkWidget *button); +LINPHONE_PUBLIC gboolean linphone_gtk_call_log_button_pressed(GtkWidget *widget, GdkEventButton *event); +LINPHONE_PUBLIC void linphone_gtk_call_statistics_closed(GtkWidget *call_stats); +LINPHONE_PUBLIC void linphone_gtk_config_uri_cancel(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_config_uri_changed(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_contact_cancel(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_contact_ok(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_dscp_edit(void); +LINPHONE_PUBLIC void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id); +LINPHONE_PUBLIC void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata); +LINPHONE_PUBLIC void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata); +LINPHONE_PUBLIC void linphone_gtk_ldap_save(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_ldap_reset(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_parameters_destroyed(GtkWidget *pb); +LINPHONE_PUBLIC void linphone_gtk_mtu_set(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_mtu_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_use_sip_info_dtmf_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_ipv6_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_disabled_udp_port_toggle(GtkCheckButton *button); +LINPHONE_PUBLIC void linphone_gtk_random_udp_port_toggle(GtkCheckButton *button); +LINPHONE_PUBLIC void linphone_gtk_udp_port_value_changed(GtkSpinButton *button); +LINPHONE_PUBLIC void linphone_gtk_disabled_tcp_port_toggle(GtkCheckButton *button); +LINPHONE_PUBLIC void linphone_gtk_random_tcp_port_toggle(GtkCheckButton *button); +LINPHONE_PUBLIC void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button); +LINPHONE_PUBLIC void linphone_gtk_min_audio_port_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_max_audio_port_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_fixed_audio_port_toggle(void); +LINPHONE_PUBLIC void linphone_gtk_min_video_port_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_max_video_port_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_fixed_video_port_toggle(void); +LINPHONE_PUBLIC void linphone_gtk_set_media_encryption_mandatory(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_edit_tunnel(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_no_firewall_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_use_nat_address_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_use_stun_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_use_ice_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_use_upnp_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_nat_address_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_stun_server_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_ring_file_set(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_play_ring_file(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_alsa_special_device_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_capture_device_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_ring_device_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_playback_device_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_echo_cancelation_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_cam_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_video_size_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_video_renderer_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_video_preset_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_show_camera_preview_clicked(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_update_my_contact(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_add_proxy(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_show_sip_accounts(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_edit_proxy(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_remove_proxy(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_clear_passwords(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_audio_codec_up(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_audio_codec_down(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_audio_codec_enable(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_audio_codec_disable(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_video_codec_up(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_video_codec_down(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_video_codec_enable(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_video_codec_disable(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_video_framerate_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_upload_bw_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_download_bw_changed(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_adaptive_rate_control_toggled(GtkToggleButton *button); +LINPHONE_PUBLIC void linphone_gtk_lang_changed(GtkComboBox *combo); +LINPHONE_PUBLIC void linphone_gtk_ui_level_toggled(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_show_ldap_config(GtkWidget* button); +LINPHONE_PUBLIC void linphone_gtk_parameters_closed(GtkWidget *button); +LINPHONE_PUBLIC void linphone_gtk_password_ok(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_password_cancel(GtkWidget *w); +LINPHONE_PUBLIC void linphone_gtk_proxy_ok(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_proxy_cancel(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_proxy_address_changed(GtkEditable *editable); +LINPHONE_PUBLIC void linphone_gtk_proxy_transport_changed(GtkWidget *combo); +LINPHONE_PUBLIC void linphone_gtk_tunnel_ok(GtkButton *button); +LINPHONE_PUBLIC void linphone_gtk_notebook_current_page_changed(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data); +LINPHONE_PUBLIC void linphone_gtk_reload_sound_devices(void); +LINPHONE_PUBLIC void linphone_gtk_reload_video_devices(void); diff --git a/gtk/logging.c b/gtk/logging.c index 15bef85e0..00d40227a 100644 --- a/gtk/logging.c +++ b/gtk/logging.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #endif +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" extern gchar *linphone_logfile; @@ -163,7 +164,6 @@ static FILE *linphone_gtk_log_init() static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg) { - time_t now; FILE *outlog; outlog = linphone_gtk_log_init(); @@ -175,12 +175,11 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg) logfile_date_format in the GtkUi section of the config file, but it defaults to something compact, but yet readable. */ const char *lname="undef"; - char date[256]; /* Convert level constant to text */ switch(lev){ case ORTP_DEBUG: - lname="debug"; + lname="debug "; break; case ORTP_MESSAGE: lname="message"; @@ -189,35 +188,28 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg) lname="warning"; break; case ORTP_ERROR: - lname="error"; + lname="error "; break; case ORTP_FATAL: - lname="fatal"; + lname="fatal "; break; default: - lname="undef"; + lname="undef "; break; } - /* Get current time and format it properly */ - now = time(NULL); - strftime(date, sizeof(date), dateformat, localtime(&now)); - /* Now print out the message to the logfile. We don't flush, - maybe we should do to ensure that we have all the messages in - case of a crash (which is one of the main reasons we have a - log facility in the first place). */ - fprintf(outlog, "[%s] [%s] %s\n", date, lname, msg); + fprintf(outlog, "[%s] %s\n", lname, msg); fflush(outlog); } } -void linphone_gtk_log_hide(){ +void linphone_gtk_log_hide(void){ if (log_window) gtk_widget_hide(log_window); } void linphone_gtk_create_log_window(void){ GtkTextBuffer *b; - log_window=linphone_gtk_create_window("log"); + log_window=linphone_gtk_create_window("log", NULL); b=gtk_text_view_get_buffer(GTK_TEXT_VIEW(linphone_gtk_get_widget(log_window,"textview"))); gtk_text_buffer_create_tag(b,"red","foreground","red",NULL); gtk_text_buffer_create_tag(b,"orange","foreground","orange",NULL); @@ -334,13 +326,24 @@ gboolean linphone_gtk_check_logs(){ * Called from any linphone thread. */ void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args){ - gchar *msg=g_strdup_vprintf(fmt,args); LinphoneGtkLog *lgl=g_new(LinphoneGtkLog,1); + gchar *msg=g_strdup_vprintf(fmt,args); + gchar *dated_msg; + struct timeval tp; + struct tm *lt; + time_t tt; + + ortp_gettimeofday(&tp, NULL); + tt = (time_t)tp.tv_sec; + lt = localtime((const time_t*)&tt); + dated_msg=g_strdup_printf("%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s", + 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), msg); + g_free(msg); lgl->lev=lev; - lgl->msg=msg; + lgl->msg=dated_msg; + linphone_gtk_log_file(lev, dated_msg); g_static_mutex_lock(&log_mutex); log_queue=g_list_append(log_queue,lgl); - linphone_gtk_log_file(lev, msg); g_static_mutex_unlock(&log_mutex); } diff --git a/gtk/login_frame.ui b/gtk/login_frame.ui new file mode 100644 index 000000000..f65229f14 --- /dev/null +++ b/gtk/login_frame.ui @@ -0,0 +1,250 @@ + + + + + + False + 0 + etched-out + + + True + False + 12 + + + True + False + + + True + False + gtk-missing-image + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + 12 + + + True + False + 5 + 2 + + + + + + True + False + Username + + + + + True + False + Password + + + 1 + 2 + + + + + False + Internet connection: + + + 3 + 4 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + + + + + True + True + False + + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + False + 0 + + + + 0 + + + + + 1 + 2 + 3 + 4 + + + + + Automatically log me in + True + True + False + True + + + 1 + 2 + 4 + 5 + + + + + False + UserID + + + 2 + 3 + + + + + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + + + + + True + False + Login information + True + + + + + True + True + 10 + 1 + + + + + True + False + + + gtk-connect + True + True + True + True + + + + False + False + 0 + + + + + + + + True + True + 2 + + + + + + + + + True + False + <b>Welcome!</b> + True + + + + + + + + + + + ADSL + + + Fiber Channel + + + + diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 08b90fe45..40748494b 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -19,16 +19,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" -void linphone_gtk_login_frame_connect_clicked(GtkWidget *button); +void test_button_clicked_cb(GtkWidget *button); void linphone_gtk_exit_login_frame(void); -enum { - NetworkKindAdsl, - NetworkKindOpticalFiber -}; -static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){ - if (sip_setup_context_login_account(ssctx,identity,passwd)==0){ +static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd, const char *userid){ + if (sip_setup_context_login_account(ssctx,identity,passwd,userid)==0){ } } @@ -40,89 +36,111 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ if (ssctx==NULL) return TRUE;/*not ready ?*/ username=linphone_gtk_get_ui_config ("login_username",NULL); if (username==NULL) { - linphone_gtk_set_ui_config_int("automatic_login",0); - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,TRUE); return FALSE; } - addr=linphone_address_new(linphone_proxy_config_get_identity(cfg)); + addr=linphone_address_clone(linphone_proxy_config_get_identity_address(cfg)); linphone_address_set_username(addr,username); tmp=linphone_address_as_string (addr); - do_login(ssctx,tmp,NULL); + do_login(ssctx,tmp,NULL,NULL); linphone_address_destroy(addr); linphone_gtk_load_identities(); return FALSE; } -void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *label=linphone_gtk_get_widget(mw,"login_label"); - const LinphoneAuthInfo *ai; +static void linphone_gtk_init_login_frame(GtkWidget *login_frame, LinphoneProxyConfig *cfg) { + gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0); + const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png"); + GtkWidget *label=linphone_gtk_get_widget(login_frame,"login_label"); + LinphoneCore *lc=linphone_gtk_get_core(); gchar *str; LinphoneAddress *from; - LinphoneCore *lc=linphone_gtk_get_core(); - int nettype; + const LinphoneAuthInfo *ai; const char *passwd=NULL; - + const char *userid=NULL; - if (linphone_core_get_download_bandwidth(lc)==512 && - linphone_core_get_upload_bandwidth(lc)==512) - nettype=NetworkKindOpticalFiber; - else nettype=NetworkKindAdsl; - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"login_internet_kind")),nettype); - //gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"internet_kind")),nettype); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame, "automatic_login")),auto_login); - if (linphone_gtk_get_ui_config_int("automatic_login",0) ){ - g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg); - return; + if (login_image){ + GdkPixbuf *pbuf=create_pixbuf (login_image); + gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(login_frame, "login_image")), pbuf); + g_object_unref(G_OBJECT(pbuf)); } - - { - const char *login_image=linphone_gtk_get_ui_config("login_image",NULL); - if (login_image){ - GdkPixbuf *pbuf=create_pixbuf (login_image); - gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(mw,"login_image")), - pbuf); - g_object_unref(G_OBJECT(pbuf)); - } + + if (linphone_gtk_get_ui_config_int("login_needs_userid",FALSE)){ + gtk_widget_show(linphone_gtk_get_widget(login_frame,"userid")); + gtk_widget_show(linphone_gtk_get_widget(login_frame,"login_userid")); } - - gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item")); - gtk_widget_hide(linphone_gtk_get_widget(mw,"main_frame")); - gtk_widget_show(linphone_gtk_get_widget(mw,"login_frame")); - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE); + str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg)); gtk_label_set_text(GTK_LABEL(label),str); - g_object_set_data(G_OBJECT(mw),"login_proxy_config",cfg); + g_object_set_data(G_OBJECT(login_frame),"login_proxy_config",cfg); g_free(str); - + from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); if (linphone_address_get_username(from)[0]=='?'){ const char *username=linphone_gtk_get_ui_config ("login_username",NULL); if (username) 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")), + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username")), linphone_address_get_username(from)); - if (ai) passwd=linphone_auth_info_get_passwd(ai); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")), + if (ai) { + passwd=linphone_auth_info_get_passwd(ai); + userid=linphone_auth_info_get_userid(ai); + } + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password")), passwd!=NULL ? passwd : ""); - + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid")), + userid ? userid : ""); + linphone_address_destroy(from); } +void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){ + GtkWidget *mw=linphone_gtk_get_main_window(); + gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0); + GtkWidget *main_frame = linphone_gtk_get_widget(mw, "main_frame"); + GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout"); + GtkWidget *login_frame; + + if (auto_login && !disable_auto_login){ + g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg); + return; + } + + login_frame = linphone_gtk_create_widget("login_frame"); + linphone_gtk_init_login_frame(login_frame, cfg); + g_object_set_data_full(G_OBJECT(mw), "main_frame", g_object_ref(main_frame), g_object_unref); + g_object_set_data(G_OBJECT(mw), "login_frame", login_frame); + gtk_container_remove(GTK_CONTAINER(main_layout), main_frame); + gtk_box_pack_start(GTK_BOX(main_layout), login_frame, TRUE, TRUE, 0); + gtk_widget_show(login_frame); + + gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item")); + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE); +} + void linphone_gtk_exit_login_frame(void){ GtkWidget *mw=linphone_gtk_get_main_window(); - gtk_widget_show(linphone_gtk_get_widget(mw,"main_frame")); - gtk_widget_hide(linphone_gtk_get_widget(mw,"login_frame")); + GtkWidget *main_layout = linphone_gtk_get_widget(mw, "main_layout"); + GtkWidget *main_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "main_frame")); + GtkWidget *login_frame = GTK_WIDGET(g_object_get_data(G_OBJECT(mw), "login_frame")); + + gtk_container_remove(GTK_CONTAINER(main_layout), login_frame); + gtk_box_pack_start(GTK_BOX(main_layout), main_frame, TRUE, TRUE, 0); + g_object_set_data(G_OBJECT(mw), "login_frame", NULL); + g_object_set_data(G_OBJECT(mw), "main_frame", NULL); + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),TRUE); gtk_widget_show(linphone_gtk_get_widget(mw,"disconnect_item")); } -void linphone_gtk_logout_clicked(){ +void linphone_gtk_logout_clicked(void){ LinphoneCore *lc=linphone_gtk_get_core(); LinphoneProxyConfig *cfg=NULL; linphone_core_get_default_proxy(lc,&cfg); @@ -130,50 +148,38 @@ void linphone_gtk_logout_clicked(){ SipSetupContext *ss=linphone_proxy_config_get_sip_setup_context(cfg); if (ss){ sip_setup_context_logout(ss); - linphone_gtk_set_ui_config_int("automatic_login",FALSE); - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,TRUE); } } } -void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ - GtkWidget *mw=gtk_widget_get_toplevel(button); +void linphone_gtk_login_frame_connect_clicked(GtkWidget *button, GtkWidget *login_frame){ const char *username; const char *password; + const char *userid; char *identity; gboolean autologin; - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(mw),"login_proxy_config"); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(login_frame),"login_proxy_config"); LinphoneAddress *from; SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg); - username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username"))); - password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password"))); + username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_username"))); + password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_password"))); + userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(login_frame,"login_userid"))); if (username==NULL || username[0]=='\0') return; - autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login"))); + autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(login_frame,"automatic_login"))); linphone_gtk_set_ui_config_int("automatic_login",autologin); linphone_gtk_set_ui_config("login_username",username); from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); linphone_address_set_username(from,username); identity=linphone_address_as_string(from); - do_login(ssctx,identity,password); + do_login(ssctx,identity,password,userid); /*we need to refresh the identities since the proxy config may have changed.*/ linphone_gtk_load_identities(); } - -void linphone_gtk_internet_kind_changed(GtkWidget *combo){ - int netkind_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); - LinphoneCore *lc=linphone_gtk_get_core(); - if (netkind_id==NetworkKindAdsl){ - linphone_core_set_upload_bandwidth(lc,256); - linphone_core_set_download_bandwidth(lc,512); - }else if (netkind_id==NetworkKindOpticalFiber){ - linphone_core_set_upload_bandwidth(lc,512); - linphone_core_set_download_bandwidth(lc,512); - } -} diff --git a/gtk/main.c b/gtk/main.c index dab29bda0..5e967242b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -22,11 +22,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" #include "lpconfig.h" +#include "liblinphone_gitversion.h" #include #include +#ifndef WIN32 #include +#endif #ifdef HAVE_GTK_OSX #include @@ -34,6 +37,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef WIN32 #define chdir _chdir +#include "direct.h" +#ifndef F_OK +#define F_OK 00 /*visual studio does not define F_OK*/ +#endif #endif #if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4) @@ -44,18 +51,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif -#define LINPHONE_ICON "linphone.png" +#ifdef ENABLE_NLS +#include +#endif + +#include "status_icon.h" + const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; +static LinphoneLDAPContactProvider* ldap_provider = NULL; +static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str); static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); +static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); @@ -63,72 +78,73 @@ 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); void _linphone_gtk_enable_video(gboolean val); +void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data); +static void linphone_gtk_init_ui(void); +static void linphone_gtk_quit(void); - - +#ifndef HAVE_GTK_OSX +static gint main_window_x=0; +static gint main_window_y=0; +#endif static gboolean verbose=0; -static gboolean auto_answer = 0; +static gboolean quit_done=FALSE; static gchar * addr_to_call = NULL; +static int start_option = START_LINPHONE; static gboolean no_video=FALSE; static gboolean iconified=FALSE; +static gboolean run_audio_assistant=FALSE; +static gboolean version=FALSE; +static gboolean selftest=FALSE; static gchar *workingdir=NULL; static char *progpath=NULL; gchar *linphone_logfile=NULL; static gboolean workaround_gtk_entry_chinese_bug=FALSE; +static gchar *custom_config_file=NULL; +static gboolean restart=FALSE; +static GtkWidget *config_fetching_dialog=NULL; + +#if _MSC_VER + +#define LINPHONE_OPTION(optlname, optsname, optarg, optargdata, optdesc) \ +{ \ + optlname, \ + optsname, \ + 0, \ + optarg, \ + optargdata, \ + optdesc, \ + NULL \ +} + +#else + +#define LINPHONE_OPTION(optlname, optsname, optarg, optargdata, optdesc) \ +{ \ + .long_name = optlname, \ + .short_name = optsname, \ + .arg = optarg, \ + .arg_data = optargdata, \ + .description = optdesc, \ +} + +#endif static GOptionEntry linphone_options[]={ - { - .long_name="verbose", - .short_name= '\0', - .arg=G_OPTION_ARG_NONE, - .arg_data= (gpointer)&verbose, - .description=N_("log to stdout some debug information while running.") - }, - { - .long_name = "logfile", - .short_name = 'l', - .arg = G_OPTION_ARG_STRING, - .arg_data = &linphone_logfile, - .description = N_("path to a file to write logs into.") - }, - { - .long_name = "no-video", - .short_name = '\0', - .arg = G_OPTION_ARG_NONE, - .arg_data = (gpointer)&no_video, - .description = N_("Start linphone with video disabled.") - }, - { - .long_name="iconified", - .short_name= '\0', - .arg=G_OPTION_ARG_NONE, - .arg_data= (gpointer)&iconified, - .description=N_("Start only in the system tray, do not show the main interface.") - }, - { - .long_name = "call", - .short_name = 'c', - .arg = G_OPTION_ARG_STRING, - .arg_data = &addr_to_call, - .description = N_("address to call right now") - }, - { - .long_name = "auto-answer", - .short_name = 'a', - .arg = G_OPTION_ARG_NONE, - .arg_data = (gpointer) & auto_answer, - .description = N_("if set automatically answer incoming calls") - }, - { - .long_name = "workdir", - .short_name = '\0', - .arg = G_OPTION_ARG_STRING, - .arg_data = (gpointer) & workingdir, - .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)") - }, + LINPHONE_OPTION("verbose", '\0', G_OPTION_ARG_NONE, (gpointer)&verbose, N_("log to stdout some debug information while running.")), + LINPHONE_OPTION("version", '\0', G_OPTION_ARG_NONE, (gpointer)&version, N_("display version and exit.")), + LINPHONE_OPTION("logfile", 'l', G_OPTION_ARG_STRING, &linphone_logfile, N_("path to a file to write logs into.")), + LINPHONE_OPTION("no-video", '\0', G_OPTION_ARG_NONE, (gpointer)&no_video, N_("Start linphone with video disabled.")), + LINPHONE_OPTION("iconified", '\0', G_OPTION_ARG_NONE, (gpointer)&iconified, N_("Start only in the system tray, do not show the main interface.")), + LINPHONE_OPTION("call", 'c', G_OPTION_ARG_STRING, &addr_to_call, N_("address to call right now")), + LINPHONE_OPTION("workdir", '\0', G_OPTION_ARG_STRING, (gpointer) & workingdir, N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")), + LINPHONE_OPTION("config", '\0', G_OPTION_ARG_FILENAME, (gpointer) &custom_config_file, N_("Configuration file")), + LINPHONE_OPTION("run-audio-assistant", '\0', G_OPTION_ARG_NONE, (gpointer) &run_audio_assistant, N_("Run the audio assistant")), + LINPHONE_OPTION("selftest", '\0', G_OPTION_ARG_NONE, (gpointer) &selftest, N_("Run self test and exit 0 if succeed")), {0} }; @@ -139,9 +155,11 @@ static GOptionEntry linphone_options[]={ #ifndef WIN32 #define CONFIG_FILE ".linphonerc" #define SECRETS_FILE ".linphone-zidcache" +#define CERTIFICATES_PATH ".linphone-usr-crt" #else #define CONFIG_FILE "linphonerc" #define SECRETS_FILE "linphone-zidcache" +#define CERTIFICATES_PATH "linphone-usr-crt" #endif char *linphone_gtk_get_config_file(const char *filename){ @@ -151,7 +169,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){ @@ -171,10 +191,10 @@ char *linphone_gtk_get_config_file(const char *filename){ #define FACTORY_CONFIG_FILE "linphonerc.factory" static char _factory_config_file[1024]; static const char *linphone_gtk_get_factory_config_file(){ + char* path = NULL; /*try accessing a local file first if exists*/ if (access(FACTORY_CONFIG_FILE,F_OK)==0){ - snprintf(_factory_config_file,sizeof(_factory_config_file), - "%s",FACTORY_CONFIG_FILE); + path = ms_strdup(FACTORY_CONFIG_FILE); } else { char *progdir; @@ -186,44 +206,69 @@ static const char *linphone_gtk_get_factory_config_file(){ if (basename != NULL) { basename ++; *basename = '\0'; - snprintf(_factory_config_file, sizeof(_factory_config_file), - "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE); - } else { - if (workingdir!=NULL) { - snprintf(_factory_config_file, sizeof(_factory_config_file), - "%s\\%s", workingdir, FACTORY_CONFIG_FILE); - } else { - free(progdir); - return NULL; - } + path = ms_strdup_printf("%s\\..\\%s", progdir, FACTORY_CONFIG_FILE); + } else if (workingdir!=NULL) { + path = ms_strdup_printf("%s\\%s", workingdir, FACTORY_CONFIG_FILE); } #else basename = strrchr(progdir, '/'); if (basename != NULL) { basename ++; *basename = '\0'; - snprintf(_factory_config_file, sizeof(_factory_config_file), - "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE); - } else { - free(progdir); - return NULL; + path = ms_strdup_printf("%s/../share/linphone/%s", progdir, FACTORY_CONFIG_FILE); } #endif free(progdir); } } - return _factory_config_file; + if (path) { + //use factory file only if it exists + if (access(path,F_OK)==0){ + snprintf(_factory_config_file, sizeof(_factory_config_file), "%s", path); + ms_free(path); + return _factory_config_file; + } + ms_free(path); + } + return NULL; +} + +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ + return ldap_provider; +} + +int linphone_gtk_is_ldap_supported(void){ + return linphone_ldap_contact_provider_available(); +} + +void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) +{ + if( ldap_provider ) + linphone_contact_provider_unref(ldap_provider); + + ldap_provider = ldap ? linphone_ldap_contact_provider_ref( ldap ) + : NULL; +} + +void linphone_gtk_schedule_restart(void){ + restart=TRUE; +} + +gboolean linphone_gtk_get_audio_assistant_option(void){ + return run_audio_assistant; } static void linphone_gtk_init_liblinphone(const char *config_file, - const char *factory_config_file) { + const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); + gchar *user_certificates_dir=linphone_gtk_get_config_file(CERTIFICATES_PATH); + vtable.global_state_changed=linphone_gtk_global_state_changed; vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; - vtable.notify_presence_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; @@ -232,22 +277,39 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_log_updated=linphone_gtk_call_log_updated; //vtable.text_received=linphone_gtk_text_received; vtable.message_received=linphone_gtk_text_received; + vtable.is_composing_received=linphone_gtk_is_composing_received; vtable.refer_received=linphone_gtk_refer_received; vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; + vtable.dtmf_received=linphone_gtk_dtmf_received; + vtable.configuring_status=linphone_gtk_configuring_status; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); + linphone_core_migrate_to_multi_transport(the_core); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); + + + if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){ + LpConfig* cfg = linphone_core_get_config(the_core); + LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap"); + linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) ); + } + linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION); linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); linphone_core_set_zrtp_secrets_file(the_core,secrets_file); g_free(secrets_file); - linphone_core_enable_video(the_core,TRUE,TRUE); + linphone_core_set_user_certificates_path(the_core,user_certificates_dir); + g_free(user_certificates_dir); + linphone_core_enable_video_capture(the_core, TRUE); + linphone_core_enable_video_display(the_core, TRUE); + linphone_core_set_native_video_window_id(the_core,LINPHONE_VIDEO_DISPLAY_NONE);/*don't create the window*/ if (no_video) { _linphone_gtk_enable_video(FALSE); linphone_gtk_set_ui_config_int("videoselfview",0); } + if (db_file) linphone_core_set_chat_database_path(the_core,db_file); } LinphoneCore *linphone_gtk_get_core(void){ @@ -259,7 +321,7 @@ GtkWidget *linphone_gtk_get_main_window(){ } void linphone_gtk_destroy_main_window() { - linphone_gtk_destroy_window(the_ui); + linphone_gtk_destroy_window(the_ui); the_ui = NULL; } @@ -281,9 +343,17 @@ static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name) linphone_gtk_visibility_set(shown,window_name,w,TRUE); if (icon_path) { GdkPixbuf *pbuf=create_pixbuf(icon_path); - if(pbuf != NULL) { - gtk_window_set_icon(GTK_WINDOW(w),pbuf); - g_object_unref(G_OBJECT(pbuf)); + if(pbuf) { + GList *pbuf_list = NULL; + GdkPixbuf *pbuf_16=gdk_pixbuf_scale_simple(pbuf, 16, 16, GDK_INTERP_BILINEAR); + GdkPixbuf *pbuf_32=gdk_pixbuf_scale_simple(pbuf, 32, 32, GDK_INTERP_BILINEAR); + pbuf_list = g_list_append(pbuf_list, pbuf); + pbuf_list = g_list_append(pbuf_list, pbuf_16); + pbuf_list = g_list_append(pbuf_list, pbuf_32); + gtk_window_set_icon_list(GTK_WINDOW(w), pbuf_list); + gtk_window_set_default_icon_list(pbuf_list); + g_list_foreach(pbuf_list, (GFunc)g_object_unref,NULL); + g_list_free(pbuf_list); } } } @@ -307,61 +377,53 @@ void linphone_gtk_destroy_window(GtkWidget *widget) { g_object_unref (G_OBJECT (builder)); } -GtkWidget *linphone_gtk_create_window(const char *window_name){ - GError* error = NULL; - GtkBuilder* builder = gtk_builder_new (); - char path[512]; - GtkWidget *w; - - if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL; - - if (!gtk_builder_add_from_file (builder, path, &error)){ - g_error("Couldn't load builder file: %s", error->message); - g_error_free (error); - return NULL; - } - w=GTK_WIDGET(gtk_builder_get_object (builder,window_name)); - if (w==NULL){ - g_error("Could not retrieve '%s' window from xml file",window_name); - return NULL; - } - g_object_set_data(G_OBJECT(w), "builder",builder); - gtk_builder_connect_signals(builder,w); - linphone_gtk_configure_window(w,window_name); - return w; -} - -GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){ +GtkWidget *linphone_gtk_create_widget(const char *widget_name) { char path[2048]; - GtkWidget *w; - GtkBuilder* builder = gtk_builder_new (); - GError *error=NULL; - gchar *object_ids[2]; - object_ids[0]=g_strdup(widget_name); - object_ids[1]=NULL; + GtkBuilder *builder = gtk_builder_new(); + GError *error = NULL; + GObject *obj; - if (get_ui_file(filename,path,sizeof(path))==-1) return NULL; - if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){ - g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message); - g_error_free (error); - g_free(object_ids[0]); - return NULL; + if(get_ui_file(widget_name, path, sizeof(path)) == -1) goto fail; + + gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE); + + if(gtk_builder_add_from_file(builder, path, &error) == 0) { + g_error("Couldn't load builder file: %s", error->message); + g_error_free(error); + goto fail; } - g_free(object_ids[0]); - w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name)); - if (w==NULL){ - g_error("Could not retrieve '%s' window from xml file",widget_name); - return NULL; + + obj = gtk_builder_get_object(builder, widget_name); + if(obj == NULL) { + g_error("'%s' widget not found", widget_name); + goto fail; + } + g_object_set_data(G_OBJECT(obj), "builder", builder); + g_signal_connect_data(G_OBJECT(obj),"destroy",(GCallback)g_object_unref,builder, NULL, G_CONNECT_AFTER|G_CONNECT_SWAPPED); + gtk_builder_connect_signals(builder, obj); + + return GTK_WIDGET(obj); + +fail: + g_object_unref(builder); + return NULL; +} + +GtkWidget *linphone_gtk_create_window(const char *window_name, GtkWidget *parent){ + GtkWidget *w = linphone_gtk_create_widget(window_name); + if(w) { + linphone_gtk_configure_window(w,window_name); + if(parent) { + gtk_window_set_transient_for(GTK_WINDOW(w), GTK_WINDOW(parent)); + gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER_ON_PARENT); + } } - g_object_set_data(G_OBJECT(w),"builder",builder); - g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder); - gtk_builder_connect_signals(builder,w); return w; } -static void entry_unmapped(GtkWidget *entry){ - g_message("Entry is unmapped, calling unrealize to workaround chinese bug."); - gtk_widget_unrealize(entry); +static void entry_unmapped(GtkWidget *widget){ + ms_message("%s is unmapped, calling unrealize to workaround chinese bug.",G_OBJECT_TYPE_NAME(widget)); + gtk_widget_unrealize(widget); } GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ @@ -378,10 +440,10 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ g_error("No widget named %s found in xml interface.",name); } if (workaround_gtk_entry_chinese_bug){ - if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){ + if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0 || strcmp(G_OBJECT_TYPE_NAME(w),"GtkTextView")==0){ if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){ g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1)); - g_message("%s is a GtkEntry",name); + ms_message("%s is a %s",name,G_OBJECT_TYPE_NAME(w)); g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL); } } @@ -400,16 +462,16 @@ void linphone_gtk_display_something(GtkMessageType type,const gchar *message){ /* draw a question box. link to dialog_click callback */ dialog = gtk_message_dialog_new ( GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", + GTK_BUTTONS_YES_NO, + "%s", (const gchar*)message); /* connect to some callback : REVISIT */ /* g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (dialog_click), - G_OBJECT (dialog)); + G_CALLBACK (dialog_click), + G_OBJECT (dialog)); */ /* actually show the box */ gtk_widget_show(dialog); @@ -417,15 +479,15 @@ void linphone_gtk_display_something(GtkMessageType type,const gchar *message){ else { dialog = gtk_message_dialog_new (GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - type, - GTK_BUTTONS_CLOSE, - "%s", - (const gchar*)message); + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_CLOSE, + "%s", + (const gchar*)message); /* Destroy the dialog when the user responds to it (e.g. clicks a button) */ g_signal_connect_swapped (G_OBJECT (dialog), "response", - G_CALLBACK (gtk_widget_destroy), - G_OBJECT (dialog)); + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); gtk_widget_show(dialog); } } @@ -441,17 +503,19 @@ static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer linphone_gtk_open_browser(url); } -void linphone_gtk_show_about(){ +void linphone_gtk_show_about(void){ struct stat filestat; const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING"; GtkWidget *about; const char *tmp; GdkPixbuf *logo=create_pixbuf( - linphone_gtk_get_ui_config("logo","linphone-banner.png")); + linphone_gtk_get_ui_config("logo","linphone-banner.png")); static const char *defcfg="defcfg"; - about=linphone_gtk_create_window("about"); + about=linphone_gtk_create_window("about", the_ui); + gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL); + memset(&filestat,0,sizeof(filestat)); if (stat(license_file,&filestat)!=0){ license_file="COPYING"; @@ -460,16 +524,19 @@ void linphone_gtk_show_about(){ if (filestat.st_size>0){ char *license=g_malloc(filestat.st_size+1); FILE *f=fopen(license_file,"r"); - if (f && fread(license,filestat.st_size,1,f)==1){ + if (f && fread(license,1,filestat.st_size,f)>0){ license[filestat.st_size]='\0'; gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license); } g_free(license); } - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LIBLINPHONE_GIT_VERSION); gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone")); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org")); - if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo); + if (logo) { + gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo); + g_object_unref(logo); + } tmp=linphone_gtk_get_ui_config("artists",defcfg); if (tmp!=defcfg){ const char *tmp2[2]; @@ -486,64 +553,9 @@ void linphone_gtk_show_about(){ gtk_widget_show(about); } -static void set_video_window_decorations(GdkWindow *w){ - const char *title=linphone_gtk_get_ui_config("title","Linphone"); - const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); - char video_title[256]; - GdkPixbuf *pbuf=create_pixbuf(icon_path); - - if (!linphone_core_in_call(linphone_gtk_get_core())){ - snprintf(video_title,sizeof(video_title),"%s video",title); - /* When not in call, treat the video as a normal window */ - gdk_window_set_keep_above(w, FALSE); - }else{ - LinphoneAddress *uri = - linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core())); - char *display_name; - - linphone_address_clean(uri); - if (linphone_address_get_display_name(uri)!=NULL){ - display_name=ms_strdup(linphone_address_get_display_name(uri)); - }else{ - display_name=linphone_address_as_string(uri); - } - snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name); - linphone_address_destroy(uri); - ms_free(display_name); - - /* During calls, bring up the video window, arrange so that - it is above all the other windows */ - gdk_window_deiconify(w); - gdk_window_set_keep_above(w,TRUE); - /* Maybe we should have the following, but then we want to - have a timer that turns it off after a little while. */ - /* gdk_window_set_urgency_hint(w,TRUE); */ - } - gdk_window_set_title(w,video_title); - /* Refrain the video window to be closed at all times. */ - gdk_window_set_functions(w, - GDK_FUNC_RESIZE|GDK_FUNC_MOVE| - GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE); - if (pbuf){ - GList *l=NULL; - l=g_list_append(l,pbuf); - gdk_window_set_icon_list(w,l); - g_list_free(l); - g_object_unref(G_OBJECT(pbuf)); - } -} - -static gboolean video_needs_update=FALSE; - -static void update_video_title(){ - video_needs_update=TRUE; -} static gboolean linphone_gtk_iterate(LinphoneCore *lc){ static gboolean first_time=TRUE; - unsigned long id; - static unsigned long previd=0; - static unsigned long preview_previd=0; static gboolean in_iterate=FALSE; /*avoid reentrancy*/ @@ -556,49 +568,10 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ first_time=FALSE; } - id=linphone_core_get_native_video_window_id(lc); - if (id!=previd || video_needs_update){ - GdkWindow *w; - previd=id; - if (id!=0){ - ms_message("Updating window decorations"); -#ifndef WIN32 - w=gdk_window_foreign_new(id); -#else - w=gdk_window_foreign_new((HANDLE)id); -#endif - if (w) { - set_video_window_decorations(w); - g_object_unref(G_OBJECT(w)); - } - else ms_error("gdk_window_foreign_new() failed"); - if (video_needs_update) video_needs_update=FALSE; - } - } - id=linphone_core_get_native_preview_window_id (lc); - if (id!=preview_previd ){ - GdkWindow *w; - preview_previd=id; - if (id!=0){ - ms_message("Updating window decorations for preview"); -#ifndef WIN32 - w=gdk_window_foreign_new(id); -#else - w=gdk_window_foreign_new((HANDLE)id); -#endif - if (w) { - set_video_window_decorations(w); - g_object_unref(G_OBJECT(w)); - } - else ms_error("gdk_window_foreign_new() failed"); - if (video_needs_update) video_needs_update=FALSE; - } - } if (addr_to_call!=NULL){ /*make sure we are not showing the login screen*/ GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame"); - if (!GTK_WIDGET_VISIBLE(login_frame)){ + if (g_object_get_data(G_OBJECT(mw), "login_frame") == NULL){ GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call); addr_to_call=NULL; @@ -609,12 +582,27 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ return TRUE; } +static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data){ + char* address = NULL; + gboolean ret = FALSE; + gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1); + + if(address) { + gchar *tmp = g_utf8_casefold(address,-1); + if (strstr(tmp,key)) ret=TRUE; + g_free(tmp); + g_free(address); + } + + return ret; +} + static void load_uri_history(){ GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); char key[20]; int i; GtkEntryCompletion *gep=gtk_entry_completion_new(); - GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING); + GtkListStore *model=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_INT); for (i=0;;i++){ const char *uri; snprintf(key,sizeof(key),"uri%i",i); @@ -622,14 +610,18 @@ static void load_uri_history(){ if (uri!=NULL) { GtkTreeIter iter; gtk_list_store_append(model,&iter); - gtk_list_store_set(model,&iter,0,uri,-1); + gtk_list_store_set(model,&iter,0,uri,1,COMPLETION_HISTORY,-1); if (i==0) gtk_entry_set_text(uribar,uri); } else break; } gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); gtk_entry_completion_set_text_column(gep,0); + gtk_entry_completion_set_popup_completion(gep, TRUE); + gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL); + gtk_entry_completion_set_minimum_key_length(gep,3); gtk_entry_set_completion(uribar,gep); + g_signal_connect (G_OBJECT (uribar), "changed", G_CALLBACK(linphone_gtk_on_uribar_changed), NULL); } static void save_uri_history(){ @@ -677,10 +669,129 @@ static void completion_add_text(GtkEntry *entry, const char *text){ } /* and prepend it on top of the list */ gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,1,COMPLETION_HISTORY,-1); save_uri_history(); } +void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data ) +{ + GtkTreeIter iter; + GtkEntry* uribar = GTK_ENTRY(data); + GtkEntryCompletion* compl = gtk_entry_get_completion(uribar); + GtkTreeModel* model = gtk_entry_completion_get_model(compl); + GtkListStore* list = GTK_LIST_STORE(model); + LinphoneLDAPContactSearch* search = linphone_ldap_contact_search_cast(req); + gboolean valid; + + // clear completion list from previous non-history entries + valid = gtk_tree_model_get_iter_first(model,&iter); + while(valid) + { + char* url; + int type; + gtk_tree_model_get(model,&iter, 0,&url, 1,&type, -1); + + if (type != COMPLETION_HISTORY) { + valid = gtk_list_store_remove(list, &iter); + } else { + valid = gtk_tree_model_iter_next(model,&iter); + } + + if( url ) g_free(url); + if( !valid ) break; + } + + // add new non-history related matches + while( friends ){ + LinphoneFriend* lf = friends->data; + if( lf ) { + const LinphoneAddress* la = linphone_friend_get_address(lf); + if( la ){ + char *addr = linphone_address_as_string(la); + + if( addr ){ + ms_message("[LDAP]Insert match: %s", addr); + gtk_list_store_insert_with_values(list, &iter, -1, + 0, addr, + 1, COMPLETION_LDAP, -1); + ms_free(addr); + } + } + } + friends = friends->next; + } + gtk_entry_completion_complete(compl); + // save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger + gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout", + GINT_TO_POINTER( + linphone_ldap_contact_search_result_count(search) + ) + ); + + // Gtk bug? we need to emit a "changed" signal so that the completion appears if + // the list of results was previously empty + g_signal_handlers_block_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); + g_signal_emit_by_name(uribar, "changed"); + g_signal_handlers_unblock_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); +} + +struct CompletionTimeout { + guint timeout_id; +}; + +static gboolean launch_contact_provider_search(void *userdata) +{ + LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap(); + GtkWidget* uribar = GTK_WIDGET(userdata); + const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar)); + gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search"); + unsigned int prev_res_count = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "ldap_res_cout")); + + if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates + unsigned int max_res_count = linphone_ldap_contact_provider_get_max_result(ldap); + LinphoneContactSearch* search; + if( previous_search && + (strstr(predicate, previous_search) == predicate) && // last search contained results from this one + (prev_res_count != max_res_count) ){ // and we didn't reach the max result limit + + ms_message("Don't launch search on already searched data (current: %s, old search: %s), (%d/%d results)", + predicate, previous_search, prev_res_count, max_res_count); + return FALSE; + } + + // save current search + if( previous_search ) ms_free(previous_search); + gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate)); + + ms_message("launch_contact_provider_search"); + search =linphone_contact_provider_begin_search( + linphone_contact_provider_cast(ldap_provider), + predicate, on_contact_provider_search_results, uribar + ); + + if(search) + linphone_contact_search_ref(search); + } + return FALSE; +} + +void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) +{ + if( linphone_gtk_get_ldap() ) { + gchar* text = gtk_editable_get_chars(uribar, 0,-1); + gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); + if( text ) g_free(text); + + if( timeout != 0 ) { + g_source_remove(timeout); + } + + timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); + + gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); + } +} + bool_t linphone_gtk_video_enabled(void){ const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core()); return vpol->automatically_accept && vpol->automatically_initiate; @@ -688,9 +799,6 @@ bool_t linphone_gtk_video_enabled(void){ void linphone_gtk_show_main_window(){ GtkWidget *w=linphone_gtk_get_main_window(); - LinphoneCore *lc=linphone_gtk_get_core(); - linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview", - VIDEOSELFVIEW_DEFAULT)); gtk_widget_show(w); gtk_window_present(GTK_WINDOW(w)); } @@ -698,11 +806,10 @@ void linphone_gtk_show_main_window(){ void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ GtkWidget *mw=linphone_gtk_get_main_window(); if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE); + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE); } if (linphone_gtk_use_in_call_view() && call) linphone_gtk_in_call_view_terminate(call,error); - update_video_title(); } static void linphone_gtk_update_call_buttons(LinphoneCall *call){ @@ -710,33 +817,25 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){ GtkWidget *mw=linphone_gtk_get_main_window(); const MSList *calls=linphone_core_get_calls(lc); GtkWidget *button; - bool_t start_active=TRUE; - //bool_t stop_active=FALSE; - bool_t add_call=FALSE; + bool_t add_call=(calls!=NULL); int call_list_size=ms_list_size(calls); + GtkWidget *conf_frame; - if (calls==NULL){ - start_active=TRUE; - //stop_active=FALSE; - }else{ - //stop_active=TRUE; - start_active=TRUE; - add_call=TRUE; - } button=linphone_gtk_get_widget(mw,"start_call"); - gtk_widget_set_sensitive(button,start_active); + gtk_widget_set_sensitive(button,TRUE); gtk_widget_set_visible(button,!add_call); button=linphone_gtk_get_widget(mw,"add_call"); + if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) { gtk_widget_set_sensitive(button,FALSE); } else { - gtk_widget_set_sensitive(button,start_active); + gtk_widget_set_sensitive(button,TRUE); } gtk_widget_set_visible(button,add_call); //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active); - GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); + conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame"); if(conf_frame==NULL){ linphone_gtk_enable_transfer_button(lc,call_list_size>1); linphone_gtk_enable_conference_button(lc,call_list_size>1); @@ -744,7 +843,6 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){ linphone_gtk_enable_transfer_button(lc,FALSE); linphone_gtk_enable_conference_button(lc,FALSE); } - update_video_title(); if (call) { linphone_gtk_update_video_button(call); } @@ -757,27 +855,40 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ char date[64]={0}; time_t curtime=time(NULL); struct tm loctime; - + const char **fmts=linphone_core_get_supported_file_formats(linphone_gtk_get_core()); + int i; + const char *ext="wav"; + #ifdef WIN32 loctime=*localtime(&curtime); #else localtime_r(&curtime,&loctime); #endif snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min); - + + for (i=0;fmts[i]!=NULL;++i){ + if (strcmp(fmts[i],"mkv")==0){ + ext="mkv"; + break; + } + } + if (address){ id=linphone_address_get_username(address); if (id==NULL) id=linphone_address_get_domain(address); } if (is_conference){ - snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav", + snprintf(filename,sizeof(filename)-1,"%s-conference-%s.%s", linphone_gtk_get_ui_config("title","Linphone"), - date); + date,ext); }else{ - snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav", + snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.%s", linphone_gtk_get_ui_config("title","Linphone"), date, - id); + id,ext); + } + if (!dir) { + ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME")); } return g_build_filename(dir,filename,NULL); } @@ -786,7 +897,7 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); LinphoneCore *lc=linphone_gtk_get_core(); LinphoneAddress *addr=linphone_core_interpret_url(lc,entered); - + if (addr!=NULL){ LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc); gchar *record_file=linphone_gtk_get_record_path(addr,FALSE); @@ -838,6 +949,18 @@ void linphone_gtk_start_call(GtkWidget *w){ } +void linphone_gtk_start_chat(GtkWidget *w){ + GtkWidget *mw=gtk_widget_get_toplevel(w); + GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); + const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); + LinphoneCore *lc=linphone_gtk_get_core(); + LinphoneAddress *addr=linphone_core_interpret_url(lc,entered); + if (addr) { + linphone_gtk_friend_list_set_chat_conversation(addr); + linphone_address_destroy(addr); + } +} + void linphone_gtk_uri_bar_activate(GtkWidget *w){ linphone_gtk_start_call(w); } @@ -869,15 +992,9 @@ 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){ - linphone_core_enable_video_preview(linphone_gtk_get_core(), - linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT)); - }else{ - linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); - } } void linphone_gtk_enable_video(GtkWidget *w){ @@ -889,7 +1006,6 @@ void linphone_gtk_enable_video(GtkWidget *w){ void linphone_gtk_enable_self_view(GtkWidget *w){ gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)); LinphoneCore *lc=linphone_gtk_get_core(); - linphone_core_enable_video_preview(lc,val); linphone_core_enable_self_view(lc,val); linphone_gtk_set_ui_config_int("videoselfview",val); } @@ -922,7 +1038,7 @@ static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){ switch(response_id){ case GTK_RESPONSE_YES: - linphone_gtk_show_contact(lf); + linphone_gtk_show_contact(lf, the_ui); break; default: linphone_core_reject_subscriber(linphone_gtk_get_core(),lf); @@ -932,19 +1048,20 @@ static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint respon static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ GtkWidget *dialog; + gchar *message; if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){ linphone_core_reject_subscriber(linphone_gtk_get_core(),lf); return; } - gchar *message=g_strdup_printf(_("%s would like to add you to his contact list.\nWould you allow him to see your presence status or add him to your contact list ?\nIf you answer no, this person will be temporarily blacklisted."),url); + message=g_strdup_printf(_("%s would like to add you to his/her contact list.\nWould you add him/her to your contact list and allow him/her to see your presence status?\nIf you answer no, this person will be temporarily blacklisted."),url); dialog = gtk_message_dialog_new ( GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", + GTK_BUTTONS_YES_NO, + "%s", message); g_free(message); g_signal_connect(G_OBJECT (dialog), "response", @@ -1002,31 +1119,35 @@ 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){ - GtkWidget *w=linphone_gtk_create_window("password"); +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", the_ui); GtkWidget *label=linphone_gtk_get_widget(w,"message"); LinphoneAuthInfo *info; gchar *msg; GtkWidget *mw=linphone_gtk_get_main_window(); - if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){ + if (mw && g_object_get_data(G_OBJECT(mw), "login_frame") != NULL){ /*don't prompt for authentication when login frame is visible*/ linphone_core_abort_authentication(lc,NULL); 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"); @@ -1036,6 +1157,11 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ status); } +static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + if (config_fetching_dialog) linphone_gtk_close_config_fetching(config_fetching_dialog, status); + config_fetching_dialog=NULL; +} + static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){ linphone_gtk_display_something(GTK_MESSAGE_INFO,msg); } @@ -1074,12 +1200,21 @@ static bool_t notify_actions_supported() { return accepts_actions; } -static NotifyNotification* build_notification(const char *title, const char *body){ - return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON) +static NotifyNotification* build_notification(const char *title, const char *body) { + NotifyNotification *n = notify_notification_new(title, body, NULL #ifdef HAVE_NOTIFY1 - ,NULL + ,NULL #endif ); +#ifndef HAVE_NOTIFY1 + { + const char *icon_path = linphone_gtk_get_ui_config("icon", LINPHONE_ICON); + GdkPixbuf *pbuf = create_pixbuf(icon_path); + /*with notify1, this function makes the notification crash the app with obscure dbus glib critical errors*/ + notify_notification_set_icon_from_pixbuf(n, pbuf); + } +#endif + return n; } static void show_notification(NotifyNotification* n){ @@ -1118,13 +1253,13 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){ NotifyNotification *n; switch(linphone_call_get_state(call)){ case LinphoneCallError: - make_notification(_("Call error"),body=g_markup_printf_escaped("%s\n%s",msg,remote)); + make_notification(_("Call error"),body=g_markup_printf_escaped("%s\n%s",msg,remote)); break; case LinphoneCallEnd: - make_notification(_("Call ended"),body=g_markup_printf_escaped("%s",remote)); + make_notification(_("Call ended"),body=g_markup_printf_escaped("%s",remote)); break; case LinphoneCallIncomingReceived: - n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("%s",remote)); + n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("%s",remote)); if (notify_actions_supported()) { notify_notification_add_action (n,"answer", _("Answer"), NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL); @@ -1134,7 +1269,7 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){ show_notification(n); break; case LinphoneCallPausedByRemote: - make_notification(_("Call paused"),body=g_markup_printf_escaped(_("by %s"),remote)); + make_notification(_("Call paused"),body=g_markup_printf_escaped(_("by %s"),remote)); break; default: break; @@ -1145,7 +1280,29 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){ } } -static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){ +static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str){ + switch(state){ + case LinphoneGlobalStartup: + the_core=lc; + break; + case LinphoneGlobalConfiguring: + if (linphone_core_get_provisioning_uri(lc)){ + config_fetching_dialog=linphone_gtk_show_config_fetching(); + } + break; + case LinphoneGlobalOn: + linphone_gtk_init_ui(); + if (selftest) { + gtk_timeout_add(300,(GtkFunction)gtk_main_quit,NULL); + } + break; + default: + break; + } +} + +static void on_call_updated_response(GtkWidget *dialog, gint responseid, gpointer user_data){ + LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(dialog), "call"); if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){ LinphoneCore *lc=linphone_call_get_core(call); LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); @@ -1153,13 +1310,12 @@ static void on_call_updated_response(GtkWidget *dialog, gint responseid, Linphon linphone_core_accept_call_update(lc,call,params); linphone_call_params_destroy(params); } - linphone_call_unref(call); g_source_remove_by_user_data(dialog); gtk_widget_destroy(dialog); } static void on_call_updated_timeout(GtkWidget *dialog){ - gtk_widget_destroy(dialog); + on_call_updated_response(dialog, GTK_RESPONSE_NO, NULL); } static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){ @@ -1170,8 +1326,8 @@ static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){ gboolean video_requested=linphone_call_params_video_enabled(rparams); gboolean video_used=linphone_call_params_video_enabled(current_params); g_message("Video used=%i, video requested=%i, automatically_accept=%i", - video_used,video_requested,pol->automatically_accept); - if (video_used==FALSE && video_requested && !pol->automatically_accept){ + video_used,video_requested,pol->automatically_accept); + if (!video_used && video_requested && !pol->automatically_accept){ linphone_core_defer_call_update(lc,call); { const LinphoneAddress *addr=linphone_call_get_remote_address(call); @@ -1180,11 +1336,12 @@ static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){ if (dname==NULL) dname=linphone_address_get_username(addr); if (dname==NULL) dname=linphone_address_get_domain(addr); dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_YES_NO, - _("%s proposed to start video. Do you accept ?"),dname); - g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call)); + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_YES_NO, + _("%s proposed to start video. Do you accept ?"),dname); + g_object_set_data_full(G_OBJECT(dialog), "call", linphone_call_ref(call), (GDestroyNotify)linphone_call_unref); + g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(on_call_updated_response), NULL); g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog); gtk_widget_show(dialog); } @@ -1216,9 +1373,10 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call linphone_gtk_create_in_call_view(call); linphone_gtk_in_call_view_set_incoming(call); linphone_gtk_status_icon_set_blinking(TRUE); - if (auto_answer) { + if (linphone_gtk_get_ui_config_int("auto_answer", 0)) { + int delay = linphone_gtk_get_ui_config_int("auto_answer_delay", 2000); linphone_call_ref(call); - g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call); + g_timeout_add(delay, (GSourceFunc)linphone_gtk_auto_answer, call); } break; case LinphoneCallResuming: @@ -1227,10 +1385,10 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call break; case LinphoneCallPausing: linphone_gtk_enable_hold_button(call,TRUE,FALSE); - update_tab_header(call,FALSE); + linphone_gtk_call_update_tab_header(call,FALSE); case LinphoneCallPausedByRemote: linphone_gtk_in_call_view_set_paused(call); - update_tab_header(call,TRUE); + linphone_gtk_call_update_tab_header(call,TRUE); break; case LinphoneCallConnected: linphone_gtk_enable_hold_button (call,TRUE,TRUE); @@ -1269,7 +1427,7 @@ static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistr }while(gtk_tree_model_iter_next(model,&iter)); } if (!found) { - g_warning("Could not find proxy config in combo box of identities."); + /*ignored, this is a notification for a removed proxy config.*/ return; } switch (rs){ @@ -1292,7 +1450,7 @@ static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistr } static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, - LinphoneRegistrationState rs, const char *msg){ + LinphoneRegistrationState rs, const char *msg){ switch (rs){ case LinphoneRegistrationOk: if (cfg){ @@ -1308,18 +1466,29 @@ static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphonePr update_registration_status(cfg,rs); } -void linphone_gtk_open_browser(const char *url){ - /*in gtk 2.16, gtk_show_uri does not work...*/ -#ifndef WIN32 -#if GTK_CHECK_VERSION(2,18,3) - gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL); +void linphone_gtk_open_browser(const char *uri) { +#ifdef __APPLE__ + GError *error = NULL; + char cmd_line[256]; + + g_snprintf(cmd_line, sizeof(cmd_line), "%s %s", "/usr/bin/open", uri); + g_spawn_command_line_async(cmd_line, &error); + if (error) { + g_warning("Could not open %s: %s", uri, error->message); + g_error_free(error); + } +#elif defined(WIN32) + HINSTANCE instance = ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL); + if ((int)instance <= 32) { + g_warning("Could not open %s (error #%i)", uri, (int)instance); + } #else - char cl[255]; - snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url); - g_spawn_command_line_async(cl,NULL); -#endif -#else /*WIN32*/ - ShellExecute(0,"open",url,NULL,NULL,1); + GError *error = NULL; + gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, &error); + if (error) { + g_warning("Could not open %s: %s", uri, error->message); + g_error_free(error); + } #endif } @@ -1328,15 +1497,6 @@ void linphone_gtk_link_to_website(GtkWidget *item){ linphone_gtk_open_browser(home); } -#ifndef HAVE_GTK_OSX - -static GtkStatusIcon *icon=NULL; - -static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){ - GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu"); - gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time); -} - static GtkWidget *create_icon_menu(){ GtkWidget *menu=gtk_menu_new(); GtkWidget *menu_item; @@ -1370,74 +1530,61 @@ static GtkWidget *create_icon_menu(){ return menu; } -static void handle_icon_click() { +#ifndef HAVE_GTK_OSX +void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){ + gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y); +} +#endif + +static void handle_icon_click(LinphoneStatusIcon *si, void *user_data) { +#ifndef HAVE_GTK_OSX GtkWidget *mw=linphone_gtk_get_main_window(); if (!gtk_window_is_active((GtkWindow*)mw)) { + if(!gtk_widget_is_drawable(mw)){ + //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was + gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y); + } linphone_gtk_show_main_window(); } else { + linphone_gtk_save_main_window_position((GtkWindow*)mw, NULL, NULL); gtk_widget_hide(mw); } -} - -static void linphone_gtk_init_status_icon(){ - const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); - const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"); - GdkPixbuf *pbuf=create_pixbuf(icon_path); - GtkWidget *menu=create_icon_menu(); - const char *title; - title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone")); - icon=gtk_status_icon_new_from_pixbuf(pbuf); -#if GTK_CHECK_VERSION(2,20,0) - gtk_status_icon_set_name(icon,title); #endif - g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL); - g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL); - gtk_status_icon_set_tooltip(icon,title); - gtk_status_icon_set_visible(icon,TRUE); - g_object_set_data(G_OBJECT(icon),"menu",menu); - g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu); - g_object_set_data(G_OBJECT(icon),"icon",pbuf); - g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf); - pbuf=create_pixbuf(call_icon_path); - g_object_set_data(G_OBJECT(icon),"call_icon",pbuf); } -static gboolean do_icon_blink(GtkStatusIcon *gi){ - GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon"); - GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon"); - GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi); - if (cur_icon==call_icon){ - gtk_status_icon_set_from_pixbuf(gi,normal_icon); - }else{ - gtk_status_icon_set_from_pixbuf(gi,call_icon); +static void linphone_gtk_status_icon_initialised_cb(LinphoneStatusIconParams *params) { + LinphoneStatusIcon *icon = linphone_status_icon_get(); + if(icon) { + linphone_status_icon_start(icon, params); } - return TRUE; + linphone_status_icon_params_unref(params); } -#endif +static void linphone_gtk_init_status_icon(void) { + GtkWidget *menu = create_icon_menu(); + LinphoneStatusIconParams *params = linphone_status_icon_params_new(); + linphone_status_icon_params_set_menu(params, menu); + linphone_status_icon_params_set_title(params, _("Linphone")); + linphone_status_icon_params_set_description(params, _("A video internet phone")); + linphone_status_icon_params_set_on_click_cb(params, handle_icon_click, NULL); -void linphone_gtk_status_icon_set_blinking(gboolean val){ -#ifdef HAVE_GTK_OSX - static gint attention_id; - GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); - if (val) - attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST); - else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id); -#else - if (icon!=NULL){ - guint tout; - tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout")); - if (val && tout==0){ - tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon); - g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout)); - }else if (!val && tout!=0){ - GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon"); - g_source_remove(tout); - g_object_set_data(G_OBJECT(icon),"timeout",NULL); - gtk_status_icon_set_from_pixbuf(icon,normal_icon); + if(linphone_status_icon_init( + (LinphoneStatusIconReadyCb)linphone_gtk_status_icon_initialised_cb, + params)) { + + LinphoneStatusIcon *icon = linphone_status_icon_get(); + if(icon) { + linphone_status_icon_start(icon, params); } + linphone_status_icon_params_unref(params); + } +} + +void linphone_gtk_status_icon_set_blinking(gboolean val) { + LinphoneStatusIcon *icon = linphone_status_icon_get(); + if(icon) { + linphone_status_icon_enable_blinking(icon, val); } -#endif } void linphone_gtk_options_activate(GtkWidget *item){ @@ -1487,8 +1634,8 @@ void linphone_gtk_load_identities(void){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1, - linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL, - 2,cfg,-1); + linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL, + 2,cfg,-1); if (cfg==def) { def_index=i; } @@ -1551,21 +1698,19 @@ static void linphone_gtk_configure_main_window(){ static const char *home; static const char *start_call_icon; static const char *add_call_icon; + static const char *start_chat_icon; static const char *search_icon; static gboolean update_check_menu; static gboolean buttons_have_borders; static gboolean show_abcd; GtkWidget *w=linphone_gtk_get_main_window(); - GHashTable *contacts_history; - - contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL); - g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history); if (!config_loaded){ title=linphone_gtk_get_ui_config("title","Linphone"); home=linphone_gtk_get_ui_config("home","http://www.linphone.org"); - start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"); - add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png"); + start_call_icon=linphone_gtk_get_ui_config("start_call_icon","call_start.png"); + add_call_icon=linphone_gtk_get_ui_config("add_call_icon","call_add.png"); + start_chat_icon=linphone_gtk_get_ui_config("start_chat_icon","chat_start.png"); search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL); update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0); buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1); @@ -1578,19 +1723,25 @@ static void linphone_gtk_configure_main_window(){ } if (start_call_icon){ gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")), - create_pixmap (start_call_icon)); + create_pixmap (start_call_icon)); if (!buttons_have_borders) gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE); } if (add_call_icon){ gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")), - create_pixmap (add_call_icon)); + create_pixmap (add_call_icon)); if (!buttons_have_borders) gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE); } + if (start_chat_icon){ + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_chat")), + create_pixmap (start_chat_icon)); + if (!buttons_have_borders) + gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_chat")),GTK_RELIEF_NONE); + } if (search_icon){ GdkPixbuf *pbuf=create_pixbuf(search_icon); - if(pbuf != NULL) { + if(pbuf) { gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf); g_object_unref(G_OBJECT(pbuf)); } @@ -1599,7 +1750,7 @@ static void linphone_gtk_configure_main_window(){ gchar *tmp; GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item"); tmp=g_strdup(home); - g_object_set_data(G_OBJECT(menu_item),"home",tmp); + g_object_set_data_full(G_OBJECT(menu_item),"home",tmp, (GDestroyNotify)g_free); } { /* @@ -1615,6 +1766,7 @@ static void linphone_gtk_configure_main_window(){ if (pbuf) { GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad")); gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf)); + g_object_unref(pbuf); } } if (linphone_gtk_can_manage_accounts()) { @@ -1633,7 +1785,7 @@ void linphone_gtk_manage_login(void){ if (cfg){ SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg); if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){ - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,FALSE); } } } @@ -1641,10 +1793,11 @@ void linphone_gtk_manage_login(void){ gboolean linphone_gtk_close(GtkWidget *mw){ /*shutdown calls if any*/ LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *camera_preview=linphone_gtk_get_camera_preview_window(); if (linphone_core_in_call(lc)){ linphone_core_terminate_all_calls(lc); } - linphone_core_enable_video_preview(lc,FALSE); + if (camera_preview) gtk_widget_destroy(camera_preview); #ifdef __APPLE__ /*until with have a better option*/ gtk_window_iconify(GTK_WINDOW(mw)); #else @@ -1655,13 +1808,6 @@ gboolean linphone_gtk_close(GtkWidget *mw){ #ifdef HAVE_GTK_OSX static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){ - bool_t video_enabled=linphone_gtk_video_enabled(); - if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){ - linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); - }else{ - linphone_core_enable_video_preview(linphone_gtk_get_core(), - linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled); - } return FALSE; } #endif @@ -1688,13 +1834,48 @@ 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"); + GtkWidget *keypad; if(k!=NULL){ gtk_widget_destroy(k); } - GtkWidget *keypad=linphone_gtk_create_window("keypad"); + keypad=linphone_gtk_create_window("keypad", NULL); linphone_gtk_connect_digits(keypad); linphone_gtk_init_dtmf_table(keypad); g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad); @@ -1716,6 +1897,7 @@ static void linphone_gtk_init_main_window(){ linphone_gtk_load_identities(); linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core())); linphone_gtk_show_friends(); + linphone_core_reset_missed_calls_count(linphone_gtk_get_core()); main_window=linphone_gtk_get_main_window(); linphone_gtk_call_log_update(main_window); @@ -1728,17 +1910,22 @@ static void linphone_gtk_init_main_window(){ #ifdef HAVE_GTK_OSX { GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1"); - GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); - gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar)); + GtkosxApplication *theMacApp = gtkosx_application_get(); + gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar)); gtk_widget_hide(menubar); - gtk_osxapplication_ready(theMacApp); + gtkosx_application_ready(theMacApp); } g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL); #endif linphone_gtk_check_menu_items(); + linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); +#ifdef BUILD_WIZARD + gtk_widget_set_visible(linphone_gtk_get_widget(main_window, "assistant_item"), TRUE); +#else + gtk_widget_set_visible(linphone_gtk_get_widget(main_window, "assistant_item"), FALSE); +#endif } - void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ if (verbose){ const char *lname="undef"; @@ -1798,22 +1985,29 @@ static void linphone_gtk_check_soundcards(){ } } +static void linphone_gtk_quit_core(void){ + linphone_gtk_unmonitor_usb(); + g_source_remove_by_user_data(linphone_gtk_get_core()); +#ifdef BUILD_WIZARD + linphone_gtk_close_assistant(); +#endif + linphone_gtk_set_ldap(NULL); + linphone_gtk_destroy_log_window(); + linphone_core_destroy(the_core); + linphone_gtk_log_uninit(); +} + static void linphone_gtk_quit(void){ - static gboolean quit_done=FALSE; if (!quit_done){ quit_done=TRUE; - linphone_gtk_unmonitor_usb(); - g_source_remove_by_user_data(linphone_gtk_get_core()); -#ifdef BUILD_WIZARD - linphone_gtk_close_assistant(); -#endif + linphone_gtk_quit_core(); linphone_gtk_uninit_instance(); - linphone_gtk_destroy_log_window(); - linphone_core_destroy(the_core); - linphone_gtk_log_uninit(); #ifdef HAVE_NOTIFY notify_uninit(); #endif + linphone_status_icon_uninit(); + gtk_widget_destroy(the_ui); + the_ui=NULL; gdk_threads_leave(); } } @@ -1833,17 +2027,45 @@ static gboolean on_block_termination(void){ } #endif -int main(int argc, char *argv[]){ -#ifdef ENABLE_NLS - void *p; +static void linphone_gtk_init_ui(void){ + linphone_gtk_init_main_window(); + +#ifdef BUILD_WIZARD + // Veryfing if at least one sip account is configured. If not, show wizard + if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) { + linphone_gtk_show_assistant(the_ui); + } #endif + + if(run_audio_assistant){ + linphone_gtk_show_audio_assistant(); + start_option=START_AUDIO_ASSISTANT; + iconified = TRUE; + } + + linphone_gtk_init_status_icon(); + + if (!iconified){ + linphone_gtk_show_main_window(); + linphone_gtk_check_soundcards(); + } + if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0) + linphone_gtk_check_for_new_version(); + linphone_gtk_monitor_usb(); +} + +int main(int argc, char *argv[]){ char *config_file; const char *factory_config_file; const char *lang; GtkSettings *settings; + const char *icon_path=LINPHONE_ICON; GdkPixbuf *pbuf; const char *app_name="Linphone"; LpConfig *factory; + char *db_file; + GError *error=NULL; + const char *tmp; #if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); @@ -1854,41 +2076,46 @@ int main(int argc, char *argv[]){ config_file=linphone_gtk_get_config_file(NULL); + workingdir= (tmp=g_getenv("LINPHONE_WORKDIR")) ? g_strdup(tmp) : NULL; -#ifdef WIN32 - /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */ - if ((lang=getenv("LANG"))!=NULL){ - if (atoi(lang)!=0){ - char tmp[128]; - snprintf(tmp,sizeof(tmp),"LANG=",lang); - _putenv(tmp); - } - } -#else +#ifdef __linux /*for pulseaudio:*/ g_setenv("PULSE_PROP_media.role", "phone", TRUE); #endif + + /* Add the data directory of the install prefix to XDG_DATA_DIRS + * This environment variable is used by GTK+ to locate the directory + * which stores icon images. */ + tmp = g_getenv("XDG_DATA_DIRS"); + if(tmp && strlen(tmp) > 0) { + char *xdg_data_dirs = g_strdup_printf("%s:%s", PACKAGE_DATA_DIR, tmp); + g_setenv("XDG_DATA_DIRS", xdg_data_dirs, TRUE); + g_free(xdg_data_dirs); + } else { + g_setenv("XDG_DATA_DIRS", PACKAGE_DATA_DIR, FALSE); + } - if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){ + lang=linphone_gtk_get_lang(config_file); + if (lang == NULL || lang[0]=='\0'){ + lang = g_getenv("LANGUAGE"); + if (!lang) lang = g_getenv("LANG"); + } + if (lang && lang[0]!='\0'){ #ifdef WIN32 - char tmp[128]; - snprintf(tmp,sizeof(tmp),"LANG=%s",lang); - _putenv(tmp); if (strncmp(lang,"zh",2)==0){ workaround_gtk_entry_chinese_bug=TRUE; } -#elif __APPLE__ - setenv("LANG",lang,1); -#else - setenv("LANGUAGE",lang,1); #endif + g_setenv("LANGUAGE",lang,1); } #ifdef ENABLE_NLS - p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); - if (p==NULL) perror("bindtextdomain failed"); + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); + + /*do not use textdomain(): this sets a global default domain. On Mac OS bundle, it breaks gtk translations (obscure bug somewhere)*/ + /*textdomain (GETTEXT_PACKAGE);*/ #else g_message("NLS disabled.\n"); #endif @@ -1898,10 +2125,27 @@ int main(int argc, char *argv[]){ gdk_threads_enter(); if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), - linphone_options,NULL,NULL)){ + linphone_options,NULL,&error)){ gdk_threads_leave(); + g_critical("%s", error->message); return -1; } + if(version) { + g_message("Linphone version %s.", LIBLINPHONE_GIT_VERSION); + return 0; + } + + if (config_file) g_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); + + if(run_audio_assistant) start_option=START_AUDIO_ASSISTANT; + if(addr_to_call != NULL) start_option=START_LINPHONE_WITH_CALL; settings=gtk_settings_get_default(); g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM)); @@ -1915,6 +2159,20 @@ int main(int argc, char *argv[]){ } } +#if defined(__APPLE__) && defined(ENABLE_NLS) + /*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again). + So we help it:*/ + { + if (g_file_test(PACKAGE_LOCALE_DIR, G_FILE_TEST_IS_DIR)){ + bindtextdomain("gtk20",PACKAGE_LOCALE_DIR); + bindtextdomain("gdk-pixbuf",PACKAGE_LOCALE_DIR); + bindtextdomain("glib20",PACKAGE_LOCALE_DIR); + } + } +#endif + add_pixmap_directory("pixmaps"); + add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); + /* Now, look for the factory configuration file, we do it this late since we want to have had time to change directory and to parse the options, in case we needed to access the working directory */ @@ -1923,69 +2181,65 @@ int main(int argc, char *argv[]){ factory=lp_config_new(NULL); lp_config_read_file(factory,factory_config_file); app_name=lp_config_get_string(factory,"GtkUi","title","Linphone"); + icon_path=lp_config_get_string(factory,"GtkUi","icon",LINPHONE_ICON); } - - if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){ - g_warning("Another running instance of linphone has been detected. It has been woken-up."); - g_warning("This instance is going to exit now."); - gdk_threads_leave(); - return 0; + g_set_application_name(app_name); + pbuf=create_pixbuf(icon_path); + if (pbuf) { + gtk_window_set_default_icon(pbuf); + g_object_unref(pbuf); } - add_pixmap_directory("pixmaps"); - add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); - #ifdef HAVE_GTK_OSX - GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); + GtkosxApplication *theMacApp = gtkosx_application_get(); g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL); g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL); /*never block termination:*/ g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL); #endif - the_ui=linphone_gtk_create_window("main"); +core_start: + if (linphone_gtk_init_instance(app_name, start_option, addr_to_call) == FALSE){ + g_warning("Another running instance of linphone has been detected. It has been woken-up."); + g_warning("This instance is going to exit now."); + gdk_threads_leave(); + return 0; + } + + the_ui=linphone_gtk_create_window("main", NULL); g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE)); linphone_gtk_create_log_window(); linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); - linphone_gtk_init_liblinphone(config_file, factory_config_file); - - g_set_application_name(app_name); - pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON)); - if (pbuf!=NULL) gtk_window_set_default_icon(pbuf); + db_file=linphone_gtk_message_storage_get_db_file(NULL); + linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); + g_free(db_file); /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); - gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL); - linphone_gtk_init_main_window(); - -#ifdef BUILD_WIZARD - // Veryfing if at least one sip account is configured. If not, show wizard - if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) { - linphone_gtk_show_assistant(); - } -#endif - -#ifndef HAVE_GTK_OSX - linphone_gtk_init_status_icon(); -#endif - if (!iconified){ - linphone_gtk_show_main_window(); - linphone_gtk_check_soundcards(); - } - if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0) - linphone_gtk_check_for_new_version(); - linphone_gtk_monitor_usb(); + gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); gtk_main(); linphone_gtk_quit(); -#ifndef HAVE_GTK_OSX - /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/ - gtk_status_icon_set_visible(icon,FALSE); -#endif + + if (restart){ + quit_done=FALSE; + restart=FALSE; + goto core_start; + } + if (config_file) g_free(config_file); free(progpath); + /*output a translated "hello" string to the terminal, which allows the builder to check that translations are working.*/ + if (selftest){ + printf(_("Hello\n")); + } return 0; } +#ifdef _MSC_VER +int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + return main(__argc, __argv); +} +#endif diff --git a/gtk/main.ui b/gtk/main.ui index e1c8c9129..567156394 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -2,1827 +2,46 @@ + True False gtk-add - + + True False - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 12 - - - True - False - - - True - False - - - True - True - False - - - False - False - 0 - - - - - False - True - 0 - - - - - True - False - <b>Callee name</b> - True - right - end - - - True - True - 1 - - - - - 90 - 30 - True - False - - - False - True - 2 - - - - - - - - - - - - - + gtk-add - + + True False - - - True - False - 0 - none - - - True - False - - - True - True - never - - - True - True - 4 - - - - - True - True - 0 - - - - - True - False - - - True - True - True - - False - False - True - True - - - True - True - 0 - - - - - True - True - True - False - - - True - False - - - True - False - gtk-ok - - - True - True - 0 - - - - - True - False - Send - - - True - True - 7 - 1 - - - - - - - False - False - 1 - - - - - False - False - 1 - - - - - - - - - - - - False - - - True - False - 0 - none - - - True - False - - - True - False - - - End conference - True - True - True - False - - - False - False - end - 0 - - - - - True - True - end - 0 - - - - - True - False - - - gtk-media-record - True - True - True - False - True - - - - False - False - 0 - - - - - True - False - True - char - - - True - True - 1 - - - - - False - False - end - 1 - - - - - - - - - - - - False - - - False - cursor - 0.5 - none - - - True - False - 12 - 12 - - - True - False - - - True - False - label - center - - - True - True - 0 - - - - - True - False - - - - - - False - False - 1 - - - - - False - - - True - False - gtk-dialog-authentication - 1 - - - False - False - 0 - - - - - True - False - gtk-apply - - - False - False - 1 - - - - - True - False - label - - - True - True - 2 - 2 - - - - - Set verified - True - True - True - False - - - - False - False - 3 - - - - - False - True - 2 - - - - - False - True - - - True - False - gtk-missing-image - 1 - - - False - False - 0 - - - - - 90 - 10 - True - False - - - False - False - 1 - - - - - True - False - gtk-missing-image - 0 - - - False - False - 2 - - - - - 90 - 10 - True - False - - - False - False - 1 - end - 3 - - - - - False - False - 2 - 3 - - - - - False - spread - - - Answer - True - True - True - False - - - - False - False - 0 - - - - - Decline - True - True - True - False - - - - False - False - 1 - - - - - False - False - 4 - - - - - False - - - gtk-media-record - True - True - True - Record this call to an audio file - False - True - - - - False - False - 0 - - - - - True - False - True - char - - - True - True - 1 - - - - - False - False - 5 - - - - - True - False - 2 - 3 - True - - - Video - True - True - True - False - - - - - Pause - True - True - True - False - - - - 1 - 2 - - - - - Mute - True - True - True - False - - - - 2 - 3 - - - - - Transfer - True - True - True - False - - - 1 - 2 - - - - - Hang up - True - True - True - False - - - - 1 - 2 - 1 - 2 - - - - - Conference - True - True - True - False - - - 2 - 3 - 1 - 2 - - - - - False - False - 7 - 6 - - - - - - - - - True - False - True - - - True - False - In call - True - center - - - True - True - 0 - - - - - True - False - Duration - center - - - True - True - 1 - - - - - 90 - 10 - True - False - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - Call quality rating - - - False - False - 2 - - - - - - + gtk-connect True False gtk-edit - + True False - gtk-info + gtk-edit - - True - False - gtk-add - - - True - False - gtk-clear - - - True - False - gtk-connect - - - True - False - gtk-add - - - True - False - gtk-add - - - True - False - gtk-add - - - True - False - gtk-add - - - True - False - gtk-missing-image - - - True - False - gtk-select-color - - - True - False - gtk-refresh - - - True - False - gtk-properties - - - True - False - gtk-home - - + True False gtk-execute - + True False - gtk-add + gtk-home - + True False - gtk-add - - - True - False - gtk-add - - - True - False - gtk-add - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - - - True - False - False - _Options - True - - - - True - False - - - gtk-preferences - True - False - False - True - True - - - - - - gtk-disconnect - False - False - True - True - - - - - - True - False - - - - - True - False - False - Always start video - True - - - - - - True - False - False - Enable self-view - True - True - - - - - - True - False - - - - - gtk-quit - False - False - True - True - - - - - - - - - - True - False - False - _Help - True - - - True - False - - - gtk-about - True - False - False - True - True - - - - - - Show debug window - True - False - False - image1 - False - - - - - - _Homepage - True - False - False - True - image4 - False - - - - - - Check _Updates - False - False - True - image5 - False - - - - - - Account assistant - False - False - image12 - False - - - - - - - - - - False - True - 0 - - - - - True - False - - - True - False - 8 - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 5 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - - True - False - False - True - True - - - - True - True - 0 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - SIP address or phone number: - True - - - - - True - True - 2 - 0 - - - - - True - True - Initiate a new call - False - - - - False - False - end - 1 - - - - - True - True - True - False - - - - False - True - 6 - end - 2 - - - - - True - True - True - False - - - - False - False - 3 - - - - - False - True - 8 - 0 - - - - - True - False - - - True - False - 4 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_STRUCTURE_MASK - 0 - Contacts - True - - - False - False - 3 - 0 - - - - - True - True - automatic - automatic - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - False - 1 - - - - - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - True - True - True - Add - immediate - False - add_image - 1 - - - - False - False - 0 - - - - - True - True - True - Edit - False - edit_image - - - - False - False - 1 - - - - - True - True - True - False - remove_image - - - - False - False - 2 - - - - - False - False - 2 - - - - - False - False - 6 - 0 - - - - - True - True - - - - - - - - - True - False - - - True - False - 2 - - - True - True - never - - - 350 - True - True - False - - - - - - - True - True - 0 - - - - - True - False - end - - - gtk-clear - True - True - True - False - True - - - - False - False - 0 - - - - - - - - - - - False - True - end - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - - False - 0 - none - - - False - - - True - True - - True - False - False - True - True - - - True - True - 0 - - - - - True - True - True - False - none - - - - True - False - - - True - False - gtk-find - - - True - True - 0 - - - - - True - False - Search - - - True - True - 1 - - - - - - - False - True - 1 - - - - - - - True - False - <b>Add contacts from directory</b> - True - - - - - False - False - 5 - 2 - - - - - True - False - - - Add contact - True - True - False - image16 - - - - False - False - 0 - - - - - False - False - 3 - - - - - False - False - end - 2 - - - - - True - True - 0 - - - - - 1 - - - - - True - False - - - True - False - gtk-refresh - 1 - - - True - True - 0 - - - - - True - False - 0.49000000953674316 - Recent calls - - - True - True - 1 - - - - - 1 - False - - - - - - - - - - - True - True - 6 - 1 - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model3 - 0 - - - - - 0 - - - - - - - True - False - 5 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - My current identity: - True - - - True - True - 0 - - - - - True - True - False - none - - - - True - False - gtk-refresh - - - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - 0 - - - - - False - 0 - etched-out - - - True - False - 12 - - - True - False - - - True - False - gtk-missing-image - - - True - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - 12 - - - True - False - 4 - 2 - - - True - False - Username - - - - - True - False - Password - - - 1 - 2 - - - - - True - False - Internet connection: - - - 2 - 3 - - - - - True - True - - False - False - True - True - - - 1 - 2 - - - - - True - True - False - - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - False - model4 - 0 - - - - - 0 - - - - - 1 - 2 - 2 - 3 - - - - - Automatically log me in - True - True - False - False - True - - - 1 - 2 - 3 - 4 - - - - - - - - - - - - True - False - Login information - True - - - - - True - True - 10 - 1 - - - - - True - False - - - gtk-connect - True - True - True - False - True - - - - False - False - 0 - - - - - True - True - 2 - - - - - - - - - True - False - <b>Welcome !</b> - True - - - - - True - True - 1 - - - - - True - True - 1 - - - - - True - False - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 - - - True - True - 0 - - - - - True - True - True - False - none - - - - False - True - 5 - 1 - - - - - False - False - 2 - - - - + gtk-info @@ -1863,19 +82,11 @@ - - - - - - - - ADSL - - - Fiber Channel - - + + True + False + 0.49000000953674316 + gtk-properties True @@ -1883,4 +94,816 @@ Delete gtk-remove + + True + False + Delete + gtk-remove + + + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 660 + 450 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + + + True + False + _Options + True + + + + True + False + + + gtk-preferences + True + False + True + True + + + + + + True + False + Set configuration URI + True + + + + + + gtk-disconnect + False + True + True + + + + + + True + False + + + + + True + False + Always start video + True + + + + + + True + False + Enable self-view + True + True + + + + + + True + False + + + + + gtk-quit + False + True + True + + + + + + + + + + True + False + _Help + True + + + True + False + + + gtk-about + True + False + True + True + + + + + + Show debug window + True + False + info_image + False + + + + + + _Homepage + True + False + True + home_image + False + + + + + + Check _Updates + False + True + execute_image + False + + + + + + Account assistant + False + connect_image + False + + + + + + Audio assistant + True + False + properties_image + False + + + + + + + + + + False + True + 0 + + + + + True + False + 8 + + + True + False + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + + True + False + False + True + True + + + + True + True + 0 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + SIP address or phone number: + True + + + + + True + True + 2 + 0 + + + + + True + True + True + + + + False + True + 1 + + + + + True + True + Initiate a new call + + + + False + False + 6 + 2 + + + + + True + True + True + + + + False + True + 3 + + + + + True + True + True + + + + False + True + end + 4 + + + + + + + + + + + False + True + 8 + 0 + + + + + True + True + + + True + False + 4 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_STRUCTURE_MASK + 0 + Contacts + True + + + False + False + 3 + 0 + + + + + True + True + automatic + automatic + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + False + 1 + + + + + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + immediate + add_image1 + 1 + + + + False + False + 0 + + + + + True + True + True + edit_image1 + + + + False + False + 1 + + + + + True + True + True + remove_image1 + + + + False + False + 2 + + + + + False + False + 2 + + + + + False + False + + + + + True + True + + + + + + + + + True + False + + + True + False + 2 + + + True + True + never + + + 350 + True + True + False + + + + + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + False + 0 + none + + + False + + + True + True + + True + False + False + True + True + + + True + True + 0 + + + + + True + True + True + none + + + + True + False + + + True + False + gtk-find + + + True + True + 0 + + + + + True + False + Search + + + True + True + 1 + + + + + + + False + True + 1 + + + + + + + True + False + <b>Add contacts from directory</b> + True + + + + + False + False + 5 + 0 + + + + + True + False + + + Add contact + True + True + + + + False + False + 0 + + + + + False + False + 1 + + + + + False + False + 1 + + + + + True + False + end + + + gtk-clear + True + True + True + True + + + + False + False + 0 + + + + + + + + + + + False + True + 2 + + + + + True + True + 0 + + + + + 1 + + + + + True + False + + + + True + False + gtk-refresh + 1 + + + True + True + 0 + + + + + True + False + 0.49000000953674316 + Recent calls + + + True + True + 1 + + + + + 1 + False + + + + + + + + + + + True + True + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + model3 + 0 + + + + + 0 + + + + + True + True + 0 + + + + + True + True + True + none + + + + False + True + 5 + 1 + + + + + + + True + False + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + My current identity: + True + + + True + True + 0 + + + + + True + True + True + none + + + + True + True + 1 + + + + + + + False + False + 2 + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + False + True + end + 2 + + + + + diff --git a/gtk/p2pwizard.ui b/gtk/p2pwizard.ui index e8e6703ee..111f46ff5 100644 --- a/gtk/p2pwizard.ui +++ b/gtk/p2pwizard.ui @@ -8,8 +8,8 @@ True - Welcome ! -This wizard will help you to setup a SIP account. + Welcome! +This wizard will help you to setup a SIP account. True GTK_JUSTIFY_CENTER diff --git a/gtk/parameters.ui b/gtk/parameters.ui index e4a6430fa..32b12b69a 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -2,52 +2,12 @@ - - 500 - 3001 - 500 - 1 - 10 - - - 1 - 65535 - 1 - 1 - 10 - - - 1 - 65535 - 1 - 1 - 10 - - - 65535 - 1 - 1 - 10 - - + -1 100000 1 10 - - -1 - 100000 - 1 - 10 - - - 1 - 65535 - 5060 - 1 - 9.9999999995529656 - 65535 2 @@ -68,13 +28,54 @@ 2 10 - - 65535 - 1 + + 500 + 3001 + 500 1 10 + + 65535 + 5060 + 1 + 10 + + + -1 + 100000 + 1 + 10 + + + 30 + 1 + 10 + + + 60000 + 2000 + 100 + 500 + + + + + + + + + anonymous + + + GSSAPI + + + SASL + + + @@ -172,6 +173,29 @@ + + 65535 + 5060 + 1 + 9.9999999995529656 + + + + + + + + + default + + + high-fps + + + custom + + + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -187,169 +211,52 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + This section defines your SIP address when not using a SIP account 0 none - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 - - True - False - - - True - False - - - Set Maximum Transmission Unit: - True - True - False - False - True - - - - True - True - 0 - - - - - True - True - False - False - True - True - adjustment1 - - - - True - True - 1 - - - - - True - True - 0 - - - - - Send DTMFs as SIP info - True - True - False - False - True - - - - True - True - 1 - - - - - Use IPv6 instead of IPv4 - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - True - True - 2 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Transport</b> - True - - - - - False - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 7 + 3 2 - + True False - model8 - - - - 0 - - + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your display name (eg: John Doe): - + True True - - True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False True True - adjustment7 + 1 @@ -357,65 +264,11 @@ - - True - False - Media encryption type - - - 3 - 5 - - - - - True - False - 0 - - - 1 - 2 - 3 - 4 - - - - - gtk-edit - True - True - False - True - - - - 1 - 2 - 6 - 7 - - - - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Video RTP/UDP: - right - - - 2 - 3 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Audio RTP/UDP: - right + Your username: 1 @@ -423,92 +276,27 @@ - + True False - DSCP fields + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Your resulting SIP address: - 5 - 6 + 2 + 3 - - gtk-edit + True True - True - False - True - - - - 1 - 2 - 5 - 6 - - - - - True - False - - - True - True - - False - False - True - True - adjustment_min_audio_port - True - - - - True - True - 0 - - - - - True - True - - True - False - False - True - True - adjustment_max_audio_port - True - - - - True - True - 1 - - - - - Fixed - True - True - False - False - True - - - - True - True - 2 - - + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + False + True + True + 1 @@ -518,64 +306,15 @@ - + True - False - - - True - True - - False - False - True - True - adjustment_min_video_port - True - - - - True - True - 0 - - - - - True - True - - True - False - False - True - True - adjustment_max_video_port - True - - - - True - True - 1 - - - - - Fixed - True - True - False - False - True - - - - True - True - 2 - - + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + False + False + True + True 1 @@ -584,282 +323,20 @@ 3 - - - False - Tunnel - - - 6 - 7 - - - - - Media encryption is mandatory - True - True - False - False - True - - - - 1 - 2 - 4 - 5 - - - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Network protocol and ports</b> + <b>Default identity</b> True - - False - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - - - Direct connection to the Internet - True - True - False - False - True - True - - - - False - False - 0 - - - - - True - False - - - Behind NAT / Firewall (specify gateway IP below) - True - True - False - False - True - True - no_nat - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Public IP address: - right - - - True - True - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - - - - True - True - 1 - - - - - True - True - 1 - - - - - False - False - 1 - - - - - Behind NAT / Firewall (use STUN to resolve) - True - True - False - False - True - no_nat - - - - True - True - 2 - - - - - Behind NAT / Firewall (use ICE) - True - True - False - False - True - no_nat - - - - True - True - 3 - - - - - Behind NAT / Firewall (use uPnP) - False - True - True - False - True - no_nat - - - - True - True - 4 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Stun server: - right - - - True - True - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - True - False - False - True - True - - - - True - True - 1 - - - - - True - True - 4 - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>NAT and Firewall</b> - True - - - - - False - True - 2 - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-network - 1 - True True @@ -867,11 +344,452 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Network settings + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Wizard + + + True + True + 1 + + + + + + + False + False + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Add + + + True + True + 1 + + + + + + + False + False + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-edit + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Edit + + + True + True + 1 + + + + + + + False + False + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Remove + + + True + True + 1 + + + + + + + False + False + 3 + + + + + False + False + 1 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Proxy accounts</b> + True + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Erase all passwords + + + True + True + 1 + + + + + + + False + False + 0 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Privacy</b> + True + + + + + True + True + 2 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 2 + 2 + + + Automatically answer when a call is received + True + True + False + True + + + + 2 + + + + + True + False + Delay before answering (ms) + + + 1 + 2 + + + + + True + True + + False + False + True + True + ajustment_auto_answer_delay + True + + + + 1 + 2 + 1 + 2 + + + + + + + + + True + False + <b>Auto-answer</b> + True + + + + + True + True + 3 + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + stock_people.png + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Manage SIP Accounts True @@ -881,6 +799,7 @@ + 2 False @@ -889,6 +808,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 True @@ -909,6 +829,9 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 2 + + + True @@ -934,7 +857,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -1110,7 +1032,6 @@ True True False - False True @@ -1121,9 +1042,6 @@ 6 - - - @@ -1159,8 +1077,8 @@ True False - 2 - 2 + 5 + 3 True @@ -1195,11 +1113,11 @@ True False - Prefered video resolution: + Preferred video resolution: - 1 - 2 + 3 + 4 @@ -1219,8 +1137,124 @@ 1 2 + 3 + 4 + + + + + True + False + Video output method: + right + + 1 2 + GTK_EXPAND + + + + + True + False + + + + + 0 + + + + + 1 + 2 + 1 + 2 + GTK_EXPAND + + + + + Show camera preview + True + True + True + + + + 2 + 3 + 5 + + GTK_EXPAND + 10 + + + + + True + False + Video preset: + + + 2 + 3 + + + + + True + False + video_preset_model + 0 + + + + + 0 + + + + + 1 + 2 + 2 + 3 + + + + + True + False + Preferred video framerate: + + + 4 + 5 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + + False + False + True + True + adjustment_video_framerate + + + + 1 + 2 + 4 + 5 + GTK_FILL + GTK_EXPAND @@ -1242,6 +1276,146 @@ 1 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + + False + False + True + True + adjustment_upload_bw + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 stands for "unlimited" + + False + False + True + True + adjustment_download_bw + + + + 1 + 2 + GTK_FILL + GTK_EXPAND + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Upload speed limit in Kbit/sec: + right + + + 1 + 2 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Download speed limit in Kbit/sec: + right + + + + + Enable adaptive rate control + True + True + False + 0 + True + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + + True + False + <i>Adaptive rate control is a technique to dynamically guess the available bandwidth during a call.</i> + True + True + + + 2 + 3 + GTK_FILL + + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Bandwidth control</b> + True + + + + + True + True + 2 + + 1 @@ -1286,113 +1460,100 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - This section defines your SIP address when not using a SIP account 0 none - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 - + True False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 3 - 2 - + True False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your display name (eg: John Doe): + + + Set Maximum Transmission Unit: + True + True + False + True + + + + True + True + 0 + + + + + True + True + False + False + True + True + adjustment_mtu + + + + True + True + 1 + + + + True + True + 0 + - + + Send DTMFs as SIP info True True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - + False + True + - 1 - 2 + True + True + 1 - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your username: - - - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Your resulting SIP address: - - - 2 - 3 - - - - + + Allow IPv6 True True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - True - True - + True + - 1 - 2 - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - False - False - True - True - - - 1 - 2 - 2 - 3 + True + True + 2 @@ -1400,15 +1561,690 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Default identity</b> + <b>Transport</b> True + + False + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 8 + 2 + + + True + False + SIP/UDP port + + + + + True + False + + + Disabled + True + True + False + True + + + + True + True + 0 + + + + + Random + True + True + False + True + + + + True + True + 1 + + + + + True + True + + True + False + False + True + True + udp_port_adjustment + + + + True + True + 2 + + + + + 1 + 2 + + + + + True + False + SIP/TCP port + + + 1 + 2 + + + + + True + False + + + Disabled + True + True + False + True + + + + True + True + 0 + + + + + Random + True + True + False + True + + + + True + True + 1 + + + + + True + True + + True + False + False + True + True + adjustment_tcp_port + + + + True + True + 2 + + + + + 1 + 2 + 1 + 2 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Audio RTP/UDP: + right + + + 2 + 3 + + + + + True + False + + + True + True + + False + False + True + True + adjustment_min_audio_port + True + + + + True + True + 0 + + + + + True + True + + True + False + False + True + True + adjustment_max_audio_port + True + + + + True + True + 1 + + + + + Fixed + True + True + False + True + + + + True + True + 2 + + + + + 1 + 2 + 2 + 3 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Video RTP/UDP: + right + + + 3 + 4 + + + + + True + False + + + True + True + + False + False + True + True + adjustment_min_video_port + True + + + + True + True + 0 + + + + + True + True + + True + False + False + True + True + adjustment_max_video_port + True + + + + True + True + 1 + + + + + Fixed + True + True + False + True + + + + True + True + 2 + + + + + 1 + 2 + 3 + 4 + + + + + True + False + Media encryption type + + + 4 + 6 + + + + + True + False + 0 + + + 1 + 2 + 4 + 5 + + + + + Media encryption is mandatory + True + True + False + True + + + + 1 + 2 + 5 + 6 + + + + + False + Tunnel + + + 7 + 8 + + + + + gtk-edit + True + True + True + + + + 1 + 2 + 7 + 8 + + + + + True + False + DSCP fields + + + 6 + 7 + + + + + gtk-edit + True + True + True + True + + + + 1 + 2 + 6 + 7 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Network protocol and ports</b> + True + + + + + False + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + + + True + False + + + Direct connection to the Internet + True + True + False + True + True + + + + False + False + 0 + + + + + Behind NAT / Firewall (specify gateway IP ) + True + True + False + True + no_nat + + + + True + True + 1 + + + + + Behind NAT / Firewall (use STUN to resolve) + True + True + False + True + no_nat + + + + True + True + 2 + + + + + Behind NAT / Firewall (use ICE) + True + True + False + True + no_nat + + + + True + True + 3 + + + + + Behind NAT / Firewall (use uPnP) + True + True + False + True + no_nat + + + + True + True + 4 + + + + + True + True + 0 + + + + + True + False + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Public IP address: + right + + + True + True + 0 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True + False + False + True + True + + + + True + True + 1 + + + + + True + False + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Stun server: + right + + + True + True + 0 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True + False + False + True + True + + + + True + True + 1 + + + + + True + False + 1 + + + + + False + False + 1 + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>NAT and Firewall</b> + True + + + + + False + True + 2 + + + + + 2 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-network + 1 + True True @@ -1416,33 +2252,60 @@ - + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Network settings + + + True + True + 1 + + + + + 2 + False + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 none - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + out - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True @@ -1453,50 +2316,21 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + center - + + gtk-go-up True True True - False - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-add - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Wizard - - - True - True - 1 - - - - + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + False @@ -1505,46 +2339,14 @@ - + + gtk-go-down True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-add - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Add - - - True - True - 1 - - - - + True + False @@ -1553,24 +2355,23 @@ - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - + - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-edit + gtk-yes True @@ -1579,11 +2380,11 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Edit + Enable True @@ -1601,24 +2402,23 @@ - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - + - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-delete + gtk-no True @@ -1627,11 +2427,11 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Remove + Disable True @@ -1651,373 +2451,6 @@ False - False - 1 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Proxy accounts</b> - True - - - - - True - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-delete - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Erase all passwords - - - True - True - 1 - - - - - - - False - False - 0 - - - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Privacy</b> - True - - - - - True - True - 2 - - - - - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - stock_people.png - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Manage SIP Accounts - - - True - True - 1 - - - - - 2 - False - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model6 - 0 - - - - - 0 - - - - - False - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - out - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - gtk-go-up - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 0 - - - - - gtk-go-down - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - - False - False - 1 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-yes - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Enable - - - True - True - 1 - - - - - - - False - False - 2 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-no - - - True - True - 0 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Disable - - - True - True - 1 - - - - - - - False - False - 3 - - - - - False - True - 1 - - - - - True True 1 @@ -2031,7 +2464,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Codecs</b> + <b>Audio codecs</b> True @@ -2043,122 +2476,182 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 none - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 3 - 2 - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" - False - False - True - True - adjustment5 - + out + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + - 1 - 2 - 1 - 2 - GTK_FILL - + True + True + 0 - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" - False - False - True - True - adjustment6 - - - - 1 - 2 - GTK_FILL - GTK_EXPAND - - - - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Upload speed limit in Kbit/sec: - right + 10 + center + + + gtk-go-up + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + False + False + 0 + + + + + gtk-go-down + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + + False + False + 1 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-yes + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Enable + + + True + True + 1 + + + + + + + False + False + 2 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-no + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Disable + + + True + True + 1 + + + + + + + False + False + 3 + + - 1 - 2 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Download speed limit in Kbit/sec: - right - - - - - Enable adaptive rate control - True - True - False - False - 0 - True - - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - - True - False - <i>Adaptive rate control is a technique to dynamically guess the available bandwidth during a call.</i> - True - True - - - 2 - 3 - GTK_FILL - + False + True + 1 @@ -2166,17 +2659,17 @@ - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Bandwidth control</b> + <b>Video codecs</b> True - True + False True 1 @@ -2225,9 +2718,10 @@ - + True False + 10 True @@ -2287,7 +2781,6 @@ True True False - False True @@ -2349,6 +2842,191 @@ False + + + True + False + 10 + + + True + False + 0 + none + + + True + False + 0 + 0 + + + True + False + 4 + 2 + True + + + + + + True + False + 1 + Server address: + + + GTK_SHRINK + GTK_SHRINK + + + + + True + False + Authentication method: + + + 1 + 2 + GTK_EXPAND | GTK_SHRINK + + + + + True + False + Username: + + + 2 + 3 + GTK_SHRINK + + + + + gtk-edit + True + True + True + True + + + + 1 + 2 + 3 + 4 + GTK_SHRINK + GTK_SHRINK + + + + + True + False + + + 1 + 2 + GTK_SHRINK + + + + + True + False + + + 1 + 2 + 1 + 2 + GTK_SHRINK + + + + + True + False + + + 1 + 2 + 2 + 3 + GTK_SHRINK + + + + + + + + + True + False + <b>LDAP Account setup</b> + True + + + + + False + True + 0 + + + + + + + + 5 + + + + + True + False + + + True + False + gtk-disconnect + + + True + True + 0 + + + + + True + False + LDAP + + + True + True + 1 + + + + + 5 + False + + + + + + + + True @@ -2368,7 +3046,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False diff --git a/gtk/password.ui b/gtk/password.ui index a355c1848..d9ce720aa 100644 --- a/gtk/password.ui +++ b/gtk/password.ui @@ -9,7 +9,6 @@ True center-on-parent dialog - False True diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 8481bef7e..59bdb2b06 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -19,37 +19,239 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" #include "linphone_tunnel.h" +#include "lpconfig.h" +#include "config.h" -typedef enum { - CAP_IGNORE, - CAP_PLAYBACK, - CAP_CAPTURE -}DeviceCap; - -static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ +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); +} + +static void linphone_gtk_ldap_display( GtkWidget* param ) +{ + LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); + LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); + GtkLabel* label; + + ms_message("linphone_gtk_ldap_display"); + label= GTK_LABEL(linphone_gtk_get_widget(param,"ldap_server")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); + + label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_auth_method")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); + + label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_username")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"username", "") ); +} + +static void linphone_gtk_ldap_set_authcombo( GtkComboBox* box, const char* authmethod ) +{ + GtkTreeModel* model = GTK_TREE_MODEL(gtk_combo_box_get_model(box)); + GtkTreeIter iter; + g_return_if_fail(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter) ); + + do{ + const char* value; + + gtk_tree_model_get(model,&iter,0,&value,-1); + if( value && strcmp(value, authmethod) == 0){ + gtk_combo_box_set_active_iter(box, &iter); + break; + } + + }while(gtk_tree_model_iter_next(model,&iter)); +} + +static void linphone_gtk_ldap_load_settings(GtkWidget* param) +{ + LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); + LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); + GtkEntry* entry; + GtkToggleButton* toggle; + GtkSpinButton* spin; + GtkComboBox* cbox; + + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_use_tls")); + gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"use_tls", 0) ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_server")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_username")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_password")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"password", "") ); + + // SASL + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_bind_dn")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"bind_dn", "") ); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_authname")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_authname", "") ); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_realm")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_realm", "") ); + + cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(param,"ldap_auth_method")); + linphone_gtk_ldap_set_authcombo(cbox, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS")); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_base_object")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_filter")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"filter", "uid=*%s*") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_name_attribute")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"name_attribute", "cn") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sip_attribute")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sip_attribute", "mobile") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_attributes")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"attributes", "cn,givenName,sn,mobile,homePhone") ); + + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_deref_aliases")); + gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"deref_aliases", 0) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_max_results")); + gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"max_results", 50) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_timeout")); + gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); + +} + + +void linphone_gtk_show_ldap_config(GtkWidget* button) +{ + GtkWidget* param = gtk_widget_get_toplevel(button); + GtkWidget* ldap_config = linphone_gtk_create_window("ldap", param); + linphone_gtk_ldap_load_settings(ldap_config); + + // to refresh parameters when the ldap config is destroyed + g_object_weak_ref(G_OBJECT(ldap_config), (GWeakNotify)linphone_gtk_ldap_display, (gpointer)param); + + gtk_widget_show(ldap_config); +} + +void linphone_gtk_ldap_reset(GtkWidget *button) +{ + GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); + ms_message("RESET LDAP"); + gtk_widget_destroy(w); +} + +void linphone_gtk_ldap_save(GtkWidget *button) +{ + LinphoneCore *lc = linphone_gtk_get_core(); + LpConfig* conf = linphone_core_get_config(lc); + LinphoneDictionary* dict = linphone_dictionary_new(); + + GtkWidget *ldap_widget = gtk_widget_get_toplevel(button); + GtkEntry* entry; + GtkToggleButton* toggle; + GtkSpinButton* spin; + GtkComboBox* cbox; + + ms_message("SAVE LDAP"); + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_use_tls")); + linphone_dictionary_set_int(dict, "use_tls", gtk_toggle_button_get_active(toggle)); + + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_server")); + linphone_dictionary_set_string(dict, "server", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_username")); + linphone_dictionary_set_string(dict, "username", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_password")); + linphone_dictionary_set_string(dict, "password", gtk_entry_get_text(entry)); + + // SASL + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_bind_dn")); + linphone_dictionary_set_string(dict, "bind_dn", gtk_entry_get_text(entry)); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_authname")); + linphone_dictionary_set_string(dict, "sasl_authname", gtk_entry_get_text(entry)); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_realm")); + linphone_dictionary_set_string(dict, "sasl_realm", gtk_entry_get_text(entry)); + + + cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(ldap_widget,"ldap_auth_method")); + linphone_dictionary_set_string(dict, "auth_method", gtk_combo_box_get_active_text(cbox)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_base_object")); + linphone_dictionary_set_string(dict, "base_object", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_filter")); + linphone_dictionary_set_string(dict, "filter", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_name_attribute")); + linphone_dictionary_set_string(dict, "name_attribute", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sip_attribute")); + linphone_dictionary_set_string(dict, "sip_attribute", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_attributes")); + linphone_dictionary_set_string(dict, "attributes", gtk_entry_get_text(entry)); + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_deref_aliases")); + linphone_dictionary_set_int(dict, "deref_aliases", gtk_toggle_button_get_active(toggle)); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_max_results")); + linphone_dictionary_set_int(dict, "max_results", gtk_spin_button_get_value(spin) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_timeout")); + linphone_dictionary_set_int(dict, "timeout", gtk_spin_button_get_value(spin) ); + + ms_message("Create LDAP from config"); + // create new LDAP according to the validated config + linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(lc, dict) ); + // save the config to linphonerc: + lp_config_load_dict_to_section(conf, "ldap", dict); + + linphone_dictionary_unref(dict); + + // close widget + gtk_widget_destroy(ldap_widget); + } void linphone_gtk_fill_video_sizes(GtkWidget *combo){ - const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; - int i,active=0; + int i; + int active=0; char vsize_def[256]; MSVideoSize cur=linphone_core_get_preferred_video_size(linphone_gtk_get_core()); + const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; /* 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*/ @@ -79,7 +281,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,47 +290,11 @@ 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"); + gtk_widget_set_sensitive(stun_entry,stunServer); + gtk_widget_set_sensitive(ip_entry,ip); } void linphone_gtk_stun_server_changed(GtkWidget *w){ @@ -217,28 +383,38 @@ void linphone_gtk_max_video_port_changed(GtkWidget *w){ } void linphone_gtk_no_firewall_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + linphone_gtk_set_propety_entry(w,FALSE,FALSE); linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyNoFirewall); + } } void linphone_gtk_use_nat_address_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + linphone_gtk_set_propety_entry(w,FALSE,TRUE); linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseNatAddress); + } } void linphone_gtk_use_stun_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + linphone_gtk_set_propety_entry(w,TRUE,FALSE); linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun); + } } void linphone_gtk_use_ice_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + linphone_gtk_set_propety_entry(w,TRUE,FALSE); linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce); + } } void linphone_gtk_use_upnp_toggled(GtkWidget *w){ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))){ + linphone_gtk_set_propety_entry(w,FALSE,FALSE); linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseUpnp); + } } void linphone_gtk_mtu_changed(GtkWidget *w){ @@ -300,6 +476,36 @@ 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_video_preset_changed(GtkWidget *w) { + gchar *sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); + GtkSpinButton *framerate = GTK_SPIN_BUTTON(linphone_gtk_get_widget(gtk_widget_get_toplevel(w), "video_framerate")); + LinphoneCore *lc = linphone_gtk_get_core(); + if (g_strcmp0(sel, "default") == 0) { + linphone_core_set_video_preset(lc, NULL); + gtk_spin_button_set_value(framerate, 0); + gtk_widget_set_sensitive(GTK_WIDGET(framerate), FALSE); + } else if (g_strcmp0(sel, "high-fps") == 0) { + linphone_core_set_video_preset(lc, "high-fps"); + gtk_spin_button_set_value(framerate, 0); + gtk_widget_set_sensitive(GTK_WIDGET(framerate), FALSE); + } else if (g_strcmp0(sel, "custom") == 0) { + linphone_core_set_video_preset(lc, "custom"); + gtk_spin_button_set_value(framerate, 30); + gtk_widget_set_sensitive(GTK_WIDGET(framerate), TRUE); + } + g_free(sel); +} + 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); @@ -347,10 +553,28 @@ static void fmtp_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_t } } +static void bitrate_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer userdata){ + GtkListStore *store=(GtkListStore*)userdata; + GtkTreeIter iter; + float newbitrate=0; + + if (!new_text) return; + + if (sscanf(new_text, "%f", &newbitrate)!=1) return; + + if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),&iter,path)){ + PayloadType *pt; + gtk_list_store_set(store,&iter,CODEC_BITRATE,newbitrate,-1); + gtk_tree_model_get(GTK_TREE_MODEL(store),&iter,CODEC_PRIVDATA,&pt,-1); + linphone_core_set_payload_type_bitrate(linphone_gtk_get_core(), pt, (int)newbitrate); + } +} + static void linphone_gtk_init_codec_list(GtkTreeView *listview){ GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *select; + GValue editable = {0}; GtkListStore *store = gtk_list_store_new (CODEC_NCOLUMNS, G_TYPE_STRING,G_TYPE_INT, G_TYPE_FLOAT, @@ -382,24 +606,34 @@ 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)"), - renderer, - "text", CODEC_BITRATE, - "foreground",CODEC_COLOR, - NULL); - gtk_tree_view_append_column (listview, column); + + g_value_init(&editable, G_TYPE_BOOLEAN); + g_value_set_boolean(&editable, TRUE); + renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Parameters"), - renderer, - "text", CODEC_PARAMS, - "foreground",CODEC_COLOR, - "editable",TRUE, - NULL); + g_object_set_property(G_OBJECT(renderer), "editable", &editable); + column = gtk_tree_view_column_new_with_attributes ( + _("IP Bitrate (kbit/s)"), + renderer, + "text", CODEC_BITRATE, + "foreground",CODEC_COLOR, + NULL); + g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(bitrate_edited),store); + gtk_tree_view_append_column (listview, column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set_property(G_OBJECT(renderer), "editable", &editable); + column = gtk_tree_view_column_new_with_attributes ( + _("Parameters"), + renderer, + "text", CODEC_PARAMS, + "foreground",CODEC_COLOR, + NULL); g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(fmtp_edited),store); gtk_tree_view_append_column (listview, column); /* Setup the selection handler */ select = gtk_tree_view_get_selection (listview); - gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); + gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); } @@ -418,7 +652,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl const MSList *elem; GtkTreeIter iter; GtkListStore *store=GTK_LIST_STORE(gtk_tree_view_get_model(listview)); - GtkTreeSelection *selection; +// GtkTreeSelection *selection; gtk_list_store_clear(store); @@ -438,7 +672,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl } /* get an iterator */ gtk_list_store_append(store,&iter); - bitrate=payload_type_get_bitrate(pt)/1000.0; + bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); rate=payload_type_get_rate(pt); if (pt->recv_fmtp!=NULL) params=pt->recv_fmtp; gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), @@ -455,8 +689,8 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl /* Setup the selection handler */ - selection = gtk_tree_view_get_selection (listview); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); +// selection = gtk_tree_view_get_selection (listview); +// gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); //gtk_tree_view_columns_autosize(GTK_TREE_VIEW (sec->interfaces)); #if GTK_CHECK_VERSION(2,12,0) gtk_tree_view_set_tooltip_column(listview,CODEC_INFO); @@ -474,7 +708,7 @@ static void linphone_gtk_check_codec_bandwidth(GtkTreeView *v){ gfloat bitrate; gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); - bitrate=payload_type_get_bitrate(pt)/1000.0; + bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR, (gpointer)get_codec_color(linphone_gtk_get_core(),pt), CODEC_BITRATE, bitrate,-1); }while(gtk_tree_model_iter_next(model,&iter)); @@ -504,24 +738,27 @@ static void linphone_gtk_draw_codec_list(GtkTreeView *v, int type){ /* 0=audio, linphone_gtk_show_codecs(v,list); } -void linphone_gtk_codec_view_changed(GtkWidget *w){ - GtkWidget *listview=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list"); - int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w)); - linphone_gtk_draw_codec_list(GTK_TREE_VIEW(listview),active); -} - void linphone_gtk_download_bw_changed(GtkWidget *w){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list")); + GtkTreeView *audiov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"audio_codec_list")); + GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"video_codec_list")); linphone_core_set_download_bandwidth(linphone_gtk_get_core(), (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); - linphone_gtk_check_codec_bandwidth(v); + linphone_gtk_check_codec_bandwidth(audiov); + linphone_gtk_check_codec_bandwidth(videov); } void linphone_gtk_upload_bw_changed(GtkWidget *w){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"codec_list")); + GtkTreeView *audiov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"audio_codec_list")); + GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"video_codec_list")); linphone_core_set_upload_bandwidth(linphone_gtk_get_core(), (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); - linphone_gtk_check_codec_bandwidth(v); + linphone_gtk_check_codec_bandwidth(audiov); + linphone_gtk_check_codec_bandwidth(videov); +} + +void linphone_gtk_video_framerate_changed(GtkWidget *w) { + linphone_core_set_preferred_framerate(linphone_gtk_get_core(), + (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))); } void linphone_gtk_adaptive_rate_control_toggled(GtkToggleButton *button){ @@ -529,17 +766,32 @@ void linphone_gtk_adaptive_rate_control_toggled(GtkToggleButton *button){ linphone_core_enable_adaptive_rate_control(linphone_gtk_get_core(),active); } -static void linphone_gtk_codec_move(GtkWidget *button, int dir){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"codec_list")); - GtkTreeSelection *sel=gtk_tree_view_get_selection(v); +static void _g_list_func_destroy_tree_path(gpointer data, gpointer user_data) { + GtkTreePath *tree_path = (GtkTreePath *)data; + gtk_tree_path_free(tree_path); +} + +static void linphone_gtk_codec_move(GtkWidget *button, int dir, int type){ /* 0=audio, 1=video*/ + GtkTreeView *v; + GtkTreeSelection *sel; GtkTreeModel *mod; GtkTreeIter iter; PayloadType *pt=NULL; LinphoneCore *lc=linphone_gtk_get_core(); - if (gtk_tree_selection_get_selected(sel,&mod,&iter)){ + + if (type == 0) v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"audio_codec_list")); + else v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); + sel=gtk_tree_view_get_selection(v); + if (gtk_tree_selection_count_selected_rows(sel) == 1){ MSList *sel_elem,*before; MSList *codec_list; + + GList *selected_rows = gtk_tree_selection_get_selected_rows(sel, &mod); + gtk_tree_model_get_iter(mod, &iter, (GtkTreePath *)g_list_nth_data(selected_rows, 0)); gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); + g_list_foreach(selected_rows, _g_list_func_destroy_tree_path, NULL); + g_list_free(selected_rows); + if (pt->type==PAYLOAD_VIDEO) codec_list=ms_list_copy(linphone_core_get_video_codecs(lc)); else codec_list=ms_list_copy(linphone_core_get_audio_codecs(lc)); @@ -563,37 +815,59 @@ static void linphone_gtk_codec_move(GtkWidget *button, int dir){ } } -static void linphone_gtk_codec_set_enable(GtkWidget *button, gboolean enabled){ - GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"codec_list")); - GtkTreeSelection *sel=gtk_tree_view_get_selection(v); - GtkTreeModel *mod; - GtkListStore *store; - GtkTreeIter iter; +static void linphone_gtk_codec_set_enable(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { PayloadType *pt=NULL; + gboolean *enabled = (gboolean *)data; + gtk_tree_model_get(model, iter, CODEC_PRIVDATA, &pt, -1); + linphone_core_enable_payload_type(linphone_gtk_get_core(), pt, *enabled); + gtk_list_store_set(GTK_LIST_STORE(model), iter, CODEC_STATUS, *enabled ? _("Enabled") : _("Disabled"), + CODEC_COLOR,(gpointer)get_codec_color(linphone_gtk_get_core(),pt), -1); +} - if (gtk_tree_selection_get_selected(sel,&mod,&iter)){ - store=GTK_LIST_STORE(mod); - gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); - linphone_core_enable_payload_type(linphone_gtk_get_core(),pt,enabled); - gtk_list_store_set(store,&iter,CODEC_STATUS, enabled ? _("Enabled") : _("Disabled"), - CODEC_COLOR,(gpointer)get_codec_color(linphone_gtk_get_core(),pt), -1); +static void linphone_gtk_codec_set_enable_all_selected(GtkWidget *button, gboolean enabled, int type){ /* 0=audio, 1=video*/ + GtkTreeView *v; + GtkTreeSelection *sel; + if (type == 0) v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"audio_codec_list")); + else v=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); + sel=gtk_tree_view_get_selection(v); + gtk_tree_selection_selected_foreach(sel, linphone_gtk_codec_set_enable, &enabled); + if (type == 0){ + /*activating audio and video codecs has consequences on video bandwidth*/ + GtkTreeView *videov=GTK_TREE_VIEW(linphone_gtk_get_widget(gtk_widget_get_toplevel(button),"video_codec_list")); + linphone_gtk_check_codec_bandwidth(videov); } } -void linphone_gtk_codec_up(GtkWidget *button){ - linphone_gtk_codec_move(button,+1); +void linphone_gtk_audio_codec_up(GtkWidget *button){ + linphone_gtk_codec_move(button,+1,0); } -void linphone_gtk_codec_down(GtkWidget *button){ - linphone_gtk_codec_move(button,-1); +void linphone_gtk_audio_codec_down(GtkWidget *button){ + linphone_gtk_codec_move(button,-1,0); } -void linphone_gtk_codec_enable(GtkWidget *button){ - linphone_gtk_codec_set_enable(button,TRUE); +void linphone_gtk_audio_codec_enable(GtkWidget *button){ + linphone_gtk_codec_set_enable_all_selected(button,TRUE,0); } -void linphone_gtk_codec_disable(GtkWidget *button){ - linphone_gtk_codec_set_enable(button,FALSE); +void linphone_gtk_audio_codec_disable(GtkWidget *button){ + linphone_gtk_codec_set_enable_all_selected(button,FALSE,0); +} + +void linphone_gtk_video_codec_up(GtkWidget *button){ + linphone_gtk_codec_move(button,+1,1); +} + +void linphone_gtk_video_codec_down(GtkWidget *button){ + linphone_gtk_codec_move(button,-1,1); +} + +void linphone_gtk_video_codec_enable(GtkWidget *button){ + linphone_gtk_codec_set_enable_all_selected(button,TRUE,1); +} + +void linphone_gtk_video_codec_disable(GtkWidget *button){ + linphone_gtk_codec_set_enable_all_selected(button,FALSE,1); } void linphone_gtk_clear_passwords(GtkWidget *button){ @@ -611,6 +885,9 @@ void linphone_gtk_show_sip_accounts(GtkWidget *w){ GtkTreeModel *model=gtk_tree_view_get_model(v); GtkListStore *store; GtkTreeSelection *select; + const LinphoneProxyConfig *default_pc = linphone_core_get_default_proxy_config(linphone_gtk_get_core()); + GtkTreePath *default_pc_path = NULL; + const MSList *elem; if (!model){ GtkCellRenderer *renderer; @@ -640,34 +917,128 @@ void linphone_gtk_show_sip_accounts(GtkWidget *w){ gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,PROXY_CONFIG_IDENTITY,linphone_proxy_config_get_identity(cfg), PROXY_CONFIG_REF,cfg,-1); + if(cfg == default_pc) default_pc_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); + } + if(default_pc_path) { + gtk_tree_selection_select_path(gtk_tree_view_get_selection(v), default_pc_path); + gtk_tree_path_free(default_pc_path); } } static void linphone_gtk_proxy_closed(GtkWidget *w){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + gboolean was_editing=! GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_new")); if (cfg){ - linphone_proxy_config_done(cfg); + if (was_editing){ + linphone_proxy_config_done(cfg); + }else linphone_proxy_config_destroy(cfg); } } +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"); + GtkWidget *w=linphone_gtk_create_window("sip_account", gtk_widget_get_toplevel(pb)); const char *tmp; - if (cfg){ + gboolean is_new=FALSE; + + if (!cfg) { + cfg=linphone_core_create_proxy_config(linphone_gtk_get_core()); + is_new=TRUE; + g_object_set_data(G_OBJECT(w),"is_new",GINT_TO_POINTER(TRUE)); + } + + if (!is_new){ 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); - 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")), - linphone_proxy_config_register_enabled(cfg)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")), - linphone_proxy_config_publish_enabled(cfg)); + 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")), + linphone_proxy_config_register_enabled(cfg)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")), + linphone_proxy_config_publish_enabled(cfg)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")), + linphone_proxy_config_avpf_enabled(cfg)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")), + linphone_proxy_config_get_avpf_rr_interval(cfg)); + g_object_set_data(G_OBJECT(w),"config",(gpointer)cfg); g_object_set_data(G_OBJECT(w),"parameters",(gpointer)pb); g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_gtk_proxy_closed,w); @@ -680,20 +1051,37 @@ 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"); - gboolean was_editing=TRUE; - if (!cfg){ - was_editing=FALSE; - cfg=linphone_proxy_config_new(); - } + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); + LinphoneTransportType tport=(LinphoneTransportType)index; + gboolean was_editing=! GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_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, @@ -702,6 +1090,23 @@ 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")))); + linphone_proxy_config_enable_avpf(cfg, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")))); + linphone_proxy_config_set_avpf_rr_interval(cfg, + (int)gtk_spin_button_get_value( + GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")))); + + /* 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; @@ -778,6 +1183,9 @@ static LangCodes supported_langs[]={ { "zh_TW" , N_("Traditional Chinese") }, { "nb_NO" , N_("Norwegian") }, { "he" , N_("Hebrew") }, + { "sr" , N_("Serbian") }, + { "ar" , N_("Arabic") }, + { "tr" , N_("Turkish") }, { NULL , NULL } }; @@ -800,14 +1208,9 @@ static void linphone_gtk_fill_langs(GtkWidget *pb){ const char *all_langs="C " LINPHONE_ALL_LANGS; const char *name; int i=0,index=0; - const char *cur_lang; - #if defined(WIN32) || defined(__APPLE__) - cur_lang=getenv("LANG"); - #else - cur_lang=getenv("LANGUAGE"); - #endif int cur_lang_index=-1; char text[256]={0}; + const char *cur_lang = g_getenv("LANGUAGE"); if (cur_lang==NULL) cur_lang="C"; /* glade creates a combo box without list model and text renderer, unless we fill it with a dummy text. @@ -829,18 +1232,13 @@ static void linphone_gtk_fill_langs(GtkWidget *pb){ void linphone_gtk_lang_changed(GtkComboBox *combo){ const char *selected=gtk_combo_box_get_active_text(combo); char code[10]; - const char *cur_lang; - #if defined(WIN32) || defined(__APPLE__) - cur_lang=getenv("LANG"); - #else - cur_lang=getenv("LANGUAGE"); - #endif + const char *cur_lang=g_getenv("LANGUAGE"); if (selected!=NULL){ sscanf(selected,"%s",code); if (cur_lang==NULL) cur_lang="C"; if (!lang_equals(cur_lang,code)){ GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(combo))), - GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", @@ -855,19 +1253,11 @@ 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"); + const char *simple_ui = linphone_gtk_get_ui_config("simple_ui", "parameters.codec_tab parameters.transport_frame parameters.ports_frame parameters.bandwidth_frame"); - ui_advanced = linphone_gtk_get_ui_config_int("advanced_ui", TRUE); + ui_advanced = linphone_gtk_get_ui_config_int("advanced_ui", FALSE); if (ui_advanced) { linphone_gtk_visibility_set(simple_ui, "parameters", top, TRUE); } else { @@ -898,11 +1288,13 @@ static void linphone_gtk_media_encryption_changed(GtkWidget *combo){ if (strcasecmp(selected,"SRTP")==0){ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,TRUE); + }else if (strcasecmp(selected,"DTLS")==0){ + linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionDTLS); + linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); }else if (strcasecmp(selected,"ZRTP")==0){ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); - } - else { + } else { linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); } @@ -918,32 +1310,46 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo"); bool_t no_enc=TRUE; - int srtp_id=-1,zrtp_id=-1; + int srtp_id=-1,zrtp_id=-1,dtls_id=-1; GtkTreeModel *model; GtkListStore *store; GtkTreeIter iter; GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - + model=GTK_TREE_MODEL((store=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); - + gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("None"),-1); - + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){ gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("SRTP"),-1); srtp_id=1; no_enc=FALSE; } + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionDTLS)){ + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,_("DTLS"),-1); + if (srtp_id!=-1) dtls_id=2; + else dtls_id=1; + no_enc=FALSE; + } if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){ gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("ZRTP"),-1); no_enc=FALSE; - if (srtp_id!=-1) zrtp_id=2; - else zrtp_id=1; + if (srtp_id!=-1) { + if (dtls_id!=-1) + zrtp_id=3; + else zrtp_id=2; + } else { + if (dtls_id!=-1) + zrtp_id=2; + else zrtp_id=1; + } } if (no_enc){ /*hide this setting*/ @@ -963,6 +1369,12 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); } break; + case LinphoneMediaEncryptionDTLS: + if (dtls_id!=-1) { + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),dtls_id); + linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); + } + break; case LinphoneMediaEncryptionZRTP: if (zrtp_id!=-1) { gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id); @@ -979,7 +1391,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); } @@ -1000,6 +1411,162 @@ void linphone_gtk_fill_webcams(GtkWidget *pb){ linphone_core_get_video_device(lc),CAP_IGNORE); } +void linphone_gtk_fill_video_renderers(GtkWidget *pb){ +#ifdef VIDEO_ENABLED /* video_stream_get_default_video_renderer requires video enabled */ + 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)); + + if (current_renderer==NULL) current_renderer=video_stream_get_default_video_renderer(); + + 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){ + MSFilterDesc *desc=(MSFilterDesc *)elem->data; + GtkTreeIter iter; + + /* do not offer the user to select combo 'decoding/rendering' filter */ + if (desc->enc_fmt != NULL) + continue; + + 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; + + i++; + } + ms_list_free(l); + if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); +#endif +} + +void linphone_gtk_fill_video_presets(GtkWidget *pb) { + GtkComboBox *combo = GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "video_preset")); + const char *preset = linphone_core_get_video_preset(linphone_gtk_get_core()); + if (preset == NULL) { + gtk_combo_box_set_active(combo, -1); + gtk_combo_box_set_active(combo, 0); + } else { + gboolean valid; + GtkTreeIter iter; + gchar *str_data; + GtkTreeModel *model = gtk_combo_box_get_model(combo); + valid = gtk_tree_model_get_iter_first(model, &iter); + while (valid) { + gtk_tree_model_get(model, &iter, 0, &str_data, -1); + if (g_strcmp0(preset, str_data) == 0) { + gtk_combo_box_set_active_iter(combo, &iter); + break; + } + valid = gtk_tree_model_iter_next(model, &iter); + } + } +} + +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 PortConfigCtx* get_port_config() { + 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->timeout_id=g_timeout_add_seconds(2,(GSourceFunc)apply_transports,cfg); + return cfg; +} + +static void transport_changed(GtkWidget *parameters){ + PortConfigCtx *cfg = get_port_config(); + + GtkWidget *udp_random_port=linphone_gtk_get_widget(parameters,"random_udp_port"); + GtkWidget *tcp_random_port=linphone_gtk_get_widget(parameters,"random_tcp_port"); + + GtkWidget *sip_udp_port=linphone_gtk_get_widget(parameters,"sip_udp_port"); + GtkWidget *sip_tcp_port=linphone_gtk_get_widget(parameters,"sip_tcp_port"); + + gboolean udp_is_disabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(parameters,"disabled_udp_port"))); + gboolean tcp_is_disabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(parameters,"disabled_tcp_port"))); + + gboolean udp_is_random=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(udp_random_port)); + gboolean tcp_is_random=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tcp_random_port)); + + int udp_port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sip_udp_port)); + int tcp_port = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sip_tcp_port)); + + + gtk_widget_set_sensitive(udp_random_port, !udp_is_disabled); + gtk_widget_set_sensitive(tcp_random_port, !tcp_is_disabled); + gtk_widget_set_sensitive(sip_udp_port, !udp_is_disabled && !udp_is_random); + gtk_widget_set_sensitive(sip_tcp_port, !tcp_is_disabled && !tcp_is_random); + + cfg->tp.udp_port=udp_is_disabled?0:udp_is_random?-1:udp_port; + cfg->tp.tcp_port=tcp_is_disabled?0:tcp_is_random?-1:tcp_port; +} + +void linphone_gtk_disabled_udp_port_toggle(GtkCheckButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + +void linphone_gtk_random_udp_port_toggle(GtkCheckButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + +void linphone_gtk_udp_port_value_changed(GtkSpinButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + +void linphone_gtk_disabled_tcp_port_toggle(GtkCheckButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + +void linphone_gtk_random_tcp_port_toggle(GtkCheckButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + +void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button){ + GtkWidget *parameters = gtk_widget_get_toplevel((GtkWidget*)button); + transport_changed(parameters); +} + void linphone_gtk_show_parameters(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); @@ -1007,41 +1574,34 @@ void linphone_gtk_show_parameters(void){ const char *tmp; LinphoneAddress *contact; LinphoneFirewallPolicy pol; - GtkWidget *codec_list; + GtkWidget *audio_codec_list; + GtkWidget *video_codec_list; int mtu; int ui_advanced; LCSipTransports tr; int min_port = 0, max_port = 0; if (pb==NULL) { - pb=linphone_gtk_create_window("parameters"); + pb=linphone_gtk_create_window("parameters", linphone_gtk_get_main_window()); g_object_set_data(G_OBJECT(mw),"parameters",pb); }else { gtk_widget_show(pb); return; } - codec_list=linphone_gtk_get_widget(pb,"codec_list"); + audio_codec_list=linphone_gtk_get_widget(pb,"audio_codec_list"); + video_codec_list=linphone_gtk_get_widget(pb,"video_codec_list"); /* NETWORK CONFIG */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ipv6_enabled")), 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")), - tr.udp_port); - } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"disabled_udp_port")), tr.udp_port==0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"disabled_tcp_port")), tr.tcp_port==0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"random_udp_port")), tr.udp_port==-1); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"random_tcp_port")), tr.tcp_port==-1); + 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); @@ -1059,7 +1619,7 @@ void linphone_gtk_show_parameters(void){ } linphone_gtk_show_media_encryption(pb); - + tmp=linphone_core_get_nat_address(lc); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp); tmp=linphone_core_get_stun_server(lc); @@ -1082,7 +1642,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")); } @@ -1101,13 +1661,18 @@ 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_presets(pb); linphone_gtk_fill_video_sizes(linphone_gtk_get_widget(pb,"video_size")); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_framerate")), + linphone_core_get_preferred_framerate(lc)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"echo_cancelation")), linphone_core_echo_cancellation_enabled(lc)); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(linphone_gtk_get_widget(pb,"ring_chooser")), linphone_core_get_ring(lc)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"adaptive_rate_control")), + linphone_core_adaptive_rate_control_enabled(lc)); /* SIP CONFIG */ contact=linphone_core_get_primary_contact_parsed(lc); if (contact){ @@ -1117,20 +1682,27 @@ void linphone_gtk_show_parameters(void){ } if (linphone_address_get_username(contact)) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username")),linphone_address_get_username(contact)); + linphone_address_destroy(contact); } - linphone_address_destroy(contact); +#ifdef BUILD_WIZARD + gtk_widget_show(linphone_gtk_get_widget(pb,"wizard")); +#else + gtk_widget_hide(linphone_gtk_get_widget(pb,"wizard")); +#endif linphone_gtk_show_sip_accounts(pb); /* CODECS CONFIG */ - linphone_gtk_init_codec_list(GTK_TREE_VIEW(codec_list)); - linphone_gtk_draw_codec_list(GTK_TREE_VIEW(codec_list),0); - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"codec_view")),0); + linphone_gtk_init_codec_list(GTK_TREE_VIEW(audio_codec_list)); + linphone_gtk_init_codec_list(GTK_TREE_VIEW(video_codec_list)); + linphone_gtk_draw_codec_list(GTK_TREE_VIEW(audio_codec_list), 0); + linphone_gtk_draw_codec_list(GTK_TREE_VIEW(video_codec_list), 1); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"download_bw")), linphone_core_get_download_bandwidth(lc)); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"upload_bw")), linphone_core_get_upload_bandwidth(lc)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"adaptive_rate_control")), - linphone_core_adaptive_rate_control_enabled(lc)); + /* CALL PARAMS CONFIG */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb, "auto_answer_checkbox")), linphone_gtk_get_ui_config_int("auto_answer", 0)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "auto_answer_delay_spinbutton")), linphone_gtk_get_ui_config_int("auto_answer_delay", 2000)); /* UI CONFIG */ linphone_gtk_fill_langs(pb); @@ -1140,15 +1712,20 @@ 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); } + /* LDAP CONFIG */ + if( linphone_gtk_is_ldap_supported() ) { // if LDAP provider is available + linphone_gtk_ldap_display(pb); + } else { + // hide the LDAP tab + GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); + gtk_notebook_remove_page(notebook,5); + } + gtk_widget_show(pb); } @@ -1184,20 +1761,20 @@ 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){ - GtkWidget *w=linphone_gtk_create_window("tunnel_config"); + GtkWidget *w=linphone_gtk_create_window("tunnel_config", gtk_widget_get_toplevel(GTK_WIDGET(button))); LinphoneCore *lc=linphone_gtk_get_core(); LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); const MSList *configs; const char *host = NULL; int port=0; - + if (!tunnel) return; - + configs = linphone_tunnel_get_servers(tunnel); if(configs != NULL) { LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data; @@ -1209,7 +1786,7 @@ void linphone_gtk_edit_tunnel(GtkButton *button){ if (port==0) port=443; gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"port")), port); - if (linphone_tunnel_enabled(tunnel)){ + if (linphone_tunnel_get_mode(tunnel)){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_enable")),1); } else{ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"radio_disable")),1); @@ -1245,7 +1822,7 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ gint http_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port"))); const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username"))); const char *password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password"))); - + if (tunnel==NULL) return; if (host && *host=='\0') host=NULL; if (http_port==0) http_port=8080; @@ -1253,9 +1830,9 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ linphone_tunnel_config_set_host(config, host); linphone_tunnel_config_set_port(config, port); linphone_tunnel_add_server(tunnel, config); - linphone_tunnel_enable(tunnel,enabled); + linphone_tunnel_set_mode(tunnel, (enabled ? LinphoneTunnelModeEnable : LinphoneTunnelModeDisable)); linphone_tunnel_set_http_proxy(tunnel,http_host,http_port,username,password); - + gtk_widget_destroy(w); } @@ -1268,7 +1845,7 @@ static void show_dscp(GtkWidget *entry, int val){ char tmp[20]; snprintf(tmp,sizeof(tmp),"0x%x",val); gtk_entry_set_text(GTK_ENTRY(entry),tmp); - + } static int read_dscp(GtkWidget *entry){ @@ -1285,9 +1862,9 @@ static int read_dscp(GtkWidget *entry){ return -1; } -void linphone_gtk_dscp_edit(){ +void linphone_gtk_dscp_edit(void){ LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *widget=linphone_gtk_create_window("dscp_settings"); + GtkWidget *widget=linphone_gtk_create_window("dscp_settings", linphone_gtk_get_main_window()); show_dscp(linphone_gtk_get_widget(widget,"sip_dscp"), linphone_core_get_sip_dscp(lc)); show_dscp(linphone_gtk_get_widget(widget,"audio_dscp"), @@ -1307,10 +1884,32 @@ void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){ read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp"))); linphone_core_set_video_dscp(lc, read_dscp(linphone_gtk_get_widget(dialog,"video_dscp"))); - + break; default: break; } gtk_widget_destroy(dialog); } + +void linphone_gtk_enable_auto_answer(GtkToggleButton *checkbox, gpointer user_data) { + gboolean auto_answer_enabled = gtk_toggle_button_get_active(checkbox); + linphone_gtk_set_ui_config_int("auto_answer", auto_answer_enabled ? 1 : 0); +} + +void linphone_gtk_auto_answer_delay_changed(GtkSpinButton *spinbutton, gpointer user_data) { + int delay = gtk_spin_button_get_value(spinbutton); + linphone_gtk_set_ui_config_int("auto_answer_delay", delay); +} + +void linphone_gtk_notebook_current_page_changed (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) { +#ifndef HAVE_LIBUDEV_H + if (page_num == 1) { + // Multimedia settings - we reload audio and video devices to detect + // hot-plugged devices + g_message("Opened multimedia page... reloading audio and video devices!"); + linphone_gtk_reload_sound_devices(); + linphone_gtk_reload_video_devices(); + } +#endif +} diff --git a/gtk/provisioning-fetch.ui b/gtk/provisioning-fetch.ui new file mode 100644 index 000000000..e2d6a0203 --- /dev/null +++ b/gtk/provisioning-fetch.ui @@ -0,0 +1,53 @@ + + + + + + False + 5 + Configuring... + dialog + True + Please wait while fetching configuration from server... + + + True + False + 2 + + + True + False + end + + + + + + + + + False + True + end + 0 + + + + + True + False + + + + + + True + True + 2 + + + + + + diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index f4374c539..c7cd6a195 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -20,113 +20,213 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" #include #include -static LinphoneAccountCreator *linphone_gtk_assistant_get_creator(GtkWidget*w); static const int PASSWORD_MIN_SIZE = 6; static const int LOGIN_MIN_SIZE = 4; +static GtkWidget *the_assistant = NULL; -static GtkWidget *the_assistant=NULL; -static GdkPixbuf *ok; -static GdkPixbuf *notok; -static GtkWidget *create_intro(){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *label=gtk_label_new(_("Welcome !\nThis assistant will help you to use a SIP account for your calls.")); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); - g_object_set_data(G_OBJECT(vbox),"label",label); +static LinphoneAccountCreator * linphone_gtk_assistant_get_creator(GtkWidget *w) { + return (LinphoneAccountCreator *)g_object_get_data(G_OBJECT(w), "creator"); +} + +static void linphone_gtk_account_validate_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status) { + GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); + if (status == LinphoneAccountCreatorOk) { + // Go to page_6_linphone_account_validation_wait + gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 6); + } else { // Error when attempting to create the account + // Go to page_8_error + gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 8); + } + gtk_assistant_commit(GTK_ASSISTANT(assistant)); +} + +static void create_account(GtkWidget *assistant) { + LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); + linphone_account_creator_validate(creator); +} + +static void linphone_gtk_test_account_validation_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status) { + GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); + if (status == LinphoneAccountCreatorOk) { + // Go to page_9_finish + gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 9); + } else { + // Go to page_8_error + gtk_assistant_set_current_page(GTK_ASSISTANT(assistant), 8); + } +} + +static void check_account_validation(GtkWidget *assistant) { + LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); + linphone_account_creator_test_validation(creator); +} + +static void linphone_gtk_assistant_closed(GtkWidget *w) { + linphone_gtk_close_assistant(); +} + +static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page) { + int pagenum = gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); + + switch (pagenum) { + case 5: + create_account(assistant); + break; + case 7: + check_account_validation(assistant); + break; + case 9: + if (linphone_account_creator_configure(linphone_gtk_assistant_get_creator(assistant)) != NULL) { + linphone_gtk_load_identities(); + } + gtk_assistant_commit(GTK_ASSISTANT(assistant)); + break; + default: + break; + } +} + +static gint destroy_assistant(GtkWidget* w){ + gtk_widget_destroy(w); + the_assistant = NULL; + return FALSE; +} + +static int linphone_gtk_assistant_forward(int curpage, gpointer data) { + GtkWidget *w = GTK_WIDGET(data); + GtkWidget *box = gtk_assistant_get_nth_page(GTK_ASSISTANT(w), curpage); + LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(w); + + switch (curpage) { + case 0: + curpage = 1; // Go to page_1_choice + break; + case 1: + { + GtkWidget *create_button = (GtkWidget*)g_object_get_data(G_OBJECT(box), "create_account"); + GtkWidget *setup_linphone_account = (GtkWidget*)g_object_get_data(G_OBJECT(box), "setup_linphone_account"); + GtkWidget *setup_account = (GtkWidget*)g_object_get_data(G_OBJECT(box), "setup_account"); + GtkWidget *config_uri = (GtkWidget*)g_object_get_data(G_OBJECT(box), "config-uri"); + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(create_button))) { + curpage = 4; // Go to page_4_linphone_account_creation_configuration + } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_linphone_account))) { + curpage = 3; // Go to page_3_linphone_account_configuration + } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_account))) { + curpage = 2; // Go to page_2_external_account_configuration + } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_uri))) { + /* Destroy the assistant and popup config-uri dialog */ + gtk_widget_hide(w); + linphone_gtk_set_configuration_uri(); + curpage = 0; + g_idle_add((GSourceFunc)destroy_assistant, w); + } + } + break; + case 2: + linphone_account_creator_set_username(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"username")))); + linphone_account_creator_set_domain(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"domain")))); + linphone_account_creator_set_route(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "proxy")))); + linphone_account_creator_set_password(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "password")))); + curpage = 9; // Go to page_9_finish + break; + case 3: + linphone_account_creator_set_username(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"username")))); + linphone_account_creator_set_domain(creator, "sip.linphone.org"); + linphone_account_creator_set_route(creator, "sip.linphone.org"); + linphone_account_creator_set_password(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "password")))); + curpage = 9; // Go to page_9_finish + break; + case 4: + linphone_account_creator_set_username(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "username")))); + linphone_account_creator_set_password(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "password")))); + linphone_account_creator_set_email(creator, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box), "email")))); + linphone_account_creator_enable_newsletter_subscription(creator, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(box), "newsletter")))); + curpage = 5; // Go to page_5_linphone_account_creation_in_progress + break; + case 6: + curpage = 7; // Go to page_7_linphone_account_validation_check_in_progress + break; + default: + break; + } + return curpage; +} + +static GtkWidget * create_intro_page(void) { + GtkWidget *vbox = gtk_vbox_new(FALSE, 2); + GtkWidget *label = gtk_label_new(_("Welcome!\nThis assistant will help you to use a SIP account for your calls.")); + gtk_box_pack_start(GTK_BOX (vbox), label, TRUE, TRUE, 2); + g_object_set_data(G_OBJECT(vbox), "label", label); gtk_widget_show_all(vbox); return vbox; } -static GtkWidget *create_setup_signin_choice(){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *t1=gtk_radio_button_new_with_label(NULL,_("Create an account on linphone.org")); - GtkWidget *t2=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1),_("I have already a linphone.org account and I just want to use it")); - GtkWidget *t3=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1),_("I have already a sip account and I just want to use it")); - gtk_box_pack_start (GTK_BOX (vbox), t1, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), t2, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), t3, TRUE, TRUE, 2); +static GtkWidget * create_choice_page(void) { + GtkWidget *vbox = gtk_vbox_new(FALSE, 2); + GtkWidget *t1 = gtk_radio_button_new_with_label(NULL, _("Create an account on linphone.org")); + GtkWidget *t2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1), _("I have already a linphone.org account and I just want to use it")); + GtkWidget *t3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1), _("I have already a sip account and I just want to use it")); + GtkWidget *t4 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1), _("I want to specify a remote configuration URI")); + + gtk_box_pack_start(GTK_BOX (vbox), t1, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX (vbox), t2, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX (vbox), t3, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX (vbox), t4, TRUE, TRUE, 2); gtk_widget_show_all(vbox); - g_object_set_data(G_OBJECT(vbox),"create_account",t1); - g_object_set_data(G_OBJECT(vbox),"setup_linphone_account",t2); - g_object_set_data(G_OBJECT(vbox),"setup_account",t3); + g_object_set_data(G_OBJECT(vbox), "create_account", t1); + g_object_set_data(G_OBJECT(vbox), "setup_linphone_account", t2); + g_object_set_data(G_OBJECT(vbox), "setup_account", t3); + g_object_set_data(G_OBJECT(vbox), "config-uri", t4); return vbox; } -static int all_account_information_entered(GtkWidget *w) { - GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"username")); - GtkEntry* domain = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"domain")); +static int external_account_configuration_complete(GtkWidget *w) { + GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "username")); + GtkEntry* domain = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "domain")); - 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("^(sip:)?([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$", gtk_entry_get_text(domain), 0, 0)) { + if ((gtk_entry_get_text_length(username) > 0) + && (gtk_entry_get_text_length(domain) > 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; } return 0; } -static void account_informations_changed(GtkEntry *entry, GtkWidget *w) { - GtkWidget *assistant=gtk_widget_get_toplevel(w); - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - all_account_information_entered(w)>0); +static void external_account_configuration_changed(GtkEntry *entry, GtkWidget *w) { + GtkWidget *assistant = gtk_widget_get_toplevel(w); + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), w, external_account_configuration_complete(w) > 0); } -static void linphone_account_informations_changed(GtkEntry *entry, GtkWidget *w) { - GtkWidget *assistant=gtk_widget_get_toplevel(w); - GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"username")); - - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - gtk_entry_get_text_length(username) >= LOGIN_MIN_SIZE); -} - -static GtkWidget *create_linphone_account_informations_page() { - GtkWidget *vbox=gtk_table_new(3, 2, TRUE); - GtkWidget *label=gtk_label_new(_("Enter your linphone.org username")); - +static GtkWidget * create_external_account_configuration_page(void) { + GtkWidget *vbox = gtk_table_new(6, 2, FALSE); + GtkWidget *label = gtk_label_new(_("Enter your account information")); GdkColor color; - gdk_color_parse ("red", &color); - GtkWidget *labelEmpty=gtk_label_new(NULL); + GtkWidget *labelEmpty; + GtkWidget *labelUsername; + GtkWidget *labelPassword; + GtkWidget *entryPassword; + GtkWidget *labelDomain; + GtkWidget *labelProxy; + GtkWidget *entryUsername; + GtkWidget *entryDomain; + GtkWidget *entryRoute; + + gdk_color_parse("red", &color); + labelEmpty = gtk_label_new(NULL); gtk_widget_modify_fg(labelEmpty, GTK_STATE_NORMAL, &color); - - GtkWidget *labelUsername=gtk_label_new(_("Username:")); - GtkWidget *entryUsername=gtk_entry_new(); - GtkWidget *labelPassword=gtk_label_new(_("Password:")); - GtkWidget *entryPassword=gtk_entry_new(); + labelUsername = gtk_label_new(_("Username*")); + labelPassword = gtk_label_new(_("Password*")); + entryPassword = gtk_entry_new(); gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE); - - gtk_table_attach_defaults(GTK_TABLE(vbox), label, 0, 2, 0, 1); - gtk_table_attach_defaults(GTK_TABLE(vbox), labelUsername, 0, 1, 1, 2); - gtk_table_attach_defaults(GTK_TABLE(vbox), entryUsername, 1, 2, 1, 2); - gtk_table_attach_defaults(GTK_TABLE(vbox), labelPassword, 0, 1, 2, 3); - gtk_table_attach_defaults(GTK_TABLE(vbox), entryPassword, 1, 2, 2, 3); - - gtk_widget_show_all(vbox); - g_object_set_data(G_OBJECT(vbox),"username",entryUsername); - g_object_set_data(G_OBJECT(vbox),"password",entryPassword); - g_object_set_data(G_OBJECT(vbox),"errorstring",labelEmpty); - g_signal_connect(G_OBJECT(entryUsername),"changed",(GCallback)linphone_account_informations_changed,vbox); - return vbox; -} - -static GtkWidget *create_account_informations_page() { - GtkWidget *vbox=gtk_table_new(6, 2, FALSE); - GtkWidget *label=gtk_label_new(_("Enter your account informations")); - - GdkColor color; - gdk_color_parse ("red", &color); - GtkWidget *labelEmpty=gtk_label_new(NULL); - gtk_widget_modify_fg(labelEmpty, GTK_STATE_NORMAL, &color); - - GtkWidget *labelUsername=gtk_label_new(_("Username*")); - GtkWidget *labelPassword=gtk_label_new(_("Password*")); - GtkWidget *entryPassword=gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE); - GtkWidget *labelDomain=gtk_label_new(_("Domain*")); - GtkWidget *labelProxy=gtk_label_new(_("Proxy")); - GtkWidget *entryUsername=gtk_entry_new(); - GtkWidget *entryDomain=gtk_entry_new(); - GtkWidget *entryRoute=gtk_entry_new(); + labelDomain = gtk_label_new(_("Domain*")); + labelProxy = gtk_label_new(_("Proxy")); + entryUsername = gtk_entry_new(); + entryDomain = gtk_entry_new(); + entryRoute = gtk_entry_new(); gtk_table_attach_defaults(GTK_TABLE(vbox), label, 0, 2, 0, 1); gtk_table_attach_defaults(GTK_TABLE(vbox), labelUsername, 0, 1, 1, 2); @@ -140,188 +240,216 @@ static GtkWidget *create_account_informations_page() { gtk_table_attach_defaults(GTK_TABLE(vbox), labelEmpty, 0, 2, 5, 6); gtk_widget_show_all(vbox); - g_object_set_data(G_OBJECT(vbox),"username",entryUsername); - g_object_set_data(G_OBJECT(vbox),"password",entryPassword); - g_object_set_data(G_OBJECT(vbox),"domain",entryDomain); - g_object_set_data(G_OBJECT(vbox),"proxy",entryRoute); - g_object_set_data(G_OBJECT(vbox),"errorstring",labelEmpty); - g_signal_connect(G_OBJECT(entryUsername),"changed",(GCallback)account_informations_changed,vbox); - g_signal_connect(G_OBJECT(entryDomain),"changed",(GCallback)account_informations_changed,vbox); - g_signal_connect(G_OBJECT(entryRoute),"changed",(GCallback)account_informations_changed,vbox); + g_object_set_data(G_OBJECT(vbox), "username", entryUsername); + g_object_set_data(G_OBJECT(vbox), "password", entryPassword); + g_object_set_data(G_OBJECT(vbox), "domain", entryDomain); + g_object_set_data(G_OBJECT(vbox), "proxy", entryRoute); + g_object_set_data(G_OBJECT(vbox), "errorstring", labelEmpty); + g_signal_connect(G_OBJECT(entryUsername), "changed", (GCallback)external_account_configuration_changed, vbox); + g_signal_connect(G_OBJECT(entryDomain), "changed", (GCallback)external_account_configuration_changed, vbox); + g_signal_connect(G_OBJECT(entryRoute), "changed", (GCallback)external_account_configuration_changed, vbox); return vbox; } -static int create_account(GtkWidget *page) { - LinphoneAccountCreator *creator=linphone_gtk_assistant_get_creator(gtk_widget_get_toplevel(page)); - LinphoneProxyConfig *res=linphone_account_creator_validate(creator); - if (res) { - if (!g_regex_match_simple("^sip:[a-zA-Z]+[a-zA-Z0-9.\\-_]{2,}@sip.linphone.org$",creator->username, 0, 0)) { - gchar identity[128]; - g_snprintf(identity, sizeof(identity), "sip:%s@sip.linphone.org", creator->username); - linphone_account_creator_set_username(creator, identity); - linphone_account_creator_set_domain(creator, "sip:sip.linphone.org"); - } +static void linphone_account_configuration_changed(GtkEntry *entry, GtkWidget *w) { + GtkWidget *assistant = gtk_widget_get_toplevel(w); + GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "username")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), w, gtk_entry_get_text_length(username) > 0); +} + +static GtkWidget * create_linphone_account_configuration_page(void) { + GtkWidget *vbox = gtk_table_new(3, 2, TRUE); + GtkWidget *label = gtk_label_new(_("Enter your linphone.org username")); + GdkColor color; + GtkWidget *labelEmpty; + GtkWidget *labelUsername; + GtkWidget *entryUsername; + GtkWidget *labelPassword; + GtkWidget *entryPassword; + + gdk_color_parse("red", &color); + labelEmpty = gtk_label_new(NULL); + gtk_widget_modify_fg(labelEmpty, GTK_STATE_NORMAL, &color); + + labelUsername = gtk_label_new(_("Username:")); + entryUsername = gtk_entry_new(); + labelPassword = gtk_label_new(_("Password:")); + entryPassword = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE); + + gtk_table_attach_defaults(GTK_TABLE(vbox), label, 0, 2, 0, 1); + gtk_table_attach_defaults(GTK_TABLE(vbox), labelUsername, 0, 1, 1, 2); + gtk_table_attach_defaults(GTK_TABLE(vbox), entryUsername, 1, 2, 1, 2); + gtk_table_attach_defaults(GTK_TABLE(vbox), labelPassword, 0, 1, 2, 3); + gtk_table_attach_defaults(GTK_TABLE(vbox), entryPassword, 1, 2, 2, 3); + + gtk_widget_show_all(vbox); + g_object_set_data(G_OBJECT(vbox), "username", entryUsername); + g_object_set_data(G_OBJECT(vbox), "password", entryPassword); + g_object_set_data(G_OBJECT(vbox), "errorstring", labelEmpty); + g_signal_connect(G_OBJECT(entryUsername), "changed", (GCallback)linphone_account_configuration_changed, vbox); + return vbox; +} + +static int linphone_account_creation_configuration_correct(GtkWidget *w) { + int is_username_available = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_username_available")); + int is_email_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_email_correct")); + int is_password_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_password_correct")); + if ((is_username_available == 1) && (is_email_correct == 1) && (is_password_correct == 1)) { return 1; } return 0; } -static int is_account_information_correct(GtkWidget *w) { - int is_username_available = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_username_available")); - int is_email_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_email_correct")); - int is_password_correct = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_password_correct")); - - if (is_username_available == 1 && is_email_correct == 1 && is_password_correct == 1) { - return 1; - } - return 0; -} - -static void account_email_changed(GtkEntry *entry, GtkWidget *w) { - // Verifying if email entered is correct, and if form is correctly filled, let the user go next page - - GtkEntry* email = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"email")); - GtkImage* isEmailOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w),"emailOk")); - GtkWidget *assistant=gtk_widget_get_toplevel(w); - - if (g_regex_match_simple("^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$", gtk_entry_get_text(email), 0, 0)) { - g_object_set_data(G_OBJECT(w),"is_email_correct",GINT_TO_POINTER(1)); - gtk_image_set_from_pixbuf(isEmailOk, ok); - } - else { - g_object_set_data(G_OBJECT(w),"is_email_correct",GINT_TO_POINTER(0)); - gtk_image_set_from_pixbuf(isEmailOk, notok); - } - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - is_account_information_correct(w)>0); -} - -static void account_password_changed(GtkEntry *entry, GtkWidget *w) { - // Verifying if passwords entered match, and if form is correctly filled, let the user go next page - - GtkEntry* password = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"password")); - GtkImage* isPasswordOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w),"passwordOk")); - GtkEntry* password_confirm = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"password_confirm")); - GtkWidget *assistant=gtk_widget_get_toplevel(w); - GtkLabel* passwordError = GTK_LABEL(g_object_get_data(G_OBJECT(w),"error")); - - if (gtk_entry_get_text_length(password) >= PASSWORD_MIN_SIZE && - g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) == 0) { - g_object_set_data(G_OBJECT(w),"is_password_correct",GINT_TO_POINTER(1)); - gtk_image_set_from_pixbuf(isPasswordOk, ok); - gtk_label_set_text(passwordError, ""); - } - else { - if (gtk_entry_get_text_length(password) < PASSWORD_MIN_SIZE) { - gtk_label_set_text(passwordError, "Password is too short !"); - } - else if (!g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) == 0) { - gtk_label_set_text(passwordError, "Passwords don't match !"); - } - g_object_set_data(G_OBJECT(w),"is_password_correct",GINT_TO_POINTER(0)); - gtk_image_set_from_pixbuf(isPasswordOk, notok); - } - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - is_account_information_correct(w)>0); -} - -gboolean update_interface_with_username_availability(gpointer *w) { +static gboolean update_interface_with_username_availability(void *w) { GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(w)); - GtkImage* isUsernameOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w),"usernameOk")); - GtkLabel* usernameError = GTK_LABEL(g_object_get_data(G_OBJECT(w),"error")); - int account_existing = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_username_used")); + GtkImage* isUsernameOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w), "usernameOk")); + GtkLabel* usernameError = GTK_LABEL(g_object_get_data(G_OBJECT(w), "error")); + int account_existing = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "is_username_used")); if (account_existing == 0) { - g_object_set_data(G_OBJECT(w),"is_username_available",GINT_TO_POINTER(1)); - gtk_image_set_from_pixbuf(isUsernameOk, ok); + GdkPixbuf *ok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "ok_pixbuf")); + g_object_set_data(G_OBJECT(w), "is_username_available", GINT_TO_POINTER(1)); + gtk_image_set_from_pixbuf(isUsernameOk, ok_pixbuf); gtk_label_set_text(usernameError, ""); + } else { + GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf")); + gtk_label_set_text(usernameError, "Username is already in use!"); + g_object_set_data(G_OBJECT(w), "is_username_available", GINT_TO_POINTER(0)); + gtk_image_set_from_pixbuf(isUsernameOk, nok_pixbuf); } - else { - gtk_label_set_text(usernameError, "Username is already in use !"); - g_object_set_data(G_OBJECT(w),"is_username_available",GINT_TO_POINTER(0)); - gtk_image_set_from_pixbuf(isUsernameOk, notok); - } - - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),GTK_WIDGET(w), - is_account_information_correct(GTK_WIDGET(w))>0); - + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), GTK_WIDGET(w), linphone_account_creation_configuration_correct(GTK_WIDGET(w)) > 0); return FALSE; } -void* check_username_availability(void* w) { - LinphoneAccountCreator *creator=linphone_gtk_assistant_get_creator(gtk_widget_get_toplevel(GTK_WIDGET(w))); - - int account_existing = linphone_account_creator_test_existence(creator); - - g_object_set_data(G_OBJECT(w),"is_username_used",GINT_TO_POINTER(account_existing)); - gdk_threads_add_idle((GSourceFunc)update_interface_with_username_availability, (void*)w); - - return NULL; +static void linphone_gtk_test_account_existence_cb(LinphoneAccountCreator *creator, LinphoneAccountCreatorStatus status) { + GtkWidget *assistant = (GtkWidget *)linphone_account_creator_get_user_data(creator); + GtkWidget *page = g_object_get_data(G_OBJECT(assistant), "linphone_account_creation_configuration"); + int account_existing = (status != LinphoneAccountCreatorOk); + g_object_set_data(G_OBJECT(page), "is_username_used", GINT_TO_POINTER(account_existing)); + gdk_threads_add_idle((GSourceFunc)update_interface_with_username_availability, (void*)page); } -static void account_username_changed(GtkEntry *entry, GtkWidget *w) { - // Verifying if username choosed is available, and if form is correctly filled, let the user go next page - GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(w)); - GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"username")); - GtkImage* isUsernameOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w),"usernameOk")); - GtkLabel* usernameError = GTK_LABEL(g_object_get_data(G_OBJECT(w),"error")); +static gboolean check_username_availability(GtkWidget *assistant) { + LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); + GtkWidget *page = GUINT_TO_POINTER(g_object_get_data(G_OBJECT(assistant), "linphone_account_creation_configuration")); + g_object_set_data(G_OBJECT(page), "usernameAvailabilityTimerID", GUINT_TO_POINTER(0)); + linphone_account_creator_test_existence(creator); + return FALSE; +} - LinphoneAccountCreator *creator=linphone_gtk_assistant_get_creator(assistant); +static void linphone_account_creation_username_changed(GtkEntry *entry, GtkWidget *w) { + GtkWidget *assistant = gtk_widget_get_toplevel(GTK_WIDGET(w)); + GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "username")); + GtkImage* isUsernameOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w), "usernameOk")); + GtkLabel* usernameError = GTK_LABEL(g_object_get_data(G_OBJECT(w), "error")); + + LinphoneAccountCreator *creator = linphone_gtk_assistant_get_creator(assistant); linphone_account_creator_set_username(creator, gtk_entry_get_text(username)); + linphone_account_creator_set_domain(creator, "sip.linphone.org"); + linphone_account_creator_set_route(creator, "sip.linphone.org"); if (g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{3,}$", gtk_entry_get_text(username), 0, 0)) { -#if !GLIB_CHECK_VERSION(2, 31, 0) - g_thread_create(check_username_availability, (void*)w, FALSE, NULL); -#else - g_thread_new(NULL, check_username_availability, w); -#endif - } - else { + guint timerID = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(w), "usernameAvailabilityTimerID")); + if (timerID > 0) { + g_source_remove(timerID); + } + timerID = g_timeout_add(500, (GSourceFunc)check_username_availability, assistant); + g_object_set_data(G_OBJECT(w), "usernameAvailabilityTimerID", GUINT_TO_POINTER(timerID)); + } else { + GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf")); if (gtk_entry_get_text_length(username) < LOGIN_MIN_SIZE) { gtk_label_set_text(usernameError, "Username is too short"); - } - else if (!g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{3,}$", gtk_entry_get_text(username), 0, 0)) { + } else if (!g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{3,}$", gtk_entry_get_text(username), 0, 0)) { gtk_label_set_text(usernameError, "Unauthorized username"); } - g_object_set_data(G_OBJECT(w),"is_username_available",GINT_TO_POINTER(0)); - gtk_image_set_from_pixbuf(isUsernameOk, notok); - - gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - is_account_information_correct(w)>0); + g_object_set_data(G_OBJECT(w), "is_username_available", GINT_TO_POINTER(0)); + gtk_image_set_from_pixbuf(isUsernameOk, nok_pixbuf); + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), w, linphone_account_creation_configuration_correct(w) > 0); } } -static GtkWidget *create_account_information_page() { - GtkWidget *vbox=gtk_table_new(7, 3, FALSE); +static void linphone_account_creation_email_changed(GtkEntry *entry, GtkWidget *w) { + GtkEntry* email = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "email")); + GtkImage* isEmailOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w), "emailOk")); + GtkWidget *assistant = gtk_widget_get_toplevel(w); - GtkWidget *label=gtk_label_new(_("(*) Required fields")); - GtkWidget *labelUsername=gtk_label_new(_("Username: (*)")); - GtkWidget *isUsernameOk=gtk_image_new_from_pixbuf(notok); - GtkWidget *labelPassword=gtk_label_new(_("Password: (*)")); - GtkWidget *isPasswordOk=gtk_image_new_from_pixbuf(notok); - GtkWidget *labelEmail=gtk_label_new(_("Email: (*)")); - GtkWidget *isEmailOk=gtk_image_new_from_pixbuf(notok); - GtkWidget *labelPassword2=gtk_label_new(_("Confirm your password: (*)")); - GtkWidget *entryUsername=gtk_entry_new(); - GtkWidget *entryPassword=gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE); - GtkWidget *entryEmail=gtk_entry_new(); - GtkWidget *entryPassword2=gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(entryPassword2), FALSE); - GtkWidget *checkNewsletter=gtk_check_button_new_with_label("Keep me informed with linphone updates"); + if (g_regex_match_simple("^[a-z0-9]([a-z0-9_\\+\\.-]+)@[a-z0-9]([a-z0-9\\.-]+)\\.[a-z]{2,}$", gtk_entry_get_text(email), 0, 0)) { + GdkPixbuf *ok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "ok_pixbuf")); + g_object_set_data(G_OBJECT(w), "is_email_correct", GINT_TO_POINTER(1)); + gtk_image_set_from_pixbuf(isEmailOk, ok_pixbuf); + } else { + GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf")); + g_object_set_data(G_OBJECT(w), "is_email_correct", GINT_TO_POINTER(0)); + gtk_image_set_from_pixbuf(isEmailOk, nok_pixbuf); + } + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), w, linphone_account_creation_configuration_correct(w) > 0); +} +static void linphone_account_creation_password_changed(GtkEntry *entry, GtkWidget *w) { + GtkEntry* password = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "password")); + GtkImage* isPasswordOk = GTK_IMAGE(g_object_get_data(G_OBJECT(w), "passwordOk")); + GtkEntry* password_confirm = GTK_ENTRY(g_object_get_data(G_OBJECT(w), "password_confirm")); + GtkWidget *assistant = gtk_widget_get_toplevel(w); + GtkLabel* passwordError = GTK_LABEL(g_object_get_data(G_OBJECT(w), "error")); + + if ((gtk_entry_get_text_length(password) >= PASSWORD_MIN_SIZE) + && (g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) == 0)) { + GdkPixbuf *ok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "ok_pixbuf")); + g_object_set_data(G_OBJECT(w), "is_password_correct", GINT_TO_POINTER(1)); + gtk_image_set_from_pixbuf(isPasswordOk, ok_pixbuf); + gtk_label_set_text(passwordError, ""); + } else { + GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf")); + if (gtk_entry_get_text_length(password) < PASSWORD_MIN_SIZE) { + gtk_label_set_text(passwordError, "Password is too short !"); + } else if (!g_ascii_strcasecmp(gtk_entry_get_text(password), gtk_entry_get_text(password_confirm)) == 0) { + gtk_label_set_text(passwordError, "Passwords don't match !"); + } + g_object_set_data(G_OBJECT(w), "is_password_correct", GINT_TO_POINTER(0)); + gtk_image_set_from_pixbuf(isPasswordOk, nok_pixbuf); + } + gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant), w, linphone_account_creation_configuration_correct(w) > 0); +} + +static GtkWidget * create_linphone_account_creation_configuration_page(void) { + GtkWidget *vbox = gtk_table_new(7, 3, FALSE); + GdkPixbuf *nok_pixbuf = GDK_PIXBUF(g_object_get_data(G_OBJECT(the_assistant), "nok_pixbuf")); + GtkWidget *label = gtk_label_new(_("(*) Required fields")); + GtkWidget *labelUsername = gtk_label_new(_("Username: (*)")); + GtkWidget *isUsernameOk = gtk_image_new_from_pixbuf(nok_pixbuf); + GtkWidget *labelPassword = gtk_label_new(_("Password: (*)")); + GtkWidget *isPasswordOk = gtk_image_new_from_pixbuf(nok_pixbuf); + GtkWidget *labelEmail = gtk_label_new(_("Email: (*)")); + GtkWidget *isEmailOk = gtk_image_new_from_pixbuf(nok_pixbuf); + GtkWidget *labelPassword2 = gtk_label_new(_("Confirm your password: (*)")); + GtkWidget *entryUsername = gtk_entry_new(); + GtkWidget *entryPassword = gtk_entry_new(); + GtkWidget *entryEmail; + GtkWidget *entryPassword2; + GtkWidget *checkNewsletter; + GtkWidget *labelError; + GtkWidget *passwordVbox1; + GtkWidget *passwordVbox2; GdkColor color; - gdk_color_parse ("red", &color); - GtkWidget *labelError=gtk_label_new(NULL); + + gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE); + entryEmail = gtk_entry_new(); + entryPassword2 = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(entryPassword2), FALSE); + checkNewsletter = gtk_check_button_new_with_label(_("Keep me informed with linphone updates")); + + gdk_color_parse("red", &color); + labelError = gtk_label_new(NULL); gtk_widget_modify_fg(labelError, GTK_STATE_NORMAL, &color); - GtkWidget *passwordVbox1=gtk_vbox_new(FALSE,2); - GtkWidget *passwordVbox2=gtk_vbox_new(FALSE,2); - gtk_box_pack_start (GTK_BOX (passwordVbox1), labelPassword, TRUE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (passwordVbox1), labelPassword2, TRUE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (passwordVbox2), entryPassword, TRUE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (passwordVbox2), entryPassword2, TRUE, FALSE, 2); + passwordVbox1 = gtk_vbox_new(FALSE, 2); + passwordVbox2 = gtk_vbox_new(FALSE, 2); + gtk_box_pack_start(GTK_BOX (passwordVbox1), labelPassword, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX (passwordVbox1), labelPassword2, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX (passwordVbox2), entryPassword, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX (passwordVbox2), entryPassword2, TRUE, FALSE, 2); gtk_table_attach_defaults(GTK_TABLE(vbox), label, 0, 3, 0, 1); gtk_table_attach_defaults(GTK_TABLE(vbox), labelEmail, 0, 1, 1, 2); @@ -337,275 +465,182 @@ static GtkWidget *create_account_information_page() { gtk_table_attach_defaults(GTK_TABLE(vbox), checkNewsletter, 0, 3, 6, 7); gtk_widget_show_all(vbox); - g_object_set_data(G_OBJECT(vbox),"username",entryUsername); - g_object_set_data(G_OBJECT(vbox),"password",entryPassword); - g_object_set_data(G_OBJECT(vbox),"email",entryEmail); - g_object_set_data(G_OBJECT(vbox),"usernameOk",isUsernameOk); - g_object_set_data(G_OBJECT(vbox),"passwordOk",isPasswordOk); - g_object_set_data(G_OBJECT(vbox),"emailOk",isEmailOk); - g_object_set_data(G_OBJECT(vbox),"password_confirm",entryPassword2); - g_object_set_data(G_OBJECT(vbox),"newsletter",checkNewsletter); - g_object_set_data(G_OBJECT(vbox),"error",labelError); - g_signal_connect(G_OBJECT(entryUsername),"changed",(GCallback)account_username_changed,vbox); - g_signal_connect(G_OBJECT(entryPassword),"changed",(GCallback)account_password_changed,vbox); - g_signal_connect(G_OBJECT(entryEmail),"changed",(GCallback)account_email_changed,vbox); - g_signal_connect(G_OBJECT(entryPassword2),"changed",(GCallback)account_password_changed,vbox); + g_object_set_data(G_OBJECT(vbox), "username", entryUsername); + g_object_set_data(G_OBJECT(vbox), "password", entryPassword); + g_object_set_data(G_OBJECT(vbox), "email", entryEmail); + g_object_set_data(G_OBJECT(vbox), "usernameOk", isUsernameOk); + g_object_set_data(G_OBJECT(vbox), "passwordOk", isPasswordOk); + g_object_set_data(G_OBJECT(vbox), "emailOk", isEmailOk); + g_object_set_data(G_OBJECT(vbox), "password_confirm", entryPassword2); + g_object_set_data(G_OBJECT(vbox), "newsletter", checkNewsletter); + g_object_set_data(G_OBJECT(vbox), "error", labelError); + g_signal_connect(G_OBJECT(entryUsername), "changed", (GCallback)linphone_account_creation_username_changed, vbox); + g_signal_connect(G_OBJECT(entryPassword), "changed", (GCallback)linphone_account_creation_password_changed, vbox); + g_signal_connect(G_OBJECT(entryEmail), "changed", (GCallback)linphone_account_creation_email_changed, vbox); + g_signal_connect(G_OBJECT(entryPassword2), "changed", (GCallback)linphone_account_creation_password_changed, vbox); return vbox; } -/* -static GtkWidget *create_confirmation_page(){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *label=gtk_label_new(NULL); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); - g_object_set_data(G_OBJECT(vbox),"label",label); - gtk_widget_show_all(vbox); - return vbox; -} -*/ - -static GtkWidget *create_error_page(){ - GtkWidget *vbox=gtk_table_new(2, 1, FALSE); - GtkWidget *label=gtk_label_new(_("Error, account not validated, username already used or server unreachable.\nPlease go back and try again.")); - - gtk_table_attach(GTK_TABLE(vbox), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 100); - - g_object_set_data(G_OBJECT(vbox),"label",label); - gtk_widget_show_all(vbox); - return vbox; -} - -static GtkWidget *create_finish_page(){ - GtkWidget *vbox=gtk_vbox_new(FALSE,2); - GtkWidget *label=gtk_label_new(_("Thank you. Your account is now configured and ready for use.")); +static GtkWidget * create_linphone_account_creation_in_progress_page(void) { + GtkWidget *vbox = gtk_vbox_new(FALSE, 2); + GtkWidget *label = gtk_label_new(_("Your account is being created, please wait.")); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); gtk_widget_show_all(vbox); return vbox; } -static GtkWidget *wait_for_activation() { - GtkWidget *vbox=gtk_table_new(2, 1, FALSE); - GtkWidget *label=gtk_label_new(_("Please validate your account by clicking on the link we just sent you by email.\n" - "Then come back here and press Next button.")); - +static GtkWidget * create_linphone_account_validation_wait_page(void) { + GtkWidget *vbox = gtk_table_new(2, 1, FALSE); + GtkWidget *label = gtk_label_new(_("Please validate your account by clicking on the link we just sent you by email.\n" + "Then come back here and press Next button.")); gtk_table_attach(GTK_TABLE(vbox), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 100); - - g_object_set_data(G_OBJECT(vbox),"label",label); + g_object_set_data(G_OBJECT(vbox), "label", label); gtk_widget_show_all(vbox); return vbox; } -static int is_account_validated(GtkWidget *page) { - LinphoneAccountCreator *creator=linphone_gtk_assistant_get_creator(gtk_widget_get_toplevel(page)); - return linphone_account_creator_test_validation(creator); +static GtkWidget * create_linphone_account_validation_check_in_progress_page(void) { + GtkWidget *vbox = gtk_vbox_new(FALSE, 2); + GtkWidget *label = gtk_label_new(_("Checking if your account is been validated, please wait.")); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); + gtk_widget_show_all(vbox); + return vbox; } -static void linphone_gtk_assistant_closed(GtkWidget *w){ - linphone_gtk_close_assistant(); +static GtkWidget * create_error_page(void) { + GtkWidget *vbox = gtk_table_new(2, 1, FALSE); + GtkWidget *label = gtk_label_new(_("Error, account not validated, username already used or server unreachable.\nPlease go back and try again.")); + gtk_table_attach(GTK_TABLE(vbox), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 100); + g_object_set_data(G_OBJECT(vbox), "label", label); + gtk_widget_show_all(vbox); + return vbox; } -static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page){ - int pagenum=gtk_assistant_get_current_page(GTK_ASSISTANT(assistant)); - - if (pagenum == 5) { - gtk_assistant_commit(GTK_ASSISTANT(assistant)); - } else if (pagenum == gtk_assistant_get_n_pages(GTK_ASSISTANT(assistant)) - 1) { - // Saving the account and making it default - LinphoneAccountCreator *creator=linphone_gtk_assistant_get_creator(assistant); - LinphoneProxyConfig *cfg=linphone_proxy_config_new(); - 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_enable_publish(cfg, FALSE); - linphone_proxy_config_enable_register(cfg, TRUE); - - gchar *username = creator->username + 4; - const gchar *needle = "@"; - username = g_strndup(username, (g_strrstr(username, needle) - username)); - gchar domain[128]; - g_snprintf(domain, sizeof(domain), "\"%s\"", creator->domain + 4); - LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, domain); - linphone_core_add_auth_info(linphone_gtk_get_core(),info); - - if (linphone_core_add_proxy_config(linphone_gtk_get_core(),cfg)==-1) - return; - - linphone_core_set_default_proxy(linphone_gtk_get_core(),cfg); - linphone_gtk_load_identities(); - - // If account created on sip.linphone.org, we configure linphone to use TLS by default - g_warning("Domain : %s", creator->domain); - if (strcmp(creator->domain, "sip:sip.linphone.org") == 0) { - LCSipTransports tr; - LinphoneCore* lc = linphone_gtk_get_core(); - linphone_core_get_sip_transports(lc,&tr); - tr.tls_port = tr.udp_port + tr.tcp_port + tr.tls_port; - tr.udp_port = 0; - tr.tcp_port = 0; - linphone_core_set_sip_transports(lc,&tr); - } - } +static GtkWidget * create_finish_page(void) { + GtkWidget *vbox = gtk_vbox_new(FALSE, 2); + GtkWidget *label = gtk_label_new(_("Thank you. Your account is now configured and ready for use.")); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2); + gtk_widget_show_all(vbox); + return vbox; } -static int linphone_gtk_assistant_forward(int curpage, gpointer data){ - GtkWidget *w=(GtkWidget*)data; - GtkWidget *box=gtk_assistant_get_nth_page(GTK_ASSISTANT(w),curpage); - if (curpage==1){ - GtkWidget *create_button=(GtkWidget*)g_object_get_data(G_OBJECT(box),"create_account"); - GtkWidget *setup_linphone_account=(GtkWidget*)g_object_get_data(G_OBJECT(box),"setup_linphone_account"); - GtkWidget *setup_account=(GtkWidget*)g_object_get_data(G_OBJECT(box),"setup_account"); - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(create_button))) { - curpage += 3; // Going to P33 - } - else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_linphone_account))) { - curpage += 2; // Going to P32 - } - else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_account))) { - curpage += 1; // Going to P31 - } - } - else if (curpage == 2) { // Account's informations entered - LinphoneAccountCreator *c=linphone_gtk_assistant_get_creator(w); - gchar identity[128]; - g_snprintf(identity, sizeof(identity), "sip:%s@%s", gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"username"))), gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"domain")))); - - gchar proxy[128]; - g_snprintf(proxy, sizeof(proxy), "sip:%s", gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"domain")))); - - linphone_account_creator_set_username(c, identity); - linphone_account_creator_set_domain(c, proxy); - linphone_account_creator_set_route(c, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"proxy")))); - linphone_account_creator_set_password(c,gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"password")))); - curpage = gtk_assistant_get_n_pages(GTK_ASSISTANT(w)) - 1; // Going to the last page - } - else if (curpage == 3) { // Linphone Account's informations entered - LinphoneAccountCreator *c=linphone_gtk_assistant_get_creator(w); - gchar identity[128]; - g_snprintf(identity, sizeof(identity), "sip:%s@sip.linphone.org", gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"username")))); - linphone_account_creator_set_username(c, identity); - linphone_account_creator_set_domain(c, "sip:sip.linphone.org"); - linphone_account_creator_set_password(c,gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"password")))); - curpage = gtk_assistant_get_n_pages(GTK_ASSISTANT(w)) - 1; // Going to the last page - } - else if (curpage == 4) { // Password & Email entered - LinphoneAccountCreator *c=linphone_gtk_assistant_get_creator(w); - linphone_account_creator_set_username(c, gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"username")))); - linphone_account_creator_set_password(c,gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"password")))); - linphone_account_creator_set_email(c,gtk_entry_get_text(GTK_ENTRY(g_object_get_data(G_OBJECT(box),"email")))); - linphone_account_creator_set_suscribe(c,gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(box),"newsletter")))); - if (create_account(w) == 1) { - curpage += 1; - } else { // Error when attempting to create the account - curpage += 2; - } - } - else if (curpage == 5) { // Waiting for account validation - if (is_account_validated(w) == 1) { - curpage += 2; // Going to the last page - } else { - curpage += 1; - } - } - else { - curpage += 1; - } - return curpage; +static LinphoneAccountCreator * linphone_gtk_assistant_init(GtkWidget *w) { + LinphoneAccountCreator *creator = linphone_account_creator_new(linphone_gtk_get_core(), "https://www.linphone.org/wizard.php"); + LinphoneAccountCreatorCbs *cbs = linphone_account_creator_get_callbacks(creator); + linphone_account_creator_set_user_data(creator, w); + linphone_account_creator_cbs_set_existence_tested(cbs, linphone_gtk_test_account_existence_cb); + linphone_account_creator_cbs_set_validation_tested(cbs, linphone_gtk_test_account_validation_cb); + linphone_account_creator_cbs_set_validated(cbs, linphone_gtk_account_validate_cb); + g_object_set_data(G_OBJECT(w), "creator", creator); + return creator; } -static LinphoneAccountCreator * linphone_gtk_assistant_init(GtkWidget *w){ - const MSList *elem; - LinphoneCore *lc=linphone_gtk_get_core(); - for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){ - SipSetup *ss=(SipSetup*)elem->data; - if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){ - LinphoneAccountCreator *creator=linphone_account_creator_new(lc,ss->name); - g_object_set_data(G_OBJECT(w),"creator",creator); - return creator; - } - } - return NULL; -} +void linphone_gtk_show_assistant(GtkWidget *parent) { + GtkWidget *w; + GtkWidget *page_0_intro; + GtkWidget *page_1_choice; + GtkWidget *page_2_external_account_configuration; + GtkWidget *page_3_linphone_account_configuration; + GtkWidget *page_4_linphone_account_creation_configuration; + GtkWidget *page_5_linphone_account_creation_in_progress; + GtkWidget *page_6_linphone_account_validation_wait; + GtkWidget *page_7_linphone_account_validation_check_in_progress; + GtkWidget *page_8_error; + GtkWidget *page_9_finish; + GdkPixbuf *ok_pixbuf; + GdkPixbuf *nok_pixbuf; -static LinphoneAccountCreator *linphone_gtk_assistant_get_creator(GtkWidget*w){ - return (LinphoneAccountCreator*)g_object_get_data(G_OBJECT(w),"creator"); -} + if (the_assistant != NULL) return; -void linphone_gtk_close_assistant(void){ - if(the_assistant==NULL) - return; - gtk_widget_destroy(the_assistant); - the_assistant = NULL; -} - -void linphone_gtk_show_assistant(void){ - if(the_assistant!=NULL) - return; - GtkWidget *w=the_assistant=gtk_assistant_new(); + w = the_assistant = gtk_assistant_new(); gtk_window_set_resizable (GTK_WINDOW(w), FALSE); + gtk_window_set_title(GTK_WINDOW(w), _("SIP account configuration assistant")); - ok = create_pixbuf(linphone_gtk_get_ui_config("ok","ok.png")); - notok = create_pixbuf(linphone_gtk_get_ui_config("notok","notok.png")); + ok_pixbuf = create_pixbuf(linphone_gtk_get_ui_config("ok", "ok.png")); + g_object_set_data_full(G_OBJECT(the_assistant), "ok_pixbuf", ok_pixbuf, g_object_unref); + nok_pixbuf = create_pixbuf(linphone_gtk_get_ui_config("notok", "notok.png")); + g_object_set_data_full(G_OBJECT(the_assistant), "nok_pixbuf", nok_pixbuf, g_object_unref); + + page_0_intro = create_intro_page(); + page_1_choice = create_choice_page(); + page_2_external_account_configuration = create_external_account_configuration_page(); + page_3_linphone_account_configuration = create_linphone_account_configuration_page(); + page_4_linphone_account_creation_configuration = create_linphone_account_creation_configuration_page(); + page_5_linphone_account_creation_in_progress = create_linphone_account_creation_in_progress_page(); + page_6_linphone_account_validation_wait = create_linphone_account_validation_wait_page(); + page_7_linphone_account_validation_check_in_progress = create_linphone_account_validation_check_in_progress_page(); + page_8_error = create_error_page(); + page_9_finish = create_finish_page(); - GtkWidget *p1=create_intro(); - GtkWidget *p2=create_setup_signin_choice(); - GtkWidget *p31=create_account_informations_page(); - GtkWidget *p32=create_linphone_account_informations_page(); - GtkWidget *p33=create_account_information_page(); - //GtkWidget *confirm=create_confirmation_page(); - GtkWidget *validate=wait_for_activation(); - GtkWidget *error=create_error_page(); - GtkWidget *end=create_finish_page(); - linphone_gtk_assistant_init(w); - gtk_assistant_append_page(GTK_ASSISTANT(w),p1); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),p1,GTK_ASSISTANT_PAGE_INTRO); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),p1,_("Welcome to the account setup assistant")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),p1,TRUE); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_0_intro); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_0_intro, GTK_ASSISTANT_PAGE_INTRO); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_0_intro, _("Welcome to the account setup assistant")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w), page_0_intro, TRUE); - gtk_assistant_append_page(GTK_ASSISTANT(w),p2); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),p2,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),p2,_("Account setup assistant")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),p2,TRUE); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_1_choice); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_1_choice, GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_1_choice, _("Account setup assistant")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w), page_1_choice, TRUE); - gtk_assistant_append_page(GTK_ASSISTANT(w),p31); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),p31,GTK_ASSISTANT_PAGE_CONFIRM); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),p31,FALSE); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),p31,_("Configure your account (step 1/1)")); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_2_external_account_configuration); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_2_external_account_configuration, GTK_ASSISTANT_PAGE_CONFIRM); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_2_external_account_configuration, _("Configure your account (step 1/1)")); - gtk_assistant_append_page(GTK_ASSISTANT(w),p32); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),p32,GTK_ASSISTANT_PAGE_CONFIRM); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),p32,FALSE); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),p32,_("Enter your sip username (step 1/1)")); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_3_linphone_account_configuration); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_3_linphone_account_configuration, GTK_ASSISTANT_PAGE_CONFIRM); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_3_linphone_account_configuration, _("Enter your sip username (step 1/1)")); - gtk_assistant_append_page(GTK_ASSISTANT(w),p33); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),p33,GTK_ASSISTANT_PAGE_CONFIRM); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),p33,_("Enter account information (step 1/2)")); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_4_linphone_account_creation_configuration); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_4_linphone_account_creation_configuration, GTK_ASSISTANT_PAGE_CONFIRM); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_4_linphone_account_creation_configuration, _("Enter account information (step 1/2)")); + g_object_set_data(G_OBJECT(w), "linphone_account_creation_configuration", page_4_linphone_account_creation_configuration); - /*gtk_assistant_append_page(GTK_ASSISTANT(w),confirm); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),confirm,GTK_ASSISTANT_PAGE_CONFIRM); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),confirm,_("Confirmation (step 2/2)")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),confirm,TRUE);*/ + gtk_assistant_append_page(GTK_ASSISTANT(w), page_5_linphone_account_creation_in_progress); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_5_linphone_account_creation_in_progress, GTK_ASSISTANT_PAGE_PROGRESS); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_5_linphone_account_creation_in_progress, _("Account creation in progress")); - gtk_assistant_append_page(GTK_ASSISTANT(w),validate); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),validate,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),validate,_("Validation (step 2/2)")); - gtk_assistant_set_page_complete(GTK_ASSISTANT(w),validate,TRUE); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_6_linphone_account_validation_wait); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_6_linphone_account_validation_wait, GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_6_linphone_account_validation_wait, _("Validation (step 2/2)")); + gtk_assistant_set_page_complete(GTK_ASSISTANT(w), page_6_linphone_account_validation_wait, TRUE); - gtk_assistant_append_page(GTK_ASSISTANT(w),error); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),error,GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),error,_("Error")); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_7_linphone_account_validation_check_in_progress); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_7_linphone_account_validation_check_in_progress, GTK_ASSISTANT_PAGE_PROGRESS); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_7_linphone_account_validation_check_in_progress, _("Account validation check in progress")); - gtk_assistant_append_page(GTK_ASSISTANT(w),end); - gtk_assistant_set_page_type(GTK_ASSISTANT(w),end,GTK_ASSISTANT_PAGE_SUMMARY); - gtk_assistant_set_page_title(GTK_ASSISTANT(w),end,_("Terminating")); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_8_error); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_8_error, GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_8_error, _("Error")); - gtk_assistant_set_forward_page_func(GTK_ASSISTANT(w),linphone_gtk_assistant_forward,w,NULL); - g_signal_connect(G_OBJECT(w),"close",(GCallback)linphone_gtk_assistant_closed,NULL); - g_signal_connect(G_OBJECT(w),"cancel",(GCallback)linphone_gtk_assistant_closed,NULL); - g_signal_connect(G_OBJECT(w),"prepare",(GCallback)linphone_gtk_assistant_prepare,NULL); + gtk_assistant_append_page(GTK_ASSISTANT(w), page_9_finish); + gtk_assistant_set_page_type(GTK_ASSISTANT(w), page_9_finish, GTK_ASSISTANT_PAGE_SUMMARY); + gtk_assistant_set_page_title(GTK_ASSISTANT(w), page_9_finish, _("Terminating")); + + gtk_assistant_set_forward_page_func(GTK_ASSISTANT(w), linphone_gtk_assistant_forward, w, NULL); + g_signal_connect(G_OBJECT(w), "close", (GCallback)linphone_gtk_assistant_closed, NULL); + g_signal_connect(G_OBJECT(w), "cancel", (GCallback)linphone_gtk_assistant_closed, NULL); + g_signal_connect(G_OBJECT(w), "prepare", (GCallback)linphone_gtk_assistant_prepare, NULL); + + gtk_window_set_transient_for(GTK_WINDOW(the_assistant), GTK_WINDOW(linphone_gtk_get_main_window())); gtk_widget_show(w); } +void linphone_gtk_close_assistant(void) { + GtkWidget *mw; + if (the_assistant == NULL) { + return; + } + gtk_widget_destroy(the_assistant); + the_assistant = NULL; + + //reload list of proxy configs because a new one was probably created... + mw=linphone_gtk_get_main_window(); + if (mw) { + GtkWidget* pb = (GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); + if (pb) { + linphone_gtk_show_sip_accounts(pb); + } + } +} diff --git a/gtk/singleinstance.c b/gtk/singleinstance.c index c9550a09f..591d5d7cd 100644 --- a/gtk/singleinstance.c +++ b/gtk/singleinstance.c @@ -33,17 +33,32 @@ gchar *make_name(const char *appname){ return g_strdup(appname); } -static gboolean execute_wakeup(char *uri){ - linphone_gtk_show_main_window(); - if (strlen(uri)>0) - linphone_gtk_refer_received(linphone_gtk_get_core(),uri); - g_free(uri); +static gboolean execute_wakeup(char *buf){ + char uri[255]={0}; + int option; + + if (strlen(buf)>1) sscanf(buf,"%i%s",&option,uri); + else sscanf(buf,"%i",&option); + + switch(option){ + case START_LINPHONE: + linphone_gtk_show_main_window(); + break; + case START_AUDIO_ASSISTANT: + linphone_gtk_show_audio_assistant(); + break; + case START_LINPHONE_WITH_CALL: + linphone_gtk_refer_received(linphone_gtk_get_core(),uri); + break; + }; + + g_free(buf); return FALSE; } static void * server_pipe_thread(void *pointer){ ortp_pipe_t child; - + do{ child=ortp_server_pipe_accept_client(server_pipe); if (server_pipe_running && child!=(ortp_pipe_t)-1){ @@ -65,18 +80,23 @@ static void linphone_gtk_init_pipe(const char *name){ server_pipe=ortp_server_pipe_create(name); if (server_pipe==(ortp_pipe_t)-1){ g_warning("Fail to create server pipe for name %s: %s",name,strerror(errno)); + return; } + server_pipe_running=TRUE; ms_thread_create(&pipe_thread,NULL,server_pipe_thread,NULL); } -bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call){ +bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call){ + ortp_pipe_t p; pipe_name=make_name(app_name); - ortp_pipe_t p=ortp_client_pipe_connect(pipe_name); + p=ortp_client_pipe_connect(pipe_name); if (p!=(ortp_pipe_t)-1){ uint8_t buf[256]={0}; g_message("There is already a running instance."); if (addr_to_call!=NULL){ - strncpy((char*)buf,addr_to_call,sizeof(buf)-1); + sprintf((char *)buf,"%i%s",option,addr_to_call); + } else { + sprintf((char *)buf,"%i",option); } if (ortp_pipe_write(p,buf,sizeof(buf))==-1){ g_error("Fail to send wakeup command to running instance: %s",strerror(errno)); diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui index 60b751cfa..6d03932d1 100644 --- a/gtk/sip_account.ui +++ b/gtk/sip_account.ui @@ -1,12 +1,20 @@ + 100000 3600 1 10 + + 5 + 1 + 5 + 1 + 1 + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -15,13 +23,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 +99,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 +120,8 @@ sip: False False + True + True 1 @@ -140,6 +150,9 @@ sip: False False + True + True + 1 @@ -148,19 +161,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 +168,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 +187,8 @@ right - 3 - 4 + 2 + 3 @@ -196,8 +198,111 @@ 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 + AVPF regular RTCP interval (sec): + right + + + 6 + 7 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + False + True + True + adjustment2 + + + 1 + 2 + 6 + 7 + + + + + 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 @@ -244,6 +349,22 @@ 2 + + + Enable AVPF + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + False + True + 3 + + diff --git a/gtk/status_icon.c b/gtk/status_icon.c new file mode 100644 index 000000000..cbee89f54 --- /dev/null +++ b/gtk/status_icon.c @@ -0,0 +1,548 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2015 Belledonne Communications + +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 "status_icon.h" +#include "linphone.h" + +#ifdef HAVE_GTK_OSX +#include +#endif + +#if !defined(WIN32) && !defined(__APPLE__) && GLIB_CHECK_VERSION(2, 26, 0) +#define STATUS_NOTIFIER_IS_USABLE 1 +#endif + +#include "status_notifier.h" +#include + +typedef struct __LinphoneStatusIconDesc _LinphoneStatusIconDesc; + +static LinphoneStatusIcon *_linphone_status_icon_instance = NULL; +static const _LinphoneStatusIconDesc *_linphone_status_icon_selected_desc = NULL; +static GSList *_linphone_status_icon_impls = NULL; + + +struct _LinphoneStatusIconParams { + char *title; + char *desc; + GtkWidget *menu; + LinphoneStatusIconOnClickCallback on_click_cb; + void *user_data; + int ref; +}; + +LinphoneStatusIconParams *linphone_status_icon_params_new(void) { + return g_new0(LinphoneStatusIconParams, 1); +} + +LinphoneStatusIconParams *linphone_status_icon_params_ref(LinphoneStatusIconParams *obj) { + obj->ref++; + return obj; +} + +void linphone_status_icon_params_unref(LinphoneStatusIconParams *obj) { + obj->ref--; + if(obj->ref < 0) { + if(obj->title) g_free(obj->title); + if(obj->menu) g_object_unref(obj->menu); + if(obj->desc) g_free(obj->desc); + g_free(obj); + } +} + +void linphone_status_icon_params_set_title(LinphoneStatusIconParams *obj, const char *title) { + if(obj->title) g_free(obj->title); + if(title) obj->title = g_strdup(title); + else obj->title = NULL; +} + +void linphone_status_icon_params_set_description(LinphoneStatusIconParams *obj, const char *desc) { + if(obj->desc) g_free(obj->desc); + if(desc) obj->desc = g_strdup(desc); + else obj->desc = NULL; +} + +void linphone_status_icon_params_set_menu(LinphoneStatusIconParams *obj, GtkWidget *menu) { + if(obj->menu) g_object_unref(obj->menu); + if(menu) obj->menu = g_object_ref_sink(menu); + else obj->menu = NULL; +} + +void linphone_status_icon_params_set_on_click_cb(LinphoneStatusIconParams *obj, LinphoneStatusIconOnClickCallback cb, void *user_data) { + obj->on_click_cb = cb; + obj->user_data = user_data; +} + + +typedef void (*LinphoneStatusIconDescInitFunc)(LinphoneStatusIcon *obj); +typedef void (*LinphoneStatusIconDescUninitFunc)(LinphoneStatusIcon *obj); +typedef void (*LinphoneStatusIconDescStartFunc)(LinphoneStatusIcon *obj); +typedef void (*LinphoneStatusIconDescEnableBlinkingFunc)(LinphoneStatusIcon *obj, gboolean enable); +typedef void (*LinphoneStatusIconDescIsSupportedResultCb)(const _LinphoneStatusIconDesc *obj, gboolean result, void *user_data); +typedef gboolean (*LinphoneStatusIconDescIsSupportedFunc)( + const _LinphoneStatusIconDesc *desc, + gboolean *result, + LinphoneStatusIconDescIsSupportedResultCb cb, + void *user_data +); +typedef void (*LinphoneStatusIconDescFindResultCb)(const _LinphoneStatusIconDesc *desc, void *user_data); + +struct __LinphoneStatusIconDesc { + const char *impl_name; + LinphoneStatusIconDescInitFunc init; + LinphoneStatusIconDescUninitFunc uninit; + LinphoneStatusIconDescStartFunc start; + LinphoneStatusIconDescEnableBlinkingFunc enable_blinking; + LinphoneStatusIconDescIsSupportedFunc is_supported; +}; + +static gboolean _linphone_status_icon_desc_is_supported( + const _LinphoneStatusIconDesc *desc, + gboolean *result, + LinphoneStatusIconDescIsSupportedResultCb cb, + void *user_data) { + + return desc->is_supported(desc, result, cb, user_data); +} + +typedef struct { + GSList *i; + LinphoneStatusIconDescFindResultCb cb; + void *user_data; +} _LinphoneStatusIconDescSearchCtx; + +static void _linphone_status_icon_desc_is_supported_result_cb( + const _LinphoneStatusIconDesc *desc, + gboolean result, + _LinphoneStatusIconDescSearchCtx *ctx) { + + if(!result) { + ctx->i = g_slist_next(ctx->i); + for(; ctx->i; ctx->i = g_slist_next(ctx->i)) { + if(_linphone_status_icon_desc_is_supported( + (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0), + &result, + (LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb, + ctx)) { + + if(result) break; + } else return; + } + } + + if(ctx->i) { + const _LinphoneStatusIconDesc *desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0); + ms_message("StatusIcon: found implementation: %s", desc->impl_name); + if(ctx->cb) ctx->cb(desc, ctx->user_data); + } else { + g_warning("StatusIcon: no implementation found"); + } + + g_free(ctx); +} + +static gboolean _linphone_status_icon_find_first_available_impl( + const _LinphoneStatusIconDesc **desc, + LinphoneStatusIconDescFindResultCb cb, + void *user_data) { + + gboolean result; + _LinphoneStatusIconDescSearchCtx *ctx = g_new0(_LinphoneStatusIconDescSearchCtx, 1); + ctx->cb = cb; + ctx->user_data = user_data; + + ms_message("StatusIcon: looking for implementation..."); + + for(ctx->i=_linphone_status_icon_impls; ctx->i; ctx->i = g_slist_next(ctx->i)) { + if(_linphone_status_icon_desc_is_supported( + (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0), + &result, + (LinphoneStatusIconDescIsSupportedResultCb)_linphone_status_icon_desc_is_supported_result_cb, + ctx)) { + + if(result) { + *desc = (const _LinphoneStatusIconDesc *)g_slist_nth_data(ctx->i, 0); + ms_message("StatusIcon: found implementation: %s", (*desc)->impl_name); + goto sync_return; + } + } else { + return 0; + } + } + g_warning("StatusIcon: no implementation found"); + *desc = NULL; + +sync_return: + g_free(ctx); + return 1; +} + + +struct _LinphoneStatusIcon { + const _LinphoneStatusIconDesc *desc; + LinphoneStatusIconParams *params; + void *data; +}; + +static LinphoneStatusIcon *_linphone_status_icon_new(const _LinphoneStatusIconDesc *desc) { + LinphoneStatusIcon *si = (LinphoneStatusIcon *)g_new0(LinphoneStatusIcon, 1); + si->desc = desc; + if(desc->init) desc->init(si); + return si; +} + +static void _linphone_status_icon_free(LinphoneStatusIcon *obj) { + if(obj->desc->uninit) obj->desc->uninit(obj->data); + if(obj->params) linphone_status_icon_params_unref(obj->params); + g_free(obj); +} + +const char *linphone_status_icon_get_implementation_name(const LinphoneStatusIcon *obj) { + return obj->desc->impl_name; +} + +void linphone_status_icon_start(LinphoneStatusIcon *obj, LinphoneStatusIconParams *params) { + ms_message("StatusIcon: starting status icon"); + obj->params = linphone_status_icon_params_ref(params); + if(obj->desc->start) obj->desc->start(obj); +} + +void linphone_status_icon_enable_blinking(LinphoneStatusIcon *obj, gboolean enable) { + ms_message("StatusIcon: blinking set to %s", enable ? "TRUE" : "FALSE"); + if(obj->desc->enable_blinking) obj->desc->enable_blinking(obj, enable); +} + +static void _linphone_status_icon_notify_click(LinphoneStatusIcon *obj) { + if(obj->params->on_click_cb) { + obj->params->on_click_cb(obj, obj->params->user_data); + } +} + + +void _linphone_status_icon_init_cb(const _LinphoneStatusIconDesc *desc, void *user_data) { + void **ctx = (void **)user_data; + LinphoneStatusIconReadyCb cb = (LinphoneStatusIconReadyCb)ctx[0]; + _linphone_status_icon_selected_desc = desc; + if(cb) cb(ctx[1]); + g_free(ctx); +} + +#ifdef STATUS_NOTIFIER_IS_USABLE +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_status_notifier; +#endif +#ifdef HAVE_GTK_OSX +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtkosx_app_desc; +#else +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtk_desc; +#endif + +void _linphone_status_icon_create_implementations_list(void) { +#ifdef STATUS_NOTIFIER_IS_USABLE + _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_status_notifier); +#endif +#if HAVE_GTK_OSX + _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_gtkosx_app_desc); +#else + _linphone_status_icon_impls = g_slist_append(_linphone_status_icon_impls, (void *)&_linphone_status_icon_impl_gtk_desc); +#endif +} + +gboolean linphone_status_icon_init(LinphoneStatusIconReadyCb ready_cb, void *user_data) { + const _LinphoneStatusIconDesc *desc; + void **ctx; + + ms_message("StatusIcon: Initialising"); + + _linphone_status_icon_create_implementations_list(); + + ctx = g_new(void *, 2); + ctx[0] = ready_cb; + ctx[1] = user_data; + + if(_linphone_status_icon_find_first_available_impl(&desc, _linphone_status_icon_init_cb, ctx)) { + _linphone_status_icon_selected_desc = desc; + g_free(ctx); + return 1; + } else return 0; +} + +void linphone_status_icon_uninit(void) { + if(_linphone_status_icon_instance) { + _linphone_status_icon_free(_linphone_status_icon_instance); + _linphone_status_icon_instance = NULL; + } + if(_linphone_status_icon_impls) { + g_slist_free(_linphone_status_icon_impls); + _linphone_status_icon_impls = NULL; + } + _linphone_status_icon_selected_desc = NULL; +} + +LinphoneStatusIcon *linphone_status_icon_get(void) { + if(_linphone_status_icon_instance == NULL) { + if(_linphone_status_icon_selected_desc) + ms_message("StatusIcon: instanciating singleton"); + _linphone_status_icon_instance = _linphone_status_icon_new(_linphone_status_icon_selected_desc); + } + return _linphone_status_icon_instance; +} + + +/* GtkStatusIcon implementation */ +#ifndef HAVE_GTK_OSX +static void _linphone_status_icon_impl_gtk_on_click_cb(LinphoneStatusIcon *si) { + _linphone_status_icon_notify_click(si); +} + +static void _linphone_status_icon_impl_gtk_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, LinphoneStatusIcon *si){ + GtkWidget *menu = si->params->menu; + gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time); +} + +static void _linphone_status_icon_impl_gtk_init(LinphoneStatusIcon *si) { + const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); + const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","call_start.png"); + GdkPixbuf *pbuf=create_pixbuf(icon_path); + GtkStatusIcon *icon=gtk_status_icon_new_from_pixbuf(pbuf); + g_signal_connect_swapped(G_OBJECT(icon),"activate", G_CALLBACK(_linphone_status_icon_impl_gtk_on_click_cb), si); + g_signal_connect(G_OBJECT(icon), "popup-menu", G_CALLBACK(_linphone_status_icon_impl_gtk_popup_menu), si); + g_object_set_data_full(G_OBJECT(icon),"icon",pbuf, g_object_unref); + pbuf=create_pixbuf(call_icon_path); + g_object_set_data_full(G_OBJECT(icon),"call_icon",pbuf, g_object_unref); + si->data = icon; +} + +// static void _linphone_status_icon_impl_gtk_uninit(LinphoneStatusIcon *si) { +// GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); +// gtk_status_icon_set_visible(icon, FALSE); +// } + +static void _linphone_status_icon_impl_gtk_start(LinphoneStatusIcon *si) { + GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); +#if GTK_CHECK_VERSION(2,20,2) + char *name = g_strdup_printf("%s - %s", si->params->title, si->params->desc); + gtk_status_icon_set_name(icon, name); + g_free(name); +#endif + gtk_status_icon_set_visible(icon,TRUE); +} + +static gboolean _linphone_status_icon_impl_gtk_do_icon_blink_cb(GtkStatusIcon *gi){ + GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon"); + GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon"); + GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi); + if (cur_icon==call_icon){ + gtk_status_icon_set_from_pixbuf(gi,normal_icon); + }else{ + gtk_status_icon_set_from_pixbuf(gi,call_icon); + } + return TRUE; +} + +static void _linphone_status_icon_impl_enable_blinking(LinphoneStatusIcon *si, gboolean val) { + GtkStatusIcon *icon = GTK_STATUS_ICON(si->data); + guint tout; + tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout")); + if (val && tout==0){ + tout=g_timeout_add(500,(GSourceFunc)_linphone_status_icon_impl_gtk_do_icon_blink_cb,icon); + g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout)); + }else if (!val && tout!=0){ + GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon"); + g_source_remove(tout); + g_object_set_data(G_OBJECT(icon),"timeout",NULL); + gtk_status_icon_set_from_pixbuf(icon,normal_icon); + } +} + +static gboolean _linphone_status_icon_impl_is_supported( + const _LinphoneStatusIconDesc *desc, + gboolean *result, + LinphoneStatusIconDescIsSupportedResultCb cb, + void *user_data) { + + *result = 1; + return 1; +} + +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtk_desc = { + "gtk_status_icon", + _linphone_status_icon_impl_gtk_init, + NULL, + _linphone_status_icon_impl_gtk_start, + _linphone_status_icon_impl_enable_blinking, + _linphone_status_icon_impl_is_supported +}; +#endif + + +/* GtkosxApplication implementation */ +#ifdef HAVE_GTK_OSX +static void _linphone_status_icon_impl_gtkosx_app_enable_blinking(LinphoneStatusIcon *si, gboolean val) { + GtkosxApplication *theMacApp=gtkosx_application_get(); + gint *attention_id = (gint *)&si->data; + if (val) { + *attention_id=gtkosx_application_attention_request(theMacApp, CRITICAL_REQUEST); + } else if (*attention_id != 0) { + gtkosx_application_cancel_attention_request(theMacApp, *attention_id); + *attention_id = 0; + } +} + +static gboolean _linphone_status_icon_impl_gtkosx_app_is_supported( + const _LinphoneStatusIconDesc *desc, + gboolean *result, + LinphoneStatusIconDescIsSupportedResultCb cb, + void *user_data) { + + *result = 1; + return 1; +} + +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_gtkosx_app_desc = { + .impl_name = "gtkosx_application", + .init = NULL, + .uninit = NULL, + .start = NULL, + .enable_blinking = _linphone_status_icon_impl_gtkosx_app_enable_blinking, + .is_supported = _linphone_status_icon_impl_gtkosx_app_is_supported +}; +#endif + + +/* Implementation based on the StatusNotifier Freedesktop standard */ +#ifdef STATUS_NOTIFIER_IS_USABLE +typedef struct { + int x; + int y; +} _LinphoneStatusIconPosition; + +static void _linphone_status_icon_impl_sn_init(LinphoneStatusIcon *si) { + si->data = bc_status_notifier_new(); +} + +// static void _linphone_status_icon_impl_sn_uninit(LinphoneStatusIcon *si) { +// bc_status_notifier_unref((BcStatusNotifier *)si->data); +// } + +static void _linphone_status_icon_impl_sn_activated_cb(BcStatusNotifier *sn, int x, int y, void *user_data) { + LinphoneStatusIcon *si = (LinphoneStatusIcon *)user_data; + _linphone_status_icon_notify_click(si); +} + +static void _linphone_status_icon_impr_sn_get_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer data) { + _LinphoneStatusIconPosition *pos = (_LinphoneStatusIconPosition *)data; + *x = pos->x; + *y = pos->y; + *push_in = TRUE; +} + +static void _linphone_status_icon_impl_sn_menu_called_cb(BcStatusNotifier *sn, int x, int y, void *user_data) { + LinphoneStatusIcon *si = (LinphoneStatusIcon *)user_data; + GtkWidget *menu = si->params->menu; + _LinphoneStatusIconPosition pos = {x, y}; + gtk_menu_popup( + GTK_MENU(menu), + NULL, + NULL, + _linphone_status_icon_impr_sn_get_position, + &pos, + 0, + gtk_get_current_event_time() + ); +} + +static void _linphone_status_icon_impl_sn_start(LinphoneStatusIcon *si) { + BcStatusNotifier *sn = (BcStatusNotifier *)si->data; + BcStatusNotifierParams *params; + BcStatusNotifierToolTip *tooltip = bc_status_notifier_tool_tip_new("linphone", si->params->title, si->params->desc); + BcStatusNotifierSignalsVTable vtable = {NULL}; + + vtable.activate_called_cb = _linphone_status_icon_impl_sn_activated_cb; + vtable.context_menu_called_cb = _linphone_status_icon_impl_sn_menu_called_cb; + + params = bc_status_notifier_params_new(); + bc_status_notifier_params_set_dbus_prefix(params, "org.kde"); + bc_status_notifier_params_set_category(params, BcStatusNotifierCategoryCommunications); + bc_status_notifier_params_set_id(params, "linphone"); + bc_status_notifier_params_set_title(params, si->params->title); + bc_status_notifier_params_set_icon_name(params, "linphone"); + bc_status_notifier_params_set_tool_tip(params, tooltip); + bc_status_notifier_params_set_vtable(params, &vtable, si); + + bc_status_notifier_start(sn, params, NULL, NULL); + + bc_status_notifier_tool_tip_unref(tooltip); + bc_status_notifier_params_unref(params); +} + +static void _linphone_status_icon_impl_sn_enable_blinking(LinphoneStatusIcon *si, gboolean val) { + BcStatusNotifier *sn = (BcStatusNotifier *)si->data; + if(val) { + bc_status_notifier_update_status(sn, BcStatusNotifierStatusNeedsAttention); + } else { + bc_status_notifier_update_status(sn, BcStatusNotifierStatusPassive); + } +} + +static void _linphone_status_icon_impl_is_supported_cb(const char *prefix, gboolean result, void **data) { + _LinphoneStatusIconDesc *desc = (_LinphoneStatusIconDesc *)data[0]; + LinphoneStatusIconDescIsSupportedResultCb cb = (LinphoneStatusIconDescIsSupportedResultCb)data[1]; + if(cb) cb(desc, result, data[2]); + g_free(data); + g_free(desc); +} + +static gboolean _linphone_status_icon_impl_sn_is_supported( + const _LinphoneStatusIconDesc *desc, + gboolean *result, + LinphoneStatusIconDescIsSupportedResultCb cb, + void *user_data) { + + _LinphoneStatusIconDesc *desc2; + void **data; + const char *desktop = g_getenv("XDG_CURRENT_DESKTOP"); + + if(desktop == NULL || g_strcmp0(desktop, "KDE") != 0) { + *result = FALSE; + return TRUE; + } + + desc2 = g_new(_LinphoneStatusIconDesc, 1); + *desc2 = *desc; + data = g_new(void *, 3); + data[0] = desc2; + data[1] = cb; + data[2] = user_data; + bc_status_notifier_is_supported( + "org.kde", + (BcStatusNotifierSupportDetectionCb)_linphone_status_icon_impl_is_supported_cb, + data + ); + return FALSE; +} + +static const _LinphoneStatusIconDesc _linphone_status_icon_impl_status_notifier = { + .impl_name = "status_notifier", + .init = _linphone_status_icon_impl_sn_init, + .uninit = NULL, + .start = _linphone_status_icon_impl_sn_start, + .enable_blinking = _linphone_status_icon_impl_sn_enable_blinking, + .is_supported = _linphone_status_icon_impl_sn_is_supported +}; +#endif diff --git a/gtk/status_icon.h b/gtk/status_icon.h new file mode 100644 index 000000000..233733724 --- /dev/null +++ b/gtk/status_icon.h @@ -0,0 +1,53 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2015 Belledonne Communications + +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. +*/ + +/* + * LinphoneStatusIcon is an singleton interface which abstracts the + * technology used to manage the status icon. + */ + +#include +#include + +struct _LinphoneStatusIcon; +typedef void (*LinphoneStatusIconOnClickCallback)(struct _LinphoneStatusIcon *si, void *user_data); + + +typedef struct _LinphoneStatusIconParams LinphoneStatusIconParams; + +LinphoneStatusIconParams *linphone_status_icon_params_new(void); +LinphoneStatusIconParams *linphone_status_icon_params_ref(LinphoneStatusIconParams *obj); +void linphone_status_icon_params_unref(LinphoneStatusIconParams *obj); + +void linphone_status_icon_params_set_title(LinphoneStatusIconParams *obj, const char *title); +void linphone_status_icon_params_set_description(LinphoneStatusIconParams *obj, const char *desc); +void linphone_status_icon_params_set_menu(LinphoneStatusIconParams *obj, GtkWidget *menu); +void linphone_status_icon_params_set_on_click_cb(LinphoneStatusIconParams* obj, LinphoneStatusIconOnClickCallback cb, void *user_data); + + +typedef void (*LinphoneStatusIconReadyCb)(void *user_data); + +typedef struct _LinphoneStatusIcon LinphoneStatusIcon; + +gboolean linphone_status_icon_init(LinphoneStatusIconReadyCb ready_cb, void* user_data); +void linphone_status_icon_uninit(void); +LinphoneStatusIcon *linphone_status_icon_get(void); +const char *linphone_status_icon_get_implementation_name(const LinphoneStatusIcon *obj); +void linphone_status_icon_start(LinphoneStatusIcon *obj, LinphoneStatusIconParams *params); +void linphone_status_icon_enable_blinking(LinphoneStatusIcon *obj, gboolean enable); diff --git a/gtk/status_notifier.c b/gtk/status_notifier.c new file mode 100644 index 000000000..da9357720 --- /dev/null +++ b/gtk/status_notifier.c @@ -0,0 +1,644 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2015 Belledonne Communications + +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 "status_notifier.h" +#include +#include + +#ifdef _MSC_VER +#include +#define getpid() _getpid() +typedef int lppid_t; +#else +#include +typedef pid_t lppid_t; +#endif + +const gchar *bc_status_notifier_category_to_string(BcStatusNotifierCategory c) { + switch(c){ + case BcStatusNotifierCategoryApplicationStatus: + return "ApplicationStatus"; + case BcStatusNotifierCategoryCommunications: + return "Communications"; + case BcStatusNotifierCategorySystemService: + return "SystemServices"; + case BcStatusNotifierCategoryHardware: + return "Hardware"; + } + return "bad category"; +} + +const gchar *bc_status_notifier_status_to_string(BcStatusNotifierStatus s) { + switch(s){ + case BcStatusNotifierStatusPassive: + return "Passive"; + case BcStatusNotifierStatusActive: + return "Active"; + case BcStatusNotifierStatusNeedsAttention: + return "NeedsAttention"; + } + return "badstatus"; +}; + + +struct _BcStatusNotifierToolTip { + char *icon_name; + char *title; + char *text; + int ref; +}; + +BcStatusNotifierToolTip *bc_status_notifier_tool_tip_new(const char *icon_name, const char *title, const char *text) { + BcStatusNotifierToolTip *obj = (BcStatusNotifierToolTip *)g_new0(BcStatusNotifierToolTip, 1); + if(icon_name) obj->icon_name = g_strdup(icon_name); + if(title) obj->title = g_strdup(title); + if(text) obj->text = g_strdup(text); + return obj; +} + +BcStatusNotifierToolTip *bc_status_notifier_tool_tip_ref(BcStatusNotifierToolTip *obj) { + obj->ref++; + return obj; +} + +void bc_status_notifier_tool_tip_unref(BcStatusNotifierToolTip *obj) { + obj->ref--; + if(obj->ref < 0) { + if(obj->icon_name) g_free(obj->icon_name); + if(obj->title) g_free(obj->title); + if(obj->text) g_free(obj->text); + g_free(obj); + } +} + +static GVariant *_bc_status_notifier_tool_tip_to_variant(const BcStatusNotifierToolTip *obj) { + GVariant *attr[] = { + g_variant_new_string(obj->icon_name ? obj->icon_name : ""), + g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0), + g_variant_new_string(obj->title ? obj->title : ""), + g_variant_new_string(obj->text ? obj->text : ""), + }; + return g_variant_new_tuple(attr, 4); +} + + +static const char *_bc_status_notifier_to_string[] = { + "vertical", + "horizontal", + NULL +}; + +static BcStatusNotifierOrientation _bc_status_notifier_orientation_from_string(const char *s) { + int i; + for(i=0; _bc_status_notifier_to_string[i] && g_strcmp0(s, _bc_status_notifier_to_string[i]) == 0; i++); + if(_bc_status_notifier_to_string[i]) return i; + else return BcStatusNotifierOrientationVertical; +} + + +struct _BcStatusNotifierParams{ + char *prefix; + int item_id; + BcStatusNotifierCategory category; + char *id; + char *title; + BcStatusNotifierStatus status; + guint32 window_id; + char *icon_name; + char *overlay_icon_name; + char *attention_icon_name; + char *attention_movie_name; + BcStatusNotifierToolTip *tool_tip; + BcStatusNotifierSignalsVTable vtable; + void *user_data; + int ref; +}; + +#define DEFAULT_PREFIX "org.freedesktop" + +BcStatusNotifierParams *bc_status_notifier_params_new(void) { + BcStatusNotifierParams *obj = (BcStatusNotifierParams *)g_new0(BcStatusNotifierParams, 1); + obj->prefix = g_strdup(DEFAULT_PREFIX); + return obj; +} + +BcStatusNotifierParams *bc_status_notifier_params_ref(BcStatusNotifierParams *obj) { + obj->ref++; + return obj; +} + +void bc_status_notifier_params_unref(BcStatusNotifierParams *obj) { + obj->ref--; + if(obj->ref < 0) { + if(obj->prefix) g_free(obj->prefix); + if(obj->id) g_free(obj->id); + if(obj->title) g_free(obj->title); + if(obj->icon_name) g_free(obj->icon_name); + if(obj->overlay_icon_name) g_free(obj->overlay_icon_name); + if(obj->attention_icon_name) g_free(obj->attention_icon_name); + if(obj->attention_movie_name) g_free(obj->attention_movie_name); + if(obj->tool_tip) bc_status_notifier_tool_tip_unref(obj->tool_tip); + g_free(obj); + } +} + +void bc_status_notifier_params_set_dbus_prefix(BcStatusNotifierParams *obj, const char *prefix) { + if(obj->prefix) g_free(obj->prefix); + if(prefix) obj->prefix = g_strdup(prefix); + else obj->prefix = NULL; +} + +const char *bc_satus_notifier_params_get_dbus_prefix(const BcStatusNotifierParams *obj) { + return obj->prefix; +} + +void bc_status_notifier_params_set_item_id(BcStatusNotifierParams *obj, int item_id) { + obj->item_id = item_id; +} + +int bc_status_notifier_params_get_item_id(const BcStatusNotifierParams *obj) { + return obj->item_id; +} + +void bc_status_notifier_params_set_category(BcStatusNotifierParams *obj, BcStatusNotifierCategory category) { + obj->category = category; +} + +BcStatusNotifierCategory bc_status_notifier_params_get_category(const BcStatusNotifierParams *obj) { + return obj->category; +} + +void bc_status_notifier_params_set_id(BcStatusNotifierParams *obj, const char *id) { + if(obj->id) g_free(obj->id); + if(id) obj->id = g_strdup(id); + else obj->id = NULL; +} + +const char *bc_status_notifier_params_get_id(const BcStatusNotifierParams *obj) { + return obj->id; +} + +void bc_status_notifier_params_set_title(BcStatusNotifierParams *obj, const char *title) { + if(obj->title) g_free(obj->title); + if(title) obj->title = g_strdup(title); + else obj->title = NULL; +} + +const char *bc_status_notifier_params_get_title(const BcStatusNotifierParams *obj) { + return obj->title; +} + +void bc_status_notifier_params_set_status(BcStatusNotifierParams *obj, BcStatusNotifierStatus status) { + obj->status = status; +} + +BcStatusNotifierStatus bc_status_notifier_params_get_status(const BcStatusNotifierParams *obj) { + return obj->status; +} + +void bc_status_notifier_params_set_window_id(BcStatusNotifierParams *obj, guint32 window_id) { + obj->window_id = window_id; +} + +guint32 bc_status_notifier_params_get_window_id(const BcStatusNotifierParams *obj) { + return obj->window_id; +} + +void bc_status_notifier_params_set_icon_name(BcStatusNotifierParams *obj, const char *name) { + if(obj->icon_name) g_free(obj->icon_name); + if(name) obj->icon_name = g_strdup(name); + else obj->icon_name = NULL; +} + +const char *bc_status_notifier_params_get_icon_name(const BcStatusNotifierParams *obj) { + return obj->icon_name; +} + +void bc_status_notifier_params_set_overlay_icon_name(BcStatusNotifierParams *obj, const char *name) { + if(obj->overlay_icon_name) g_free(obj->overlay_icon_name); + if(name) obj->overlay_icon_name = g_strdup(name); + else obj->overlay_icon_name = NULL; +} + +const char *bc_status_notifier_params_get_overlay_icon_name(const BcStatusNotifierParams *obj) { + return obj->overlay_icon_name; +} + +void bc_status_notifier_params_set_attention_icon_name(BcStatusNotifierParams *obj, const char *name) { + if(obj->attention_icon_name) g_free(obj->attention_icon_name); + if(name) obj->attention_icon_name = g_strdup(name); + else obj->attention_icon_name = NULL; +} + +const char *bc_status_notifier_params_get_attention_icon_name(const BcStatusNotifierParams *obj) { + return obj->attention_icon_name; +} + +void bc_status_notifier_params_set_attention_movie_name(BcStatusNotifierParams *obj, const char *name) { + if(obj->attention_movie_name) g_free(obj->attention_movie_name); + if(name) obj->attention_movie_name = g_strdup(name); + else obj->attention_movie_name = NULL; +} + +const char *bc_status_notifier_params_get_attention_movie_name(const BcStatusNotifierParams *obj) { + return obj->attention_movie_name; +} + +void bc_status_notifier_params_set_tool_tip(BcStatusNotifierParams *obj, BcStatusNotifierToolTip *tool_tip) { + if(obj->tool_tip) bc_status_notifier_tool_tip_unref(obj->tool_tip); + if(tool_tip) obj->tool_tip = bc_status_notifier_tool_tip_ref(tool_tip); + else obj->tool_tip = NULL; +} + +const BcStatusNotifierToolTip *bc_status_notifier_params_get_tool_tip(const BcStatusNotifierParams *obj) { + return obj->tool_tip; +} + +void bc_status_notifier_params_set_vtable(BcStatusNotifierParams *obj, const BcStatusNotifierSignalsVTable *vtable, void *user_data) { + obj->vtable = *vtable; + obj->user_data = user_data; +} + + +struct _BcStatusNotifier { + BcStatusNotifierParams *params; + guint bus_owner_id; + GDBusConnection *conn; + BcStatusNotifierState state; + BcStatusNotifierStateVTable vtable; + void *user_data; + int ref; +}; + +#define ITEM_NAME "StatusNotifierItem" +#define WATCHER_NAME "StatusNotifierWatcher" +#define CALL_TIMEOUT 1000 + +#define STATUS_NOTIFIER_INTROSPECTION_DATA \ + " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + " + +BcStatusNotifier *bc_status_notifier_new(void) { + return (BcStatusNotifier *)g_new0(BcStatusNotifier, 1); +} + +BcStatusNotifier *bc_status_notifier_ref(BcStatusNotifier *obj) { + obj->ref++; + return obj; +} + +void bc_status_notifier_unref(BcStatusNotifier *obj) { + obj->ref--; + if(obj->ref < 0) { + bc_status_notifier_stop(obj); + if(obj->params) bc_status_notifier_params_unref(obj->params); + g_free(obj); + } +} + +static GVariant *_bc_status_notifier_get_property_cb( + GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, + BcStatusNotifier *sn) { + + + GVariant *value = NULL; + if(g_strcmp0(property_name, "Category") == 0) { + value = g_variant_new_string(bc_status_notifier_category_to_string(sn->params->category)); + } else if(g_strcmp0(property_name, "Id") == 0) { + value = g_variant_new_string(sn->params->id ? sn->params->id : ""); + } else if(g_strcmp0(property_name, "Title") == 0) { + value = g_variant_new_string(sn->params->title ? sn->params->title : ""); + } else if(g_strcmp0(property_name, "Status") == 0) { + value = g_variant_new_string(bc_status_notifier_status_to_string(sn->params->status)); + } else if(g_strcmp0(property_name, "WindowId") == 0) { + value = g_variant_new_uint32(sn->params->window_id); + } else if(g_strcmp0(property_name, "IconName") == 0) { + value = g_variant_new_string(sn->params->icon_name ? sn->params->icon_name : ""); + } else if(g_strcmp0(property_name, "IconPixmap") == 0) { + value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); + } else if(g_strcmp0(property_name, "OverlayIconName") == 0) { + value = g_variant_new_string(sn->params->overlay_icon_name ? sn->params->overlay_icon_name : ""); + } else if(g_strcmp0(property_name, "OverlayIconPixmap") == 0) { + value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); + } else if(g_strcmp0(property_name, "AttentionIconName") == 0) { + value = g_variant_new_string(sn->params->attention_icon_name ? sn->params->attention_icon_name : ""); + } else if(g_strcmp0(property_name, "AttentionIconPixmap") == 0) { + value = g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0); + } else if(g_strcmp0(property_name, "AttentionMovieName") == 0) { + value = g_variant_new_string(sn->params->attention_movie_name ? sn->params->attention_movie_name : ""); + } else if(g_strcmp0(property_name, "ToolTip") == 0) { + if(sn->params->tool_tip) { + value = _bc_status_notifier_tool_tip_to_variant(sn->params->tool_tip); + } else { + BcStatusNotifierToolTip *tool_tip = bc_status_notifier_tool_tip_new("", "", ""); + value = _bc_status_notifier_tool_tip_to_variant(tool_tip); + bc_status_notifier_tool_tip_unref(tool_tip); + } + } + return value; +} + +static void _bc_status_notifier_method_call_cb( + GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + BcStatusNotifier *sn) { + + if(g_strcmp0(method_name, "ContextMenu") == 0) { + if(sn->params->vtable.context_menu_called_cb) { + int x, y; + g_variant_get_child(parameters, 0, "i", &x); + g_variant_get_child(parameters, 1, "i", &y); + sn->params->vtable.context_menu_called_cb(sn, x, y, sn->params->user_data); + } + } else if(g_strcmp0(method_name, "Activate") == 0) { + if(sn->params->vtable.activate_called_cb) { + int x, y; + g_variant_get_child(parameters, 0, "i", &x); + g_variant_get_child(parameters, 1, "i", &y); + sn->params->vtable.activate_called_cb(sn, x, y, sn->params->user_data); + } + } else if(g_strcmp0(method_name, "SecondaryActivate") == 0) { + if(sn->params->vtable.secondary_activate_called_cb) { + int x, y; + g_variant_get_child(parameters, 0, "i", &x); + g_variant_get_child(parameters, 1, "i", &y); + sn->params->vtable.secondary_activate_called_cb(sn, x, y, sn->params->user_data); + } + } else if(g_strcmp0(method_name, "Scroll") == 0) { + if(sn->params->vtable.scroll_called_cb) { + int delta; + BcStatusNotifierOrientation orient; + char *orient_str; + g_variant_get_child(parameters, 0, "i", &delta); + g_variant_get_child(parameters, 1, "&s", &orient_str); + orient = _bc_status_notifier_orientation_from_string(orient_str); + sn->params->vtable.scroll_called_cb(sn, delta, orient, sn->params->user_data); + } + } + g_dbus_method_invocation_return_value(invocation, NULL); +} + +static void _bc_status_notifier_bus_acquired_cb(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { + char *interface_name = g_strdup_printf("%s.%s", sn->params->prefix, ITEM_NAME); + char *item_path = g_strdup_printf("/%s", ITEM_NAME); + GDBusInterfaceVTable vtable = { + (GDBusInterfaceMethodCallFunc)_bc_status_notifier_method_call_cb, + (GDBusInterfaceGetPropertyFunc)_bc_status_notifier_get_property_cb, + NULL + }; + + GDBusNodeInfo *node_info = g_dbus_node_info_new_for_xml(STATUS_NOTIFIER_INTROSPECTION_DATA, NULL); + GDBusInterfaceInfo *interface = g_dbus_node_info_lookup_interface( + node_info, + interface_name + ); + g_free(interface_name); + + sn->conn = conn; + + g_dbus_connection_register_object( + conn, + item_path, + interface, + &vtable, + bc_status_notifier_ref(sn), + (GDestroyNotify)bc_status_notifier_unref, + NULL + ); + g_free(item_path); + + g_dbus_node_info_unref(node_info); +} + +static void _bc_status_notifier_name_acquired_cb(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { + GVariant *item_name = g_variant_new_string(name); + GVariant *parameters = g_variant_new_tuple(&item_name, 1); + char *watcher_bus_name = g_strdup_printf("%s.%s", sn->params->prefix, WATCHER_NAME); + char *watcher_interface_name = watcher_bus_name; + char *watcher_path = g_strdup_printf("/%s", WATCHER_NAME); + + g_dbus_connection_call( + conn, + watcher_bus_name, + watcher_path, + watcher_interface_name, + "RegisterStatusNotifierItem", + parameters, + NULL, + G_DBUS_CALL_FLAGS_NONE, + CALL_TIMEOUT, + NULL, + NULL, + NULL + ); + g_free(watcher_bus_name); + g_free(watcher_path); + + sn->state = BcStatusNotifierStateRunning; + if(sn->vtable.success) sn->vtable.success(sn, sn->user_data); +} + +static void _bc_status_notifier_name_lost(GDBusConnection *conn, const gchar *name, BcStatusNotifier *sn) { + if(conn == NULL) { + sn->state = BcStatusNotifierStateStopped; + if(sn->vtable.fail) sn->vtable.fail(sn, sn->user_data); + } +} + +void bc_status_notifier_start(BcStatusNotifier* obj, BcStatusNotifierParams* params, const BcStatusNotifierStateVTable *vtable, void *user_data) { + if(obj->state == BcStatusNotifierStateStopped) { + lppid_t pid = getpid(); + char *dbus_name = g_strdup_printf("%s.%s-%d-%d", params->prefix, ITEM_NAME, pid, params->item_id); + + if(obj->params) bc_status_notifier_params_unref(obj->params); + obj->params = bc_status_notifier_params_ref(params); + if(vtable) obj->vtable = *vtable; + else { + obj->vtable.success = NULL; + obj->vtable.fail = NULL; + } + obj->user_data = user_data; + obj->state = BcStatusNotifierStateStarting; + obj->bus_owner_id = g_bus_own_name( + G_BUS_TYPE_SESSION, + dbus_name, + G_BUS_NAME_OWNER_FLAGS_NONE, + (GBusAcquiredCallback)_bc_status_notifier_bus_acquired_cb, + (GBusNameAcquiredCallback)_bc_status_notifier_name_acquired_cb, + (GBusNameLostCallback)_bc_status_notifier_name_lost, + bc_status_notifier_ref(obj), + (GDestroyNotify)bc_status_notifier_unref + ); + g_free(dbus_name); + } +} + +void bc_status_notifier_stop(BcStatusNotifier *obj) { + if(obj->state == BcStatusNotifierStateRunning) { + g_bus_unown_name(obj->bus_owner_id); + obj->bus_owner_id = 0; + obj->conn = NULL; + obj->state = BcStatusNotifierStateStopped; + } +} + +const BcStatusNotifierParams *bc_status_notifier_get_params(const BcStatusNotifier *obj) { + return obj->params; +} + +static void _bc_status_notifier_emit_signal(const BcStatusNotifier *obj, const char *sig_name, GVariant *parameters) { + char *item_interface_name = g_strdup_printf("%s.%s", obj->params->prefix, ITEM_NAME); + char *item_path = g_strdup_printf("/%s", ITEM_NAME); + g_dbus_connection_emit_signal( + obj->conn, + NULL, + item_path, + item_interface_name, + sig_name, + parameters, + NULL + ); + g_free(item_interface_name); + g_free(item_path); +} + +void bc_status_notifier_update_title(BcStatusNotifier *obj, const char *title) { + bc_status_notifier_params_set_title(obj->params, title); + _bc_status_notifier_emit_signal(obj, "NewTitle", NULL); +} + +void bc_status_notifier_update_icon(BcStatusNotifier *obj, const char *icon_name) { + bc_status_notifier_params_set_icon_name(obj->params, icon_name); + _bc_status_notifier_emit_signal(obj, "NewIcon", NULL); +} + +void bc_status_notifier_update_attention_icon(BcStatusNotifier *obj, const char *icon_name) { + bc_status_notifier_params_set_attention_icon_name(obj->params, icon_name); + _bc_status_notifier_emit_signal(obj, "NewAttentionIcon", NULL); +} + +void bc_status_notifier_update_overlay_icon(BcStatusNotifier *obj, const char *icon_name) { + bc_status_notifier_params_set_overlay_icon_name(obj->params, icon_name); + _bc_status_notifier_emit_signal(obj, "NewOverlayIcon", NULL); +} + +void bc_status_notifier_update_tool_tip(BcStatusNotifier *obj, BcStatusNotifierToolTip *tool_tip) { + bc_status_notifier_params_set_tool_tip(obj->params, tool_tip); + _bc_status_notifier_emit_signal(obj, "NewToolTip", NULL); +} + +void bc_status_notifier_update_status(BcStatusNotifier *obj, BcStatusNotifierStatus status) { + GVariant *status_var = g_variant_new_string(bc_status_notifier_status_to_string(status)); + GVariant *parameter = g_variant_new_tuple(&status_var, 1); + bc_status_notifier_params_set_status(obj->params, status); + _bc_status_notifier_emit_signal(obj, "NewStatus", parameter); +} + + +typedef struct _BcWatcherDetectionCtx { + char *prefix; + guint watcher_id; + BcStatusNotifierSupportDetectionCb cb; + void *user_data; +} BcWatcherDetectionCtx; + +static void _bc_watcher_detection_ctx_free(BcWatcherDetectionCtx *obj) { + g_free(obj->prefix); + g_free(obj); +} + +static void _bc_watcher_name_appeared_cb(GDBusConnection *conn, const char *name, const char *name_owner, BcWatcherDetectionCtx *ctx) { + g_bus_unwatch_name(ctx->watcher_id); + if(ctx->cb) ctx->cb(ctx->prefix, 1, ctx->user_data); +} + +static void _bc_watcher_name_vannished_cb(GDBusConnection *conn, const char *name, BcWatcherDetectionCtx *ctx) { + g_bus_unwatch_name(ctx->watcher_id); + if(ctx->cb) ctx->cb(ctx->prefix, 0, ctx->user_data); +} + +void bc_status_notifier_is_supported(const char* prefix, BcStatusNotifierSupportDetectionCb cb, void *user_data) { + char *bus_name = g_strdup_printf("%s.%s", prefix, WATCHER_NAME); + BcWatcherDetectionCtx *ctx = (BcWatcherDetectionCtx *)g_new0(BcWatcherDetectionCtx, 1); + ctx->prefix = g_strdup(prefix); + ctx->cb = cb; + ctx->user_data = user_data; + + ctx->watcher_id = g_bus_watch_name( + G_BUS_TYPE_SESSION, + bus_name, + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback)_bc_watcher_name_appeared_cb, + (GBusNameVanishedCallback)_bc_watcher_name_vannished_cb, + ctx, + (GDestroyNotify)_bc_watcher_detection_ctx_free + ); + g_free(bus_name); +} diff --git a/gtk/status_notifier.h b/gtk/status_notifier.h new file mode 100644 index 000000000..b8067fdeb --- /dev/null +++ b/gtk/status_notifier.h @@ -0,0 +1,163 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2015 Belledonne Communications + +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. +*/ + +/** + * BcStatusNotifier is an implementation of the StatusNotiferItem standard defined by freedesktop.org. + * It is a new way to manage status icons on GNU/Linux systems by using D-Bus. It is implemented by + * Unity desktop environmemt and it is the only way to create status icons on KDE 5. + * Visit http://freedesktop.org/wiki/Specifications/StatusNotifierItem/ for more information. + */ + +#ifndef STATUS_NOTIFIER_H +#define STATUS_NOTIFIER_H + +#include + +struct _BcStatusNotifier; + + +typedef enum { + BcStatusNotifierCategoryApplicationStatus, + BcStatusNotifierCategoryCommunications, + BcStatusNotifierCategorySystemService, + BcStatusNotifierCategoryHardware +} BcStatusNotifierCategory; + +const gchar *bc_status_notifier_category_to_string(BcStatusNotifierCategory c); + + +typedef enum { + BcStatusNotifierStatusPassive, + BcStatusNotifierStatusActive, + BcStatusNotifierStatusNeedsAttention +} BcStatusNotifierStatus; + +const gchar *bc_status_notifier_status_to_string(BcStatusNotifierStatus s); + + +typedef struct _BcStatusNotifierToolTip BcStatusNotifierToolTip; + +BcStatusNotifierToolTip *bc_status_notifier_tool_tip_new(const char *icon_name, const char *title, const char *text); +BcStatusNotifierToolTip *bc_status_notifier_tool_tip_ref(BcStatusNotifierToolTip *obj); +void bc_status_notifier_tool_tip_unref(BcStatusNotifierToolTip *obj); + + +typedef enum _BcStatusNotifierOrientation { + BcStatusNotifierOrientationVertical, + BcStatusNotifierOrientationHorizontal +} BcStatusNotifierOrientation; + + +typedef void (*BcStatusNotifierContextMenuCalledCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); +typedef void (*BcStatusNotifierActivateCalledCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); +typedef void (*BcStatusNotifierSecondaryActivateCb)(struct _BcStatusNotifier *sn, int x, int y, void *user_data); +typedef void (*BcStatusNotifierScrollCalledCb)(struct _BcStatusNotifier *sn, int delta, BcStatusNotifierOrientation o, void *user_data); + +typedef struct _BcStatusNotifierSignalsVTable { + BcStatusNotifierContextMenuCalledCb context_menu_called_cb; + BcStatusNotifierActivateCalledCb activate_called_cb; + BcStatusNotifierSecondaryActivateCb secondary_activate_called_cb; + BcStatusNotifierScrollCalledCb scroll_called_cb; +} BcStatusNotifierSignalsVTable; + + +typedef struct _BcStatusNotifierParams BcStatusNotifierParams; + +BcStatusNotifierParams *bc_status_notifier_params_new(void); +BcStatusNotifierParams *bc_status_notifier_params_ref(BcStatusNotifierParams *obj); +void bc_status_notifier_params_unref(BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_dbus_prefix(BcStatusNotifierParams *obj, const char *prefix); +const char *bc_satus_notifier_params_get_dbus_prefix(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_item_id(BcStatusNotifierParams *obj, int item_id); +int bc_status_notifier_params_get_item_id(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_category(BcStatusNotifierParams *obj, BcStatusNotifierCategory category); +BcStatusNotifierCategory bc_status_notifier_params_get_category(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_id(BcStatusNotifierParams *obj, const char *id); +const char *bc_status_notifier_params_get_id(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_title(BcStatusNotifierParams *obj, const char *title); +const char *bc_status_notifier_params_get_title(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_status(BcStatusNotifierParams *obj, BcStatusNotifierStatus status); +BcStatusNotifierStatus bc_status_notifier_params_get_status(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_window_id(BcStatusNotifierParams *obj, guint32 window_id); +guint32 bc_status_notifier_params_get_window_id(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_icon_name(BcStatusNotifierParams *obj, const char *name); +const char *bc_status_notifier_params_get_icon_name(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_overlay_icon_name(BcStatusNotifierParams *obj, const char *name); +const char *bc_status_notifier_params_get_overlay_icon_name(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_attention_icon_name(BcStatusNotifierParams *obj, const char *icon_name); +const char *bc_status_notifier_params_get_attention_icon_name(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_attention_movie_name(BcStatusNotifierParams *obj, const char *name); +const char *bc_status_notifier_params_get_attention_movie_name(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_tool_tip(BcStatusNotifierParams *obj, BcStatusNotifierToolTip *tool_tip); +const BcStatusNotifierToolTip *bc_status_notifier_params_get_tool_tip(const BcStatusNotifierParams *obj); + +void bc_status_notifier_params_set_vtable(BcStatusNotifierParams *obj, const BcStatusNotifierSignalsVTable *vtable, void *user_data); + + +typedef enum _BcStatusNotifierState { + BcStatusNotifierStateStopped, + BcStatusNotifierStateStarting, + BcStatusNotifierStateRunning +} BcStatusNotifierState; + + +typedef void (*BcStatusNotifierStartedCb)(struct _BcStatusNotifier *sn, void *user_data); +typedef void (*BcStatusNotifierStartingFailedCb)(struct _BcStatusNotifier *sn, void *user_data); + +typedef struct _BcStatusNotifierStateVTable { + BcStatusNotifierStartedCb success; + BcStatusNotifierStartingFailedCb fail; +} BcStatusNotifierStateVTable; + + +typedef struct _BcStatusNotifier BcStatusNotifier; + +BcStatusNotifier *bc_status_notifier_new(void); +BcStatusNotifier *bc_status_notifier_ref(BcStatusNotifier *obj); +void bc_status_notifier_unref(BcStatusNotifier *obj); + +void bc_status_notifier_start(BcStatusNotifier* obj, BcStatusNotifierParams* params, const BcStatusNotifierStateVTable* vtable, void* user_data); +void bc_status_notifier_stop(BcStatusNotifier* obj); + +const BcStatusNotifierParams *bc_status_notifier_get_params(const BcStatusNotifier *obj); +void bc_status_notifier_update_title(BcStatusNotifier* obj, const char* title); +void bc_status_notifier_update_icon(BcStatusNotifier* obj, const char* icon_name); +void bc_status_notifier_update_attention_icon(BcStatusNotifier* obj, const char* icon_name); +void bc_status_notifier_update_overlay_icon(BcStatusNotifier* obj, const char* icon_name); +void bc_status_notifier_update_tool_tip(BcStatusNotifier* obj, BcStatusNotifierToolTip* tool_tip); +void bc_status_notifier_update_status(BcStatusNotifier* obj, BcStatusNotifierStatus status); + + +typedef void (*BcStatusNotifierSupportDetectionCb)(const char *prefix, gboolean is_supported, void *user_data); + +void bc_status_notifier_is_supported(const char* prefix, BcStatusNotifierSupportDetectionCb cb, void *user_data); + +#endif \ No newline at end of file diff --git a/gtk/support.c b/gtk/support.c index de6c3a910..ebb61c33d 100644 --- a/gtk/support.c +++ b/gtk/support.c @@ -92,17 +92,17 @@ create_pixbuf_animation(const gchar *filename) gchar *pathname = NULL; GdkPixbufAnimation *pixbuf; GError *error = NULL; - + if (!filename || !filename[0]) return NULL; - + pathname = find_pixmap_file (filename); - + if (!pathname){ g_warning (_("Couldn't find pixmap file: %s"), filename); return NULL; } - + pixbuf = gdk_pixbuf_animation_new_from_file (pathname, &error); if (!pixbuf){ fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", @@ -155,26 +155,13 @@ const char *linphone_gtk_get_lang(const char *config_file){ void linphone_gtk_set_lang(const char *code){ LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); - const char *curlang; - #if defined(WIN32) || defined(__APPLE__) - curlang=getenv("LANG"); - #else - curlang=getenv("LANGUAGE"); - #endif + const char *curlang=g_getenv("LANGUAGE"); if (curlang!=NULL && strncmp(curlang,code,2)==0) { /* do not loose the _territory@encoding part*/ return; } lp_config_set_string(cfg,"GtkUi","lang",code); -#ifdef WIN32 - char tmp[128]; - snprintf(tmp,sizeof(tmp),"LANG=%s",code); - _putenv(tmp); -#elif __APPLE__ - setenv("LANG",code,1); -#else - setenv("LANGUAGE",code,1); -#endif + g_setenv("LANGUAGE",code,1); } const gchar *linphone_gtk_get_ui_config(const char *key, const char *def){ @@ -203,6 +190,27 @@ void linphone_gtk_set_ui_config(const char *key , const char * val){ lp_config_set_string(cfg,"GtkUi",key,val); } +const char *linphone_gtk_get_sound_path(const char *name){ + static char *ret=NULL; + const char *file; + file=linphone_gtk_get_ui_config(name,NULL); + if (file==NULL){ + char *dirname=g_path_get_dirname(name); + if (strcmp(dirname,".")!=0){ + g_free(dirname); + return name; + } + g_free(dirname); + file=name; + } + if (ret){ + g_free(ret); + ret=NULL; + } + ret=g_build_filename(PACKAGE_SOUND_DIR,name,NULL); + return ret; +} + static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){ char tmp[64]; char *dot; 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/gtk/utils.c b/gtk/utils.c index b8db633d8..fc3ebde92 100644 --- a/gtk/utils.c +++ b/gtk/utils.c @@ -30,7 +30,7 @@ void *linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, co switch(ws){ case LinphoneWaitingStart: gdk_threads_enter(); - w=linphone_gtk_create_window("waiting"); + w=linphone_gtk_create_window("waiting", NULL); gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window())); gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT); if (purpose) { @@ -102,14 +102,14 @@ void linphone_gtk_reload_sound_devices(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); linphone_core_reload_sound_devices(linphone_gtk_get_core()); - linphone_gtk_fill_soundcards(pb); + if (pb) linphone_gtk_fill_soundcards(pb); } void linphone_gtk_reload_video_devices(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); linphone_core_reload_video_devices(linphone_gtk_get_core()); - linphone_gtk_fill_webcams(pb); + if (pb) linphone_gtk_fill_webcams(pb); } #ifdef HAVE_LIBUDEV_H diff --git a/gtk/videowindow.c b/gtk/videowindow.c new file mode 100644 index 000000000..ebc5f69a5 --- /dev/null +++ b/gtk/videowindow.c @@ -0,0 +1,362 @@ +/* +linphone, gtk interface. +Copyright (C) 2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" + +#ifdef GDK_WINDOWING_X11 +#include +#elif defined(WIN32) +#include +#elif defined(__APPLE__) +extern void *gdk_quartz_window_get_nswindow(GdkWindow *window); +extern void *gdk_quartz_window_get_nsview(GdkWindow *window); +#endif + +#include + +enum { + TARGET_STRING, + TARGET_TEXT, + TARGET_URILIST +}; + +static GtkTargetEntry targets[] = { + { "text/uri-list", GTK_TARGET_OTHER_APP, TARGET_URILIST }, +}; + +static void set_video_controls_position(GtkWidget *video_window); + +static void on_end_of_play(LinphonePlayer *player, void *user_data){ + linphone_player_close(player); +} + +static void drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, gpointer user_data){ + int datalen=gtk_selection_data_get_length(selection_data) >= 0; + const void *data=gtk_selection_data_get_data(selection_data); + LinphoneCall *call=g_object_get_data(G_OBJECT(widget),"call"); + + ms_message("target_type=%i, datalen=%i, data=%p",target_type,datalen,data); + if (target_type==TARGET_URILIST && data){ + LinphonePlayer *player=linphone_call_get_player(call); + const char *path=(const char*)data; + if (player){ + if (strstr(path,"file://")==path) path+=strlen("file://"); + if (linphone_player_open(player,path,on_end_of_play,NULL)==0){ + linphone_player_start(player); + }else{ + GtkWidget *warn=gtk_message_dialog_new(GTK_WINDOW(widget),GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE, + _("Cannot play %s."),path); + g_signal_connect(warn,"response",(GCallback)gtk_widget_destroy,NULL); + gtk_widget_show(warn); + } + } + + } + gtk_drag_finish (context, TRUE, FALSE, time); +} + +static gboolean drag_drop(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time, gpointer user_data){ +#if GTK_CHECK_VERSION(2,21,0) + GList *l=gdk_drag_context_list_targets(drag_context); + GList *elem; + + if (l){ + ms_message("drag_drop"); + /* Choose the best target type */ + for(elem=l;elem!=NULL;elem=g_list_next(elem)){ + char *name=gdk_atom_name(GDK_POINTER_TO_ATOM(elem->data)); + ms_message("target: %s",name); + g_free(name); + } + }else{ + ms_warning("drag_drop no targets"); + return FALSE; + } +#endif + return TRUE; +} + +static void *get_native_handle(GdkWindow *gdkw){ +#ifdef GDK_WINDOWING_X11 + return (void *)GDK_WINDOW_XID(gdkw); +#elif defined(WIN32) + return (void *)GDK_WINDOW_HWND(gdkw); +#elif defined(__APPLE__) + return (void *)gdk_quartz_window_get_nsview(gdkw); +#endif + g_warning("No way to get the native handle from gdk window"); + return 0; +} + +static void _resize_video_window(GtkWidget *video_window, MSVideoSize vsize){ + MSVideoSize cur; + gtk_window_get_size(GTK_WINDOW(video_window),&cur.width,&cur.height); + if (vsize.width*vsize.height > cur.width*cur.height || + ms_video_size_get_orientation(vsize)!=ms_video_size_get_orientation(cur) ){ + gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); + } +} + +static gint resize_video_window(LinphoneCall *call){ + const LinphoneCallParams *params=linphone_call_get_current_params(call); + if (params){ + MSVideoSize vsize=linphone_call_params_get_received_video_size(params); + if (vsize.width>0 && vsize.height>0){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); + if (video_window){ + _resize_video_window(video_window,vsize); + } + } + } + return TRUE; +} + +static void on_video_window_destroy(GtkWidget *w, guint timeout){ + g_source_remove(timeout); + linphone_core_set_native_video_window_id(linphone_gtk_get_core(),LINPHONE_VIDEO_DISPLAY_NONE); +} + +static void video_window_set_fullscreen(GtkWidget *w, gboolean val){ + if (val){ + g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(1)); + gtk_window_fullscreen(GTK_WINDOW(w)); + }else{ + g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(0)); + gtk_window_unfullscreen(GTK_WINDOW(w)); + } +} +/*old names in old version of gdk*/ +#ifndef GDK_KEY_Escape +#define GDK_KEY_Escape GDK_Escape +#define GDK_KEY_F GDK_F +#define GDK_KEY_f GDK_f +#endif + +static void on_video_window_key_press(GtkWidget *w, GdkEvent *ev, gpointer up){ + g_message("Key press event"); + switch(ev->key.keyval){ + case GDK_KEY_f: + case GDK_KEY_F: + video_window_set_fullscreen(w,TRUE); + break; + case GDK_KEY_Escape: + video_window_set_fullscreen(w,FALSE); + break; + } +} + +static void on_controls_response(GtkWidget *dialog, int response_id, GtkWidget *video_window){ + + gtk_widget_destroy(dialog); + switch(response_id){ + case GTK_RESPONSE_YES: + video_window_set_fullscreen(video_window,TRUE); + break; + case GTK_RESPONSE_NO: + video_window_set_fullscreen(video_window,FALSE); + break; + case GTK_RESPONSE_REJECT: + { + LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(video_window),"call"); + linphone_core_terminate_call(linphone_gtk_get_core(),call); + } + break; + } + +} + +static void on_controls_destroy(GtkWidget *w){ + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(w),"video_window"); + gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); + if (timeout!=0){ + g_source_remove(timeout); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(0)); + } + g_object_set_data(G_OBJECT(video_window),"controls",NULL); +} + +static gboolean _set_video_controls_position(GtkWidget *video_window){ + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); + if (w){ + gint vw,vh; + gint cw,ch; + gint x,y; + gtk_window_get_size(GTK_WINDOW(video_window),&vw,&vh); + gtk_window_get_position(GTK_WINDOW(video_window),&x,&y); + gtk_window_get_size(GTK_WINDOW(w),&cw,&ch); + gtk_window_move(GTK_WINDOW(w),x+vw/2 - cw/2, y + vh - ch); + } + return FALSE; +} + +static void set_video_controls_position(GtkWidget *video_window){ + /*do it a first time*/ + _set_video_controls_position(video_window); + /*and schedule to do it a second time in order to workaround a bug in fullscreen mode, where poistion is not taken into account the first time*/ + g_timeout_add(0,(GSourceFunc)_set_video_controls_position,video_window); +} + +static gboolean video_window_moved(GtkWidget *widget, GdkEvent *event, gpointer user_data){ + set_video_controls_position(widget); + return FALSE; +} + +static GtkWidget *show_video_controls(GtkWidget *video_window){ + GtkWidget *w; + w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); + if (!w){ + gboolean isfullscreen=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_window),"fullscreen")); + const char *stock_button=isfullscreen ? GTK_STOCK_LEAVE_FULLSCREEN : GTK_STOCK_FULLSCREEN; + gint response_id=isfullscreen ? GTK_RESPONSE_NO : GTK_RESPONSE_YES ; + gint timeout; + GtkWidget *button; + w=gtk_dialog_new_with_buttons("",GTK_WINDOW(video_window),GTK_DIALOG_DESTROY_WITH_PARENT,stock_button,response_id,NULL); + gtk_window_set_opacity(GTK_WINDOW(w),0.5); + gtk_window_set_decorated(GTK_WINDOW(w),FALSE); + button=gtk_button_new_with_label(_("Hang up")); + gtk_button_set_image(GTK_BUTTON(button),create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png"))); + gtk_widget_show(button); + gtk_dialog_add_action_widget(GTK_DIALOG(w),button,GTK_RESPONSE_REJECT); + g_signal_connect(w,"response",(GCallback)on_controls_response,video_window); + timeout=g_timeout_add(3000,(GSourceFunc)gtk_widget_destroy,w); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(timeout)); + g_signal_connect(w,"destroy",(GCallback)on_controls_destroy,NULL); + g_object_set_data(G_OBJECT(w),"video_window",video_window); + g_object_set_data(G_OBJECT(video_window),"controls",w); + set_video_controls_position(video_window); + gtk_widget_show(w); + }else{ + gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); + g_source_remove(timeout); + timeout=g_timeout_add(3000,(GSourceFunc)gtk_widget_destroy,w); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(timeout)); + } + return w; +} + +static GtkWidget *create_video_window(LinphoneCall *call){ + char *remote,*title; + GtkWidget *video_window; + const LinphoneAddress *addr; + guint timeout; + MSVideoSize vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H}; + GdkColor color; + + addr=linphone_call_get_remote_address(call); + remote=linphone_gtk_address(addr); + video_window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + title=g_strdup_printf("%s - Video call with %s",linphone_gtk_get_ui_config("title","Linphone"),remote); + ms_free(remote); + gtk_window_set_title(GTK_WINDOW(video_window),title); + g_free(title); + gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); + gdk_color_parse("black",&color); + gtk_widget_modify_bg(video_window,GTK_STATE_NORMAL,&color); + + gtk_drag_dest_set(video_window, GTK_DEST_DEFAULT_ALL, targets, sizeof(targets)/sizeof(GtkTargetEntry), GDK_ACTION_COPY); + gtk_widget_show(video_window); + gdk_window_set_events(gtk_widget_get_window(video_window), + gdk_window_get_events(gtk_widget_get_window(video_window)) | GDK_POINTER_MOTION_MASK); + timeout=g_timeout_add(500,(GSourceFunc)resize_video_window,call); + g_signal_connect(video_window,"destroy",(GCallback)on_video_window_destroy,GINT_TO_POINTER(timeout)); + g_signal_connect(video_window,"key-press-event",(GCallback)on_video_window_key_press,NULL); + g_signal_connect_swapped(video_window,"motion-notify-event",(GCallback)show_video_controls,video_window); + g_signal_connect(video_window,"configure-event",(GCallback)video_window_moved,NULL); + g_signal_connect(video_window, "drag-data-received",(GCallback)drag_data_received, NULL); + g_signal_connect(video_window, "drag-drop",(GCallback)drag_drop, NULL); + g_object_set_data(G_OBJECT(video_window),"call",call); + return video_window; +} + +void linphone_gtk_in_call_show_video(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); + const LinphoneCallParams *params=linphone_call_get_current_params(call); + LinphoneCore *lc=linphone_gtk_get_core(); + + if (((bool_t)lp_config_get_int(linphone_core_get_config(lc), "video", "rtp_io", FALSE)) == FALSE) { + if (linphone_call_get_state(call)!=LinphoneCallPaused && params && linphone_call_params_video_enabled(params)){ + if (video_window==NULL){ + video_window=create_video_window(call); + g_object_set_data(G_OBJECT(callview),"video_window",video_window); + } + linphone_core_set_native_video_window_id(lc,get_native_handle(gtk_widget_get_window(video_window))); + }else{ + if (video_window){ + gtk_widget_destroy(video_window); + g_object_set_data(G_OBJECT(callview),"video_window",NULL); + } + } + } +} + +static void on_video_preview_destroyed(GtkWidget *video_preview, GtkWidget *mw){ + LinphoneCore *lc=linphone_gtk_get_core(); + guint timeout_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_preview),"timeout-id")); + g_object_set_data(G_OBJECT(mw),"video_preview",NULL); + linphone_core_enable_video_preview(lc,FALSE); + linphone_core_set_native_preview_window_id(lc,(void *)(unsigned long)-1); + g_source_remove(timeout_id); +} + +GtkWidget *linphone_gtk_get_camera_preview_window(void){ + return (GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"video_preview"); +} + +static gboolean check_preview_size(GtkWidget *video_preview){ + MSVideoSize vsize=linphone_core_get_current_preview_video_size(linphone_gtk_get_core()); + if (vsize.width && vsize.height){ + MSVideoSize cur; + gtk_window_get_size(GTK_WINDOW(video_preview),&cur.width,&cur.height); + if (cur.width!=vsize.width || cur.height!=vsize.height){ + gtk_window_resize(GTK_WINDOW(video_preview),vsize.width,vsize.height); + } + } + return TRUE; +} + +void linphone_gtk_show_camera_preview_clicked(GtkButton *button){ + GtkWidget *mw=linphone_gtk_get_main_window(); + GtkWidget *video_preview=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"video_preview"); + + if (!video_preview){ + gchar *title; + LinphoneCore *lc=linphone_gtk_get_core(); + GdkColor color; + guint tid; + + video_preview=gtk_window_new(GTK_WINDOW_TOPLEVEL); + title=g_strdup_printf("%s - Video preview",linphone_gtk_get_ui_config("title","Linphone")); + gtk_window_set_title(GTK_WINDOW(video_preview),title); + gdk_color_parse("black",&color); + gtk_widget_modify_bg(video_preview,GTK_STATE_NORMAL,&color); + g_free(title); + g_object_set_data(G_OBJECT(mw),"video_preview",video_preview); + g_signal_connect(video_preview,"destroy",(GCallback)on_video_preview_destroyed,mw); + gtk_widget_show(video_preview); + linphone_core_set_native_preview_window_id(lc,get_native_handle(gtk_widget_get_window(video_preview))); + linphone_core_enable_video_preview(lc,TRUE); + tid=g_timeout_add(100,(GSourceFunc)check_preview_size,video_preview); + g_object_set_data(G_OBJECT(video_preview),"timeout-id",GINT_TO_POINTER(tid)); + } +} + diff --git a/include/MSVC/inttypes.h b/include/MSVC/inttypes.h new file mode 100644 index 000000000..4b3828a21 --- /dev/null +++ b/include/MSVC/inttypes.h @@ -0,0 +1,305 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff --git a/include/MSVC/stdint.h b/include/MSVC/stdint.h new file mode 100644 index 000000000..d02608a59 --- /dev/null +++ b/include/MSVC/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] 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/include/sal/sal.h b/include/sal/sal.h deleted file mode 100644 index 759e36ad1..000000000 --- a/include/sal/sal.h +++ /dev/null @@ -1,493 +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. -*/ - -/** - This header files defines the Signaling Abstraction Layer. - The purpose of this layer is too allow experiment different call signaling - protocols and implementations under linphone, for example SIP, JINGLE... -**/ - -#ifndef sal_h -#define sal_h - -#include "mediastreamer2/mscommon.h" -#include "ortp/ortp_srtp.h" - -#ifdef LIBLINPHONE_EXPORTS -#define LINPHONE_PUBLIC __declspec(dllexport) -#else -#define LINPHONE_PUBLIC __declspec(dllimport) -#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 -#define PAYLOAD_TYPE_FLAG_CAN_SEND PAYLOAD_TYPE_USER_FLAG_2 -#endif -struct Sal; - -typedef struct Sal Sal; - -struct SalOp; - -typedef struct SalOp SalOp; - -struct SalAddress; - -typedef struct SalAddress SalAddress; - -struct SalCustomHeader; - -typedef struct SalCustomHeader SalCustomHeader; - -typedef enum { - SalTransportUDP, /*UDP*/ - SalTransportTCP, /*TCP*/ - SalTransportTLS, /*TLS*/ - SalTransportDTLS /*DTLS*/ -}SalTransport; - -#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 -#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 -#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 -#define SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED 0x04 -#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED | SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) - -const char* sal_transport_to_string(SalTransport transport); -SalTransport sal_transport_parse(const char*); -/* Address manipulation API*/ -SalAddress * sal_address_new(const char *uri); -SalAddress * sal_address_clone(const 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_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); -SalTransport sal_address_get_transport(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); -void sal_address_set_port(SalAddress *addr, const char *port); -void sal_address_set_port_int(SalAddress *uri, int port); -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); - - -Sal * sal_init(); -void sal_uninit(Sal* sal); -void sal_set_user_pointer(Sal *sal, void *user_data); -void *sal_get_user_pointer(const Sal *sal); - - -typedef enum { - SalAudio, - SalVideo, - SalOther -} SalStreamType; - -typedef enum{ - SalProtoUnknown, - SalProtoRtpAvp, - SalProtoRtpSavp -}SalMediaProto; - -typedef enum{ - SalStreamSendRecv, - SalStreamSendOnly, - SalStreamRecvOnly, - SalStreamInactive -}SalStreamDir; - -#define SAL_ENDPOINT_CANDIDATE_MAX 2 - -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64 -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN 32 -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN 6 - -typedef struct SalIceCandidate { - char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; - char raddr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; - char foundation[SAL_MEDIA_DESCRIPTION_MAX_ICE_FOUNDATION_LEN]; - char type[SAL_MEDIA_DESCRIPTION_MAX_ICE_TYPE_LEN]; - unsigned int componentID; - unsigned int priority; - int port; - int rport; -} SalIceCandidate; - -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10 - -typedef struct SalIceRemoteCandidate { - char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; - int port; -} SalIceRemoteCandidate; - -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES 2 - -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 - -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]; -} SalSrtpCryptoAlgo; - -#define SAL_CRYPTO_ALGO_MAX 4 - -typedef struct SalStreamDescription{ - SalMediaProto proto; - SalStreamType type; - char typeother[32]; - char rtp_addr[64]; - char rtcp_addr[64]; - int rtp_port; - int rtcp_port; - MSList *payloads; //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); - -struct SalCustomHeader{ - MSList node; - char *header_name; - char *header_value; -}; - -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); - - -/*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_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); -/*enable contact fixing*/ -void sal_nat_helper_enable(Sal *sal,bool_t enable); -bool_t sal_nat_helper_enabled(Sal *sal); -#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/.DS_Store b/java/common/org/.DS_Store deleted file mode 100644 index 2d8977d32..000000000 Binary files a/java/common/org/.DS_Store and /dev/null differ diff --git a/java/common/org/linphone/.DS_Store b/java/common/org/linphone/.DS_Store deleted file mode 100644 index f0988f202..000000000 Binary files a/java/common/org/linphone/.DS_Store and /dev/null differ diff --git a/java/common/org/linphone/core/CallDirection.java b/java/common/org/linphone/core/CallDirection.java index 142708cc2..40a5e32d9 100644 --- a/java/common/org/linphone/core/CallDirection.java +++ b/java/common/org/linphone/core/CallDirection.java @@ -18,9 +18,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * Enum representing the direction of a call. +**/ public class CallDirection { + /** + * outgoing calls* + * */ public static CallDirection Outgoing = new CallDirection("CallOutgoing"); + /** + * incoming calls + */ public static CallDirection Incoming = new CallDirection("Callincoming"); private String mStringValue; private CallDirection(String aStringValue) { diff --git a/java/common/org/linphone/core/ErrorInfo.java b/java/common/org/linphone/core/ErrorInfo.java new file mode 100644 index 000000000..348f7fd61 --- /dev/null +++ b/java/common/org/linphone/core/ErrorInfo.java @@ -0,0 +1,24 @@ +package org.linphone.core; + +public interface ErrorInfo { + /** + * Return the Reason enum corresponding to the error type. + * @return the reason. + */ + Reason getReason(); + /** + * Get the protocol code corresponding to the error (typically a SIP status code). + * @return the code. + */ + int getProtocolCode(); + /** + * Get the reason-phrase provided by the protocol (typically a SIP reason-phrase). + * @return the reason phrase. + */ + String getPhrase(); + /** + * Get details about the error, if provided by the protocol. For SIP it consists of the content of a Warning or Reason header. + * @return details about the error. + */ + String getDetails(); +} diff --git a/java/common/org/linphone/core/LinphoneAddress.java b/java/common/org/linphone/core/LinphoneAddress.java index b2a2c9380..fefb0edc0 100644 --- a/java/common/org/linphone/core/LinphoneAddress.java +++ b/java/common/org/linphone/core/LinphoneAddress.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 java.util.Vector; + /** * Object that represents a SIP address. * The LinphoneAddress is an opaque object to represents SIP addresses, ie the content of SIP's 'from' and 'to' headers. @@ -28,6 +31,38 @@ package org.linphone.core; * */ public interface LinphoneAddress { + static public class TransportType { + static private Vector values = new Vector(); + static public TransportType LinphoneTransportUdp = new TransportType(0, "LinphoneTransportUdp"); + static public TransportType LinphoneTransportTcp = new TransportType(1, "LinphoneTransportTcp"); + static public TransportType LinphoneTransportTls = new TransportType(2, "LinphoneTransportTls"); + + private final int mValue; + private final String mStringValue; + + private TransportType(int value, String stringValue) { + mValue = value; + values.addElement(this); + mStringValue = stringValue; + } + + public static TransportType fromInt(int value) { + for (int i = 0; i < values.size(); i++) { + TransportType type = (TransportType) values.elementAt(i); + if (type.mValue == value) return type; + } + throw new RuntimeException("state not found ["+value+"]"); + } + + public String toString() { + return mStringValue; + } + + public int toInt() { + return mValue; + } + } + /** * Human display name * @return null if not set @@ -39,21 +74,39 @@ public interface LinphoneAddress { */ public String getUserName(); /** - * + * Domain name * @return null if not set */ public String getDomain(); - public String getPort(); - public int getPortInt(); + /** + * Port + * @return 0 if not set + */ + public int getPort(); /** * set display name * @param name */ public void setDisplayName(String name); + /** + * set user name + * @param username + */ public void setUserName(String username); + /** + * set domain name + * @param domain + */ public void setDomain(String domain); - public void setPort(String port); - public void setPortInt(int port); + /** + * set port + * @param port, 0 if not set + */ + public void setPort(int port); + + /** + * Removes address's tags and uri headers so that it is displayable to the user. + **/ public void clean(); /** @@ -72,4 +125,16 @@ public interface LinphoneAddress { * * */ public String toString(); + + /** + * Gets the transport set in the address + * @return the transport + */ + public TransportType getTransport(); + + /** + * Sets the transport in the address + * @param transport the transport to set + */ + public void setTransport(TransportType transport); } diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index 6590dafeb..5e2744a1e 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -20,7 +20,7 @@ package org.linphone.core; /** * Object holding authentication information. * In most case, authentication information consists of a username and password. Sometimes, a userid is required by proxy, and realm can be useful to discriminate different SIP domains. - *
    This object is instanciated using {@link LinphoneCoreFactory#createAuthInfo(String, String, String)}. + *
    This object is instantiated using either {@link LinphoneCoreFactory#createAuthInfo(String, String, String)} or {@link LinphoneCoreFactory#createAuthInfo(String, String, String, String, String)}. *
    *Once created and filled, a LinphoneAuthInfo must be added to the LinphoneCore in order to become known and used automatically when needed. *Use {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)} for that purpose. @@ -63,6 +63,43 @@ public interface LinphoneAuthInfo { * @param realm */ void setRealm(String realm); + /** + * get auth userid has used in authentication header. If null, username is taken for authentication + * @return auth userid + */ + String getUserId(); + /** + * set auth userid has used in authentication header. If null, username is taken for authentication + * + */ + void setUserId(String userid); + /** + * get ha1 + * @return ha1 + */ + String getHa1(); + /** + * set ha1 + */ + 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/LinphoneBuffer.java b/java/common/org/linphone/core/LinphoneBuffer.java new file mode 100644 index 000000000..1aee74c18 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneBuffer.java @@ -0,0 +1,15 @@ +package org.linphone.core; + +/** + * The LinphoneContent object representing a data buffer. +**/ +public interface LinphoneBuffer { + + byte[] getContent(); + + void setContent(byte[] data); + + int getSize(); + + void setSize(int size); +} diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 893572e2e..cd74b6d07 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -119,6 +119,15 @@ public interface LinphoneCall { */ public static final State CallReleased = new State(18,"Released"); + /** + * The call is updated by remote while not yet answered (SIP UPDATE in early dialog received) + */ + public static final State CallEarlyUpdatedByRemote = new State(19,"EarlyUpdatedByRemote"); + + /** + * We are updating the call while not yet answered (SIP UPDATE in early dialog sent) + **/ + public static final State CallEarlyUpdating = new State(20,"EarlyUpdating"); private State(int value,String stringValue) { mValue = value; @@ -259,6 +268,16 @@ public interface LinphoneCall { void setAuthenticationTokenVerified(boolean verified); boolean isInConference(); + + /** + * Indicates whether an operation is in progress at the media side. + * It can a bad idea to initiate signaling operations (adding video, pausing the call, removing video, changing video parameters) while + * the media is busy in establishing the connection (typically ICE connectivity checks). It can result in failures generating loss of time + * in future operations in the call. + * Applications are invited to check this function after each call state change to decide whether certain operations are permitted or not. + * @return TRUE if media is busy in establishing the connection, FALSE otherwise. + **/ + boolean mediaInProgress(); float getPlayVolume(); @@ -292,4 +311,53 @@ 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(); + + Reason getReason(); + + /** + * Returns last error reported for the call. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); + + /** + * attached a user data to a call + **/ + void setUserData(Object obj); + + /** + * Returns user data from a call. return null if any + * @return an Object. + */ + Object getUserData(); + + /** + * Get a call player + * Call player enable to stream a media file through a call + * @return A player + */ + public LinphonePlayer getPlayer(); + } diff --git a/java/common/org/linphone/core/LinphoneCallLog.java b/java/common/org/linphone/core/LinphoneCallLog.java index 2e839234f..f1dd742b3 100644 --- a/java/common/org/linphone/core/LinphoneCallLog.java +++ b/java/common/org/linphone/core/LinphoneCallLog.java @@ -24,7 +24,11 @@ package org.linphone.core; import java.util.Vector; - +/** + * Object representing a call log. + * + * +**/ public interface LinphoneCallLog { /** * Represents call status @@ -91,26 +95,30 @@ public interface LinphoneCallLog { public CallDirection getDirection(); /** * get status of this call - * @return + * @return CallStatus */ public CallStatus getStatus(); /** - * @return a human readble String with the start date/time of the call + * A human readable String with the start date/time of the call + * @return String */ public String getStartDate(); /** - * @return a timestamp of the start date/time of the call in milliseconds since January 1st 1970 + * A timestamp of the start date/time of the call in milliseconds since January 1st 1970 + * @return long */ public long getTimestamp(); /** - * @return the call duration, in seconds + * The call duration, in seconds + * @return int */ public int getCallDuration(); /** - * @return the call id from signaling + * Call id from signaling + * @return int */ public int getCallId(); } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index b6d5ef33d..fa827faa2 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -76,6 +76,9 @@ public interface LinphoneCallParams { /** * Set a path to file where the call will be recorded. * Actual start of the recording is controlled by LinphoneCall.startRecording(). + * @param path Path to the file where the call will be recorded. If it is a WAV + * file, only audio will be written whereas if it is a MKV file, audio and video + * will be written. **/ void setRecordFile(String path); @@ -93,4 +96,66 @@ 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(); + + /** + * Set the session name of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * @param name the session name + **/ + void setSessionName(String name); + /** + * Get the session name of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * @return the session name + **/ + String getSessionName(); + + /** + * Gets the size of the video that is sent. + * @return The sent video size. + */ + VideoSize getSentVideoSize(); + + /** + * Gets the size of the video that is received. + * @return The received video size. + */ + VideoSize getReceivedVideoSize(); + /** + * Use to enable multicast rtp for audio stream. + * * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into audio cline. In case of outgoing call audio stream is sent to this multicast address. + *
    For incoming calls behavior is unchanged. + * @param yesno if yes, subsequent calls will propose multicast ip set by LinphoneCore.setAudioMulticastAddr + **/ + void enableAudioMulticast(boolean yesno); + + /** + * Use to get multicast state of audio stream. + * @return true if subsequent calls will propose multicast ip set by LinphoneCore.setAudioMulticastAddr + **/ + boolean audioMulticastEnabled(); + + /** + * Use to enable multicast rtp for video stream. + * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address. + *
    For incoming calls behavior is unchanged. + * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by LinphoneCore.setVideoMulticastAddr + **/ + void enableVideoMulticast(boolean yesno); + /** + * Use to get multicast state of video stream. + * @return true if subsequent calls will propose multicast ip set by LinphoneCore.setVideoMulticastAddr + **/ + boolean videoMulticastEnabled(); + } diff --git a/java/common/org/linphone/core/LinphoneCallStats.java b/java/common/org/linphone/core/LinphoneCallStats.java index f1248c445..295c99484 100644 --- a/java/common/org/linphone/core/LinphoneCallStats.java +++ b/java/common/org/linphone/core/LinphoneCallStats.java @@ -121,25 +121,25 @@ public interface LinphoneCallStats { public float getUploadBandwidth(); /** - * Get the sender loss rate since last report + * Get the local loss rate since last report * @return The sender loss rate */ public float getSenderLossRate(); /** - * Get the receiver loss rate since last report + * Get the remote reported loss rate since last report * @return The receiver loss rate */ public float getReceiverLossRate(); /** - * Get the sender interarrival jitter + * Get the local interarrival jitter * @return The interarrival jitter at last emitted sender report */ public float getSenderInterarrivalJitter(); /** - * Get the receiver interarrival jitter + * Get the remote reported interarrival jitter * @return The interarrival jitter at last received receiver report */ public float getReceiverInterarrivalJitter(); @@ -161,4 +161,16 @@ public interface LinphoneCallStats { * @return The jitter buffer size in milliseconds */ public float getJitterBufferSize(); + + /** + * Get the local loss rate. Unlike getSenderLossRate() that returns this loss rate "since last emitted RTCP report", the value returned here is updated every second. + * @return The local loss rate percentage. + **/ + public float getLocalLossRate(); + + /** + * Get the local late packets rate. The value returned here is updated every second. + * @return The local late rate percentage. + **/ + public float getLocalLateRate(); } diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 3a2a45718..b80c3a070 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -4,9 +4,38 @@ import java.util.Vector; public interface LinphoneChatMessage { - interface StateListener{ + @Deprecated + interface StateListener { void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); } + + interface LinphoneChatMessageListener { + void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); + + /** + * This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file. + * @param content incoming content information + * @param buffer holding the received data. Empty buffer means end of file. + */ + void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer); + + /** + * This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0. + * @param content incoming content information + * @param offset the offset in the file from where to get the data to be sent + * @param size the number of bytes expected by the framework + * @param bufferToFill A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file. + */ + void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill); + + /** + * File transfer progress indication callback prototype. + * @param content incoming content information + * @param offset The number of bytes sent/received since the beginning of the transfer. + * @param total The total number of bytes to be sent/received. + */ + void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total); + } public static class State { static private Vector values = new Vector(); private final int mValue; @@ -14,21 +43,29 @@ public interface LinphoneChatMessage { private final String mStringValue; /** - * Idle + * Initial state */ public final static State Idle = new State(0,"Idle"); /** - * Incoming call received. + * Delivery in progress */ public final static State InProgress = new State(1,"InProgress"); /** - * Outgoing call initialiazed. + * Message succesffully delivered an acknoleged by remote end point */ public final static State Delivered = new State(2,"Delivered"); /** - * Outgoing call in progress. + * Message was not delivered */ public final static State NotDelivered = new State(3,"NotDelivered"); + /** + * Message was received(and acknowledged) but cannot get file from server + */ + public final static State FileTransferError = new State(4,"FileTransferError"); + /** + * File transfer has been completed successfully. + */ + public final static State FileTransferDone = new State(5,"FileTransferDone"); private State(int value,String stringValue) { mValue = value; @@ -52,11 +89,6 @@ public interface LinphoneChatMessage { } } - long getNativePtr(); - - Object getUserData(); - - void setUserData(); /** * get text associated to this LinphoneChatMessage @@ -79,6 +111,12 @@ public interface LinphoneChatMessage { */ LinphoneAddress getFrom(); + /** + * Get destination address of the LinphoneChatMessage. + * @return the LinphoneAddress in the To field of the message. + */ + LinphoneAddress getTo(); + /** * Linphone message can carry external body as defined by rfc2017 * @param message #LinphoneChatMessage @@ -106,4 +144,87 @@ public interface LinphoneChatMessage { * @return the value of the header, or null if not found. */ String getCustomHeader(String name); + + /** + * Gets the time at which the message was sent + * @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(); + + /** + * @return the reason if response received + */ + Reason getReason(); + + /** + * Returns full error in case of failure when sending message. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); + + /** + * Cancel an ongoing file transfer attached to this message.(upload or download). + */ + void cancelFileTransfer(); + /** + * Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer) + * @return a pointer to the LinphoneContent structure or NULL if not present. + */ + LinphoneContent getFileTransferInformation(); + + /** + * Sets data in the chat message + * @param data to store in the message + */ + void setAppData(String data); + + /** + * @return the data stored in the chat message if any, else null + */ + String getAppData(); + + /** + * Set the path to the file to read from or write to during the file transfer. + * @param path The path to the file to use for the file transfer. + */ + void setFileTransferFilepath(String path); + + /** + * Start the download of the file referenced in a LinphoneChatMessage from remote server. + */ + void downloadFile(); + + /** + * Set the callbacks associated with the LinphoneChatMessage. + */ + void setListener(LinphoneChatMessage.LinphoneChatMessageListener listener); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index d6512f170..f281b4bb6 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -17,9 +17,12 @@ 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. + * + * A chat room is the place where text messages are exchanged. Can be created by linphone_core_create_chat_room(). * */ @@ -30,17 +33,20 @@ public interface LinphoneChatRoom { * @return LinphoneAddress peer address */ LinphoneAddress getPeerAddress(); + /** * send a message to peer member of this chat room. * @param message to be sent */ void sendMessage(String message); + /** * Send a message to peer member of this chat room. * @param chat message */ + @Deprecated void sendMessage(LinphoneChatMessage message, LinphoneChatMessage.StateListener listener); - + /** * Create a LinphoneChatMessage * @param chatRoom chat room associated to the message @@ -48,4 +54,94 @@ 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); + + /** + * Returns the chat history associated with the peer address associated with this chat room for the given range, sorted from oldest to most recent + * @param begin the first (most recent) message to retrieve. Newest message has index 0. If negative, use value 0 instead. + * @param end the last (oldest) message to retrieve. Oldest message has value "history size" - 1 (equivalent to -1). If negative or lower than begin value, value is given, use -1. + * @return an array of LinphoneChatMessage, empty if nothing has been found + */ + LinphoneChatMessage[] getHistoryRange(int begin, int end); + + /** + * 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(); + + /** + * Returns the amount of messages associated with the peer of this chatRoom. + * @return the amount of messages in the conversation + */ + int getHistorySize(); + + /** + * Deletes all the messages associated with the peer of this chat room + */ + void deleteHistory(); + + /** + * Notify the destination of the chat message being composed that the user is typing a new message. + */ + void compose(); + + /** + * Tells whether the remote is currently composing a message. + * @return true if the remote is currently composing a message, false otherwise. + */ + boolean isRemoteComposing(); + + /** + * Marks all the messages in this conversation as read + */ + void markAsRead(); + + /** + * Deletes a message + * @param message the message to delete + */ + void deleteMessage(LinphoneChatMessage message); + + /** + * Create a LinphoneChatMessage + * @return LinphoneChatMessage object + */ + LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming); + + /** + * Returns a back pointer to the core managing the chat room. + * @return the LinphoneCore + */ + LinphoneCore getCore(); + + /** + * Create a message attached to a dedicated chat room with a particular content. + * @param content LinphoneContent initial content. + * @return a new LinphoneChatMessage + */ + LinphoneChatMessage createFileTransferMessage(LinphoneContent content); + + /** + * + * @param message + */ + void sendChatMessage(LinphoneChatMessage message); } diff --git a/java/common/org/linphone/core/LinphoneContent.java b/java/common/org/linphone/core/LinphoneContent.java new file mode 100644 index 000000000..eb41c62f7 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneContent.java @@ -0,0 +1,77 @@ +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 expected data size. + * @return the expected data size + */ + int getExpectedSize(); + + /** + * Sets the expected data size + */ + void setExpectedSize(int size); + + /** + * Return the size of the data field + * @return the size of the data field + */ + int getRealSize(); + + /** + * 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[]); + + void setName(String name); + + String getName(); +} diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index ab25520a4..e668520f9 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -20,8 +20,14 @@ package org.linphone.core; import java.util.Vector; +import org.linphone.core.LinphoneCoreListener; +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)}. + * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}. * */ @@ -30,12 +36,12 @@ public interface LinphoneCore { * linphone core states */ static public class GlobalState { - + static private Vector values = new Vector(); /** * Off */ - static public GlobalState GlobalOff = new GlobalState(0,"GlobalOff"); + static public GlobalState GlobalOff = new GlobalState(0,"GlobalOff"); /** * Startup */ @@ -48,11 +54,15 @@ public interface LinphoneCore { * Shutdown */ static public GlobalState GlobalShutdown = new GlobalState(3,"GlobalShutdown"); + /** + * Configuring + */ + static public GlobalState GlobalConfiguring = new GlobalState(4,"GlobalConfiguring"); private final int mValue; private final String mStringValue; - + private GlobalState(int value,String stringValue) { mValue = value; values.addElement(this); @@ -70,17 +80,57 @@ public interface LinphoneCore { return mStringValue; } } + /** + * linphone remote provisioning states + */ + static public class RemoteProvisioningState { + + static private Vector values = new Vector(); + /** + * Off + */ + static public RemoteProvisioningState ConfiguringSuccessful = new RemoteProvisioningState(0,"ConfiguringSuccessful"); + /** + * Startup + */ + static public RemoteProvisioningState ConfiguringFailed = new RemoteProvisioningState(1,"ConfiguringFailed"); + /** + * On + */ + static public RemoteProvisioningState ConfiguringSkipped = new RemoteProvisioningState(2,"ConfiguringSkipped"); + + private final int mValue; + private final String mStringValue; + + + private RemoteProvisioningState(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static RemoteProvisioningState fromInt(int value) { + + for (int i=0; i values = new Vector(); /** * None */ - public static RegistrationState RegistrationNone = new RegistrationState(0,"RegistrationNone"); + public static RegistrationState RegistrationNone = new RegistrationState(0,"RegistrationNone"); /** * In Progress */ @@ -100,7 +150,7 @@ public interface LinphoneCore { private final int mValue; private final String mStringValue; - + private RegistrationState(int value,String stringValue) { mValue = value; values.addElement(this); @@ -123,12 +173,12 @@ public interface LinphoneCore { * */ static public class FirewallPolicy { - + static private Vector values = new Vector(); /** * No firewall is assumed. */ - static public FirewallPolicy NoFirewall = new FirewallPolicy(0,"NoFirewall"); + static public FirewallPolicy NoFirewall = new FirewallPolicy(0,"NoFirewall"); /** * Use NAT address (discouraged) */ @@ -145,11 +195,11 @@ public interface LinphoneCore { * Use uPnP. */ static public FirewallPolicy UseUpnp = new FirewallPolicy(4,"UseUpnp"); - + private final int mValue; private final String mStringValue; - + private FirewallPolicy(int value,String stringValue) { mValue = value; values.addElement(this); @@ -170,15 +220,26 @@ public interface LinphoneCore { return mValue; } } - + /** - * Signaling transports ports. + * Linphone core SIP transport ports. + * Use with {@link LinphoneCore#setSignalingTransportPorts(Transports)} + * @ingroup initializing */ static public class Transports { + /** + * udp port to listening on, negative value if not set + * */ public int udp; + /** + * tcp port to listening on, negative value if not set + * */ public int tcp; + /** + * tls port to listening on, negative value if not set + * */ public int tls; - + public Transports() {}; public Transports(Transports t) { this.udp = t.udp; @@ -194,12 +255,12 @@ public interface LinphoneCore { * */ static public final class MediaEncryption { - + static private Vector values = new Vector(); /** * None */ - static public final MediaEncryption None = new MediaEncryption(0,"None"); + static public final MediaEncryption None = new MediaEncryption(0,"None"); /** * SRTP */ @@ -208,10 +269,14 @@ public interface LinphoneCore { * ZRTP */ static public final MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP"); + /** + * DTLS + */ + static public final MediaEncryption DTLS = new MediaEncryption(3,"DTLS"); protected final int mValue; private final String mStringValue; - + private MediaEncryption(int value,String stringValue) { mValue = value; values.addElement(this); @@ -229,11 +294,43 @@ public interface LinphoneCore { return mStringValue; } } + static public final class AdaptiveRateAlgorithm { + + static private Vector values = new Vector(); + /** + * Simple + */ + static public final AdaptiveRateAlgorithm Simple = new AdaptiveRateAlgorithm(0,"Simple"); + /** + * Stateful + */ + static public final AdaptiveRateAlgorithm Stateful = new AdaptiveRateAlgorithm(1,"Stateful"); + protected final int mValue; + private final String mStringValue; + + + private AdaptiveRateAlgorithm(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static AdaptiveRateAlgorithm fromString(String value) { + + for (int i=0; i values = new Vector(); /* Do not change the values of these constants or the strings associated with them to prevent breaking the collection of echo canceller calibration results during the wizard! */ @@ -261,7 +358,7 @@ public interface LinphoneCore { private final int mValue; private final String mStringValue; - + private EcCalibratorStatus(int value,String stringValue) { mValue = value; values.addElement(this); @@ -282,11 +379,11 @@ public interface LinphoneCore { return mValue; } } - + static public class UpnpState { static private Vector values = new Vector(); /** - * Idle + * Idle */ static public UpnpState Idle = new UpnpState(0, "Idle"); /** @@ -310,9 +407,14 @@ public interface LinphoneCore { */ static public UpnpState Ok = new UpnpState(5, "Ok"); /** - * Ko + * 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; @@ -332,6 +434,45 @@ public interface LinphoneCore { return mStringValue; } } + /** + * linphone log collection upload states + */ + static public class LogCollectionUploadState { + + static private Vector values = new Vector(); + /** + * Delivery in progress + */ + static public LogCollectionUploadState LogCollectionUploadStateInProgress = new LogCollectionUploadState(0,"LinphoneCoreLogCollectionUploadStateInProgress"); + /** + * Log collection upload successfully delivered and acknowledged by remote end point + */ + static public LogCollectionUploadState LogCollectionUploadStateDelivered = new LogCollectionUploadState(1,"LinphoneCoreLogCollectionUploadStateDelivered"); + /** + * Log collection upload was not delivered + */ + static public LogCollectionUploadState LogCollectionUploadStateNotDelivered = new LogCollectionUploadState(2,"LinphoneCoreLogCollectionUploadStateNotDelivered"); + + private final int mValue; + private final String mStringValue; + + private LogCollectionUploadState(int value, String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static LogCollectionUploadState fromInt(int value) { + + for (int i=0; i - * This default proxy must be part of the list of already entered {@link LinphoneProxyConfig}. - * Toggling it as default will make LinphoneCore use the identity associated with the proxy configuration in all incoming and outgoing calls. - * @param proxyCfg + * This default proxy must be part of the list of already entered {@link LinphoneProxyConfig}. + * Toggling it as default will make LinphoneCore favor the identity associated with the proxy configuration in all incoming and outgoing calls. + * Better proxy configuration match may override this choice. Pass null to unset the default proxy. + * @param proxyCfg */ public void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg); - + /** * get he default proxy configuration, that is the one used to determine the current identity. - * @return null if no default proxy config + * @return null if no default proxy config */ 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 */ @@ -373,7 +537,7 @@ public interface LinphoneCore { * @param info */ void addAuthInfo(LinphoneAuthInfo info); - + /** * Build an address according to the current proxy config. In case destination is not a sip address, the default proxy domain is automatically appended * @param destination @@ -381,7 +545,7 @@ public interface LinphoneCore { * @throws If no LinphoneAddress can be built from destination */ public LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException; - + /** * Starts a call given a destination. Internally calls {@link #interpretUrl(String)} then {@link #invite(LinphoneAddress)}. * @param uri @@ -389,10 +553,10 @@ public interface LinphoneCore { public LinphoneCall invite(String destination)throws LinphoneCoreException; /** * Initiates an outgoing call given a destination LinphoneAddress - *
    The LinphoneAddress can be constructed directly using linphone_address_new(), or created by linphone_core_interpret_url(). The application doesn't own a reference to the returned LinphoneCall object. Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + *
    The LinphoneAddress can be constructed directly using {@link LinphoneCoreFactory#createLinphoneAddress} , or created {@link LinphoneCore#interpretUrl(String)}. . * @param to the destination of the call (sip address). - * @return LinphoneCall - * @throws LinphoneCoreException + * @return linphone call + * @throws LinphoneCoreException if linphone call cannot be created */ public LinphoneCall invite(LinphoneAddress to)throws LinphoneCoreException; /** @@ -402,26 +566,28 @@ public interface LinphoneCore { public void terminateCall(LinphoneCall aCall); /** * Declines an incoming call, providing a reason for declining it. + * @param call the LinphoneCall, must be in the {@link LinphoneCall.State#IncomingReceived} state. + * @param reason the reason for rejecting the call: {@link Reason#Declined} or {@link Reason#Busy} */ public void declineCall(LinphoneCall aCall, Reason reason); /** * Returns The LinphoneCall the current call if one is in call * **/ - public LinphoneCall getCurrentCall(); - + public LinphoneCall getCurrentCall(); + /** * get current call remote address in case of in/out call * @return null if no call engaged yet */ public LinphoneAddress getRemoteAddress(); /** - * - * @return TRUE if there is a call running or pending. + * + * @return true if there is a call running or pending. */ public boolean isIncall(); /** - * + * * @return Returns true if in incoming call is pending, ie waiting for being answered or declined. */ public boolean isInComingInvitePending(); @@ -432,7 +598,7 @@ public interface LinphoneCore { *
  • receiving of SIP messages *
  • handles timers and timeout *
  • performs registration to proxies - *
  • authentication retries The application MUST call this function from periodically, in its main loop. + *
  • authentication retries The application MUST call this function from periodically, in its main loop. *
    Be careful that this function must be call from the same thread as other liblinphone methods. In not the case make sure all liblinphone calls are serialized with a mutex. */ @@ -444,10 +610,10 @@ public interface LinphoneCore { * {@link LinphoneCoreListener#callState} listener method. * The application can later respond positively to the call using * this method. - * @throws LinphoneCoreException + * @throws LinphoneCoreException */ public void acceptCall(LinphoneCall aCall) throws LinphoneCoreException; - + /** * Accept an incoming call. * @@ -455,10 +621,10 @@ public interface LinphoneCore { * {@link LinphoneCoreListener#callState} listener method. * The application can later respond positively to the call using * this method. - * @throws LinphoneCoreException + * @throws LinphoneCoreException */ public void acceptCallWithParams(LinphoneCall aCall, LinphoneCallParams params) throws LinphoneCoreException; - + /** * Accept call modifications initiated by other end. * @@ -466,11 +632,11 @@ public interface LinphoneCore { * {@link LinphoneCoreListener#callState} listener method. * The application can later respond positively to the call using * this method. - * @throws LinphoneCoreException + * @throws LinphoneCoreException */ public void acceptCallUpdate(LinphoneCall aCall, LinphoneCallParams params) throws LinphoneCoreException; - - + + /** * Prevent LinphoneCore from performing an automatic answer * @@ -478,28 +644,26 @@ public interface LinphoneCore { * {@link LinphoneCoreListener#callState} listener method. * The application can later respond positively to the call using * this method. - * @throws LinphoneCoreException + * @throws LinphoneCoreException */ public void deferCallUpdate(LinphoneCall aCall) throws LinphoneCoreException; - public void startRinging(); - /** - * @return a list of LinphoneCallLog + * @return a list of LinphoneCallLog */ public LinphoneCallLog[] getCallLogs(); - + /** * This method is called by the application to notify the Linphone core library when network is reachable. * Calling this method with true trigger Linphone to initiate a registration process for all proxy * configuration with parameter register set to enable. * This method disable the automatic registration mode. It means you must call this method after each network state changes - * @param network state + * @param network state * */ public void setNetworkReachable(boolean isReachable); /** - * + * Get network state has known by {@link LinphoneCore} * @return if false, there is no network connection. */ public boolean isNetworkReachable(); @@ -508,12 +672,12 @@ public interface LinphoneCore { */ public void destroy(); /** - * Allow to control play level before entering sound card: + * Allow to control play level before entering sound card: * @param level in db */ public void setPlaybackGain(float gain); /** - * get play level before entering sound card: + * get play level before entering sound card: * @return level in db */ public float getPlaybackGain(); @@ -534,58 +698,149 @@ public interface LinphoneCore { */ void muteMic(boolean isMuted); /** - * + * * @return true is mic is muted */ boolean isMicMuted(); /** * Initiate a dtmf signal if in call - * @param number + * @param send dtmf ['0'..'9'] | '#', '*' */ void sendDtmf(char number); /** * Initiate a dtmf signal to the speaker if not in call. * Sending of the DTMF is done in another function. - * @param number + * @param dtmf ['0'..'9'] | '#', '*' * @param duration in ms , -1 for unlimited */ - void playDtmf(char number,int duration); + void playDtmf(char dtmf,int duration); /** * stop current dtmf */ void stopDtmf(); - + /** * remove all call logs */ void clearCallLogs(); - /*** - * get payload type from mime type, clock rate, and number of channels.- - * - * return null if not found + + + + + /** + * Get payload type from mime type and clock rate + * + * This function searches in audio and video codecs for the given payload type name and clockrate. + * @param mime payload mime type (I.E SPEEX, PCMU, VP8) + * @param clockRate (I.E 8000, 16000, 90000, ...) + * @param channels number of channels + * @return Returns null if not found. */ - PayloadType findPayloadType(String mime, int clockRate, int channels); + PayloadType findPayloadType(String mime, int clockRate, int channels); /*** * get payload type from mime type and clock rate.. - * - * return null if not found + * Same as @{link {@link #findPayloadType(String, int, int)} but ignoring channels params + * @param mime payload mime type (I.E SPEEX, PCMU, VP8) + * @param clockRate (I.E 8000, 16000, 90000, ...) + * @return null if not found */ - PayloadType findPayloadType(String mime, int clockRate); + PayloadType findPayloadType(String mime, int clockRate); + + /*** + * get payload type from mime type + * Same as @{link {@link #findPayloadType(String, int, int)} but ignoring channels and clock rate params + * @param mime payload mime type (I.E SPEEX, PCMU, VP8) + * @return null if not found + */ + PayloadType findPayloadType(String mime); + /** - * not implemented yet - * @param pt - * @param enable - * @throws LinphoneCoreException + * Enable payload type + * @param pt payload type to enable, can be retrieve from {@link #findPayloadType} + * @param true if enabled + * @exception LinphoneCoreException + * */ void enablePayloadType(PayloadType pt, boolean enable) throws LinphoneCoreException; + + /** + * @param pt the payload type + * @return whether or not the payload is enabled in linphonecore. + */ + boolean isPayloadTypeEnabled(PayloadType pt); + + /** + * @param pt the payload type + * @return whether or not the payload epresents a VBR codec + */ + boolean payloadTypeIsVbr(PayloadType pt); + + /** + * Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s. + * @param pt the payload type + * @param bitrate target IP bitrate in kbit/s + */ + void setPayloadTypeBitrate(PayloadType pt, int bitrate); + + /** + * Get target bitrate previously set by setPayloadTypeBitrate(). + * @param pt + * @return IP bitrate in kbit/s + */ + int getPayloadTypeBitrate(PayloadType pt); + + /** + * Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s. + * @param pt the payload type + * @param number target IP bitrate in kbit/s + */ + + /** + * Force a number for a payload type. The LinphoneCore does payload type number assignment automatically. THis function is to be used mainly for tests, in order + * to override the automatic assignment mechanism. + * @param pt the payload type + * @param number + **/ + void setPayloadTypeNumber(PayloadType pt, int number); + + /** + * @param pt the payload type + * @return the payload type number assigned for this codec. + */ + int getPayloadTypeNumber(PayloadType pt); + + /** + * Enable adaptive rate control. + * @param enable + */ + void enableAdaptiveRateControl(boolean enable); + + /** + * Enables or disable adaptive rate control. + * @return true if adaptive rate control is enabled. + */ + boolean isAdaptiveRateControlEnabled(); + + /** + * Sets adaptive rate algorithm. It will be used for each new calls + * starting from now. Calls already started will not be updated. + */ + void setAdaptiveRateAlgorithm(AdaptiveRateAlgorithm alg); + + /** + * Returns which adaptive rate algorithm is currently configured for + * future calls. + */ + AdaptiveRateAlgorithm getAdaptiveRateAlgorithm(); + /** * Enables or disable echo cancellation. * @param enable */ void enableEchoCancellation(boolean enable); /** - * get EC status + * get EC status * @return true if echo cancellation is enabled. */ boolean isEchoCancellationEnabled(); @@ -595,13 +850,28 @@ public interface LinphoneCore { */ boolean isEchoLimiterEnabled(); /** - * @param transports used for signaling (TCP, UDP and TLS) + * Set transport ports linphone core will listen on + * @param local transports ports used for signaling (TCP, UDP and TLS) */ void setSignalingTransportPorts(Transports transports); - /** + /**Get * @return transports used for signaling (TCP, UDP, TLS) */ Transports getSignalingTransportPorts(); + + /** + * Assign a dscp value for the SIP socket. + * DSCP is an IP packet field used to indicate the type of routing service to routers. + * @param dscp + */ + void setSipDscp(int dscp); + + /** + * Get DSCP used for SIP socket. + * @return the DSCP value used for the SIP socket. + */ + int getSipDscp(); + /** * Activates or deactivates the speaker. * @param value @@ -620,30 +890,85 @@ 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 + * Get list of LinphoneFriend + * @return LinphoneFriend list */ - void setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status); + LinphoneFriend[] getFriendList(); + + /** + * @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 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 + * @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} + * @param video window of type {@link AndroidVideoWindowImpl} + **/ void setVideoWindow(Object w); + /** + * Set the native video window id where the video preview is to be displayed. + * On Android, it must of type {@link SurfaceView} + * @param video window of type {@link SurfaceView} + **/ void setPreviewWindow(Object w); + /** + * Tells the core the device current orientation. This can be used by capture filters + * on mobile devices to select between portrait/landscape mode and to produce properly + * oriented images. The exact meaning of the value in rotation if left to each device + * specific implementations. + *@param rotation . Android supported values are 0, 90, 180 and 270. + * + **/ void setDeviceRotation(int rotation); - + /** + * Sets the active video device. + * + * @param id of the video device as returned by {@link AndroidCameraConfiguration#retrieveCameras} + **/ void setVideoDevice(int id); + /** + * Returns the id of the currently active video device as found in {@link AndroidCameraConfiguration#retrieveCameras}. + **/ int getVideoDevice(); - + + + /** + * Teturns true if the underlying sdk support video + * + * */ + boolean isVideoSupported(); + /** * 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. @@ -655,20 +980,21 @@ public interface LinphoneCore { void enableVideo(boolean vcap_enabled, boolean display_enabled); /** * Returns TRUE if video is enabled, FALSE otherwise. - * + * ***/ boolean isVideoEnabled(); - + /** * Specify a STUN server to help firewall traversal. * @param stun_server Stun server address and port, such as stun.linphone.org or stun.linphone.org:3478 */ void setStunServer(String stun_server); /** + * Get STUN server * @return stun server address if previously set. */ String getStunServer(); - + /** * Sets policy regarding workarounding NATs * @param pol one of the FirewallPolicy members. @@ -678,11 +1004,35 @@ public interface LinphoneCore { * @return previously set firewall policy. */ FirewallPolicy getFirewallPolicy(); - + /** + * Initiates an outgoing call given a destination LinphoneAddress + * + * @param addr the destination of the call {@link #LinphoneAddress }. + * @param params call parameters {@link #LinphoneCallParams } + * + *
    The LinphoneAddress can be constructed directly using {@link LinphoneCoreFactory#createLinphoneAddress} , or created {@link LinphoneCore#interpretUrl(String)}. . + * + * @return a {@link #LinphoneCall LinphoneCall} object + * @throws LinphoneCoreException in case of failure + **/ LinphoneCall inviteAddressWithParams(LinphoneAddress destination, LinphoneCallParams params) throws LinphoneCoreException ; - + /** + * Updates a running call according to supplied call parameters or parameters changed in the LinphoneCore. + * + * In this version this is limited to the following use cases: + * - setting up/down the video stream according to the video parameter of the {@link LinphoneCallParams} (see {@link LinphoneCallParams#enableVideo} ). + * - changing the size of the transmitted video after calling {@link LinphoneCore#setPreferredVideoSize(VideoSize)} + * + * In case no changes are requested through the {@link LinphoneCallParams} argument, then this argument can be omitted and set to null. + * @param call the {@link LinphoneCall} to be updated + * @param params the new {@link LinphoneCallParams call parameters} to use. (may be NULL) + * @return 0 if successful, -1 otherwise. + **/ int updateCall(LinphoneCall call, LinphoneCallParams params); - + /** + * Get default call parameters reflecting current linphone core configuration + * @return LinphoneCallParams + */ LinphoneCallParams createDefaultCallParameters(); /** @@ -694,47 +1044,121 @@ public interface LinphoneCore { /** * gets the path to a wav file used for ringing. * - * @param null if not set + * @return null if not set */ String getRing(); - + /** * Sets file or folder containing trusted root CAs * * @param path path to file with multiple PEM certif or to folder with multiple PEM files - */ + */ void setRootCA(String path); - + + /** + * Sets the path to a wav file used for for ringing back. + * + * Ringback means the ring that is heard when it's ringing at the remote party. + * + * @param path The file must be a wav 16bit linear. + */ + void setRingback(String path); + + /** + * Retrieve the maximum available upload bandwidth. + **/ + int getUploadBandwidth(); + void setUploadBandwidth(int bw); + /** + * Retrieve the maximum available download bandwidth. + **/ + int getDownloadBandwidth(); + + /** + * Sets maximum available download bandwidth + * + * + * 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. + * + * @param bw the bandwidth in kbits/s, 0 for infinite + */ void setDownloadBandwidth(int bw); - + /** * Sets audio packetization interval suggested for remote end. * @param ptime packetization interval in milliseconds */ void setDownloadPtime(int ptime); - + /** * Sets audio packetization interval sent to remote end. * @param ptime packetization interval in milliseconds */ void setUploadPtime(int ptime); - + /** + * Sets the preferred video size. + * + * 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 vSize + * + **/ 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 + * + **/ VideoSize getPreferredVideoSize(); + + /** + * Set the preferred frame rate for video. + * Based on the available bandwidth constraints and network conditions, the video encoder + * remains free to lower the framerate. There is no warranty that the preferred frame rate be the actual framerate. + * used during a call. Default value is 0, which means "use encoder's default fps value". + * @param fps the target frame rate in number of frames per seconds. + **/ + void setPreferredFramerate(float fps); + /** + * Returns the preferred video framerate, previously set by setPreferredFramerate(). + * @return frame rate in number of frames per seconds. + **/ + float getPreferredFramerate(); /** * Returns the currently supported audio codecs, as PayloadType elements * @return */ PayloadType[] getAudioCodecs(); + /** + * Set the list of audio codecs. + * @param codecs List of PayloadType objects + */ + void setAudioCodecs(PayloadType[] codecs); /** * Returns the currently supported video codecs, as PayloadType elements * @return */ PayloadType[] getVideoCodecs(); + /** + * Set the list of video codecs. + * @param codecs List of PayloadType objects + */ + void setVideoCodecs(PayloadType[] codecs); /** * enable signaling keep alive. small udp packet sent periodically to keep udp NAT association */ @@ -747,10 +1171,10 @@ public interface LinphoneCore { /** * Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceler automatically. * status is notified to {@link LinphoneCoreListener#ecCalibrationStatus(EcCalibratorStatus, int, Object)} - * @param User object + * @param listener the LinphoneEchoCalibrationListener to call when the calibration is done * @throws LinphoneCoreException if operation is still in progress; **/ - void startEchoCalibration(Object data) throws LinphoneCoreException; + void startEchoCalibration(LinphoneCoreListener listener) throws LinphoneCoreException; /** * Returns true if echo calibration is recommended. @@ -758,23 +1182,37 @@ public interface LinphoneCore { */ boolean needsEchoCalibration(); + /** + * Returns true if the software echo canceler needs to be turned on. + * If the device has a builtin echo canceller, it will return false. + */ + boolean hasBuiltInEchoCanceler(); + void enableIpv6(boolean enable); + + boolean isIpv6Enabled(); + /** * @deprecated * @param i */ void adjustSoftwareVolume(int i); - + /** - * Pause a call. + * Pauses a call. If a music file has been setup using {@link LinphoneCore#setPlayFile(String)}, + * this file will be played to the remote user. + * **/ boolean pauseCall(LinphoneCall call); /** * Resume a call. **/ boolean resumeCall(LinphoneCall call); + /** + * Pause all currently running calls. + **/ boolean pauseAllCalls(); - + void setZrtpSecretsCache(String file); void enableEchoLimiter(boolean val); @@ -783,56 +1221,146 @@ public interface LinphoneCore { **/ boolean isInConference(); /** - * Connect the local user to the conference. + * Moves the local participant inside the conference. + * + * Makes the local participant to join the conference. + * Typically, the local participant is by default always part of the conference when joining an active call into a conference. + * However, by calling {@link #leaveConference()} and {@link #enterConference()} the application can decide to temporarily + * move out and in the local participant from the conference. + * + * @returns true if successful **/ boolean enterConference(); /** - * Disconnect the local user from the conference. + * Moves the local participant out of the conference. + * When the local participant is out of the conference, the remote participants can continue to talk normally. **/ void leaveConference(); /** - * Add an established call to the conference. The LinphoneCore is able to manage one client based conference. + * Merge a call into a conference. + * + * If this is the first call that enters the conference, the virtual conference will be created automatically. + * If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference. + * If the call was in paused state, then it is automatically resumed when entering into the conference. + * @param call an established call, either in {@link LinphoneCall.State#StreamsRunning} or {@link LinphoneCall.State#Paused} state. + * **/ void addToConference(LinphoneCall call); /** - * Remove an established call from the conference. - **/ + * Remove a call from the conference. + * @param call a call that has been previously merged into the conference. + * + * After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state. + * If one single remote participant is left alone together with the local user in the conference after the removal, then the conference is + * automatically transformed into a simple call in StreamsRunning state. + * The conference's resources are then automatically destroyed. + * + * In other words, unless {@link #leaveConference()} is explicitely called, the last remote participant of a conference is automatically + * put in a simple call in running state. + * + **/ void removeFromConference(LinphoneCall call); - void addAllToConference(); - /** - * Terminate the conference, all users are disconnected. + * Add all calls into a conference. + * + * Merge all established calls (either in {@link LinphoneCall.State#StreamsRunning} or {@link LinphoneCall.State#Paused}) into a conference. + * + **/ + void addAllToConference(); + + /** + * Terminates the conference and the calls associated with it. + * + * All the calls that were merged to the conference are terminated, and the conference resources are destroyed. + * **/ void terminateConference(); + /** + * Returns the number of participants to the conference, including the local participant. + * + * Typically, after merging two calls into the conference, there is total of 3 participants: + * the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls. + * + * @returns the number of participants to the conference + **/ int getConferenceSize(); /** * Request recording of the conference into a supplied file path. * The format is wav. + * @param path where to write recording file **/ void startConferenceRecording(String path); - + /** * Stop recording of the conference. **/ void stopConferenceRecording(); - + /** + * Terminates all the calls. + */ void terminateAllCalls(); /** * Returns all calls. + * @return an array with all call currently handle by Linphone core **/ LinphoneCall[] getCalls(); + /** + * Get number of calls currently handled by Linphone core + * @returns number of calls + * */ int getCallsNb(); - + /** + * Performs a simple call transfer to the specified destination. + * + * @param call The current local call remains active and thus can be later paused or terminated. + * @param referTo The remote call party endpoint is expected to issue a new call to this specified destination. + **/ void transferCall(LinphoneCall call, String referTo); + /** + * Transfer a call to destination of another running call. This is used for "attended transfer" scenarios. + * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. + * The destination call is a call previously established to introduce the transfered person. + * 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). + * @param call a running call you want to transfer + * @param dest a running call whose remote person will receive the transfer + **/ void transferCallToAnother(LinphoneCall callToTransfer, LinphoneCall destination); + /** + * Start a new call as a consequence of a transfer request received from a call. + * This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application + * wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification. + * @param call a call that has just been notified about LinphoneCallRefered state event. + * @param params the call parameters to be applied to the new call. + * @return a LinphoneCall corresponding to the new call that is attempted to the transfer destination. + **/ + LinphoneCall startReferedCall(LinphoneCall call, LinphoneCallParams params); + /** + * Search from the list of current calls if a remote address match uri + * @param uri which should match call remote uri + * @return LinphoneCall or NULL is no match is found + */ LinphoneCall findCallFromUri(String uri); - + /** + * Get 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 + * @return max number of simultaneous calls + */ int getMaxCalls(); + /** + * 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 + * @param max number of simultaneous calls + */ void setMaxCalls(int max); + /** + * @deprecated + * @param uri + * @return + */ boolean isMyself(String uri); /** @@ -840,7 +1368,7 @@ public interface LinphoneCore { * which could result in an active call. * Eg: don't start a new call if one is in outgoing ringing. * Eg: don't merge to conference either as it could result - * in two active calls (conference and accepted call). + * in two active calls (conference and accepted call). * @return */ boolean soundResourcesLocked(); @@ -871,9 +1399,84 @@ public interface LinphoneCore { * @param path path to music file played to remote side when on hold. */ void setPlayFile(String path); + + + enum TunnelMode { + disable(0), + enable(1), + auto(2); + private final int value; + + private TunnelMode(int value){ + this.value = value; + } + public static int enumToInt(TunnelMode enum_mode) { + return enum_mode.value; + } + public static TunnelMode intToEnum(int value) { + switch(value) { + case 0: return disable; + case 1: return enable; + case 2: return auto; + default: return disable; + } + } + } + + /** + * @deprecated Use tunnelSetMode() instead + * Enable or disable tunnel + * @param enable True to enable and false to disable + */ void tunnelEnable(boolean enable); + + /** + * Set the tunnel mode. + * The tunnel can be enable or disable by passing 'enable' or 'disable'. + * If the mode is set to 'auto', Linphone will try to establish an RTP session + * on the mirror port of the tunnel server. If the connection fails, the tunnel + * will be activated. + * @param mode enable, disable or auto + */ + void tunnelSetMode(TunnelMode mode); + + /** + * Get the set mode + * @return + */ + TunnelMode tunnelGetMode(); + + /** + * Set whether sip packets must pass through the tunnel + * @param enable If true, tunnel will transport SIP packets in addition + * of RTP packets. + */ + void tunnelEnableSip(boolean enable); + + /** + * Check whether SIP tuneling is enabled + * @return true means the tunnel is set to transport SIP packets + */ + boolean tunnelSipEnabled(); + + /** + * @deprecated Use tunnelSetMode instaead + * Enable tunnel if the mirror RTP session cannot be established + */ void tunnelAutoDetect(); + + /** + * Clean the list of server + */ void tunnelCleanServers(); + + /** + * Set an optional HTTP proxy + * @param proxy_host + * @param port + * @param username + * @param password + */ void tunnelSetHttpProxy(String proxy_host, int port, String username, String password); /** * @param host tunnel server ip address @@ -882,29 +1485,66 @@ public interface LinphoneCore { * @param roundTripDelay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms */ void tunnelAddServerAndMirror(String host, int port, int udpMirrorPort, int roundTripDelay); + /** + * Add a server to the list of tunnel servers. + * @param config Parameters of the server to add. + */ + void tunnelAddServer(TunnelConfig config); + /** + * Returns a list of configured servers. + * @return Array of server configs. + */ + TunnelConfig[] tunnelGetServers(); boolean isTunnelAvailable(); - + /** + * Returns an unmodifiable list of entered proxy configurations. + * @return list of proxy config + **/ LinphoneProxyConfig[] getProxyConfigList(); - + /** + * Sets the default policy for video. + * This policy defines whether: + * @param autoInitiate video shall be initiated by default for outgoing calls + * @param autoAccept video shall be accepter by default for incoming calls + **/ void setVideoPolicy(boolean autoInitiate, boolean autoAccept); - void setStaticPicture(String path); + /** + * 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 + * */ + void setStaticPicture(String path); + /** + * Sets the user agent string used in SIP messages. + * @param user agent name + * @param user agent version + **/ void setUserAgent(String name, String version); - + /** + * Set the number of cores used for media processing + * */ void setCpuCount(int count); - + /** * remove a call log */ public void removeCallLog(LinphoneCallLog log); - + /** * @return count of missed calls */ public int getMissedCallsCount(); - + /** * Set missed calls count to zero */ @@ -918,67 +1558,126 @@ public interface LinphoneCore { * return the version code of linphone core */ public String getVersion(); - + /** * remove a linphone friend from linphone core and linphonerc */ void removeFriend(LinphoneFriend lf); - + /** * return a linphone friend (if exists) that matches the sip address */ LinphoneFriend findFriendByAddress(String sipUri); - + /** * Sets the UDP port used for audio streaming. **/ void setAudioPort(int port); - + /** * Sets the UDP port range from which to randomly select the port used for audio streaming. */ void setAudioPortRange(int minPort, int maxPort); - + + /** + * Assign a DSCP value to the audio RTP sockets. + * @param dscp the DSCP value. + * DSCP is an IP header field used to indicate a type of service to routers. + */ + void setAudioDscp(int dscp); + + /** + * Return DSCP value used for the audio RTP sockets. + * @return the DSCP value used for the audio RTP sockets. + */ + int getAudioDscp(); + /** * Sets the UDP port used for video streaming. **/ void setVideoPort(int port); - + /** * Sets the UDP port range from which to randomly select the port used for video streaming. */ void setVideoPortRange(int minPort, int maxPort); - + + /** + * Assign a DSCP value to the video RTP sockets. + * @param dscp the DSCP value. + * DSCP is an IP header field used to indicate a type of service to routers. + */ + void setVideoDscp(int dscp); + + /** + * Return DSCP value used for the video RTP sockets. + * @return the DSCP value used for the video RTP sockets. + */ + int getVideoDscp(); + /** * Set the incoming call timeout in seconds. * If an incoming call isn't answered for this timeout period, it is * automatically declined. **/ void setIncomingTimeout(int timeout); - + /** * Set the call timeout in seconds. * Once this time is elapsed (ringing included), the call is automatically hung up. **/ void setInCallTimeout(int timeout); - + /** + * Allow to control microphone level: + * @param gain in db + **/ void setMicrophoneGain(float gain); - + + /** + * Set address to use if no LinphoneProxyConfig configured + */ + void setPrimaryContact(String address); + + /** + * Returns the address used if no LinphoneProxyConfig configured + */ + String getPrimaryContact(); + /** * Set username and display name to use if no LinphoneProxyConfig configured */ 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 * the config file with your own sections @@ -989,25 +1688,375 @@ public interface LinphoneCore { /** * Return the availability of uPnP. * - * @return true if uPnP is available otherwise return false. + * @return true if uPnP is available otherwise return false. */ public boolean upnpAvailable(); /** - * Return the internal state of uPnP. + * Return the internal state of uPnP. * - * @return an UpnpState. + * @return an UpnpState. */ public UpnpState getUpnpState(); /** - * Return the external ip address of router. + * Return the external ip address of router. * In some cases the uPnP can have an external ip address but not a usable uPnP - * (state different of Ok). + * (state different of Ok). * * @return a null terminated string containing the external ip address. If the - * the external ip address is not available return null. + * the external ip address is not available return null. */ 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); + + /** + * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body. + * If accepted, the subscription runs for a finite period, but is automatically renewed if not terminated before. + * Unlike linphone_core_subscribe() the subscription isn't sent immediately. It will be send when calling linphone_event_send_subscribe(). + * @param resource the destination resource + * @param event the event name + * @param expires the whished duration of the subscription + * @param body an optional body, may be NULL. + * @return a LinphoneEvent holding the context of the created subcription. + */ + public LinphoneEvent createSubscribe(LinphoneAddress resource, String event, int expires); + + /** + * Create a publish context for an event state. + * After being created, the publish must be sent using linphone_event_send_publish(). + * After expiry, the publication is refreshed unless it is terminated before. + * @param resource the resource uri for the event + * @param event the event name + * @param expires the lifetime of the publication + * @return the LinphoneEvent holding the context of the publish. + */ + public LinphoneEvent createPublish(LinphoneAddress resource, String event, int expires); + + /** + * 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(); + + /** + * Gets the linphonecore supported resolutions for video + * @return an array of String + */ + public String[] getSupportedVideoSizes(); + + /** + * Migrate configuration so that all SIP transports are enabled. + * Versions of linphone < 3.7 did not support using multiple SIP transport simultaneously. + * This function helps application to migrate the configuration so that all transports are enabled. + * Existing proxy configuration are added a transport parameter so that they continue using the unique transport that was set previously. + * This function must be used just after creating the core, before any call to linphone_core_iterate() + * @returns 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error. + */ + public int migrateToMultiTransport(); + + /** + * When receiving an incoming, accept to start a media session as early-media. + * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. + * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. + * The call can then later be fully accepted using linphone_core_accept_call() or linphone_core_accept_call_with_params(). + * @param lc the linphonecore + * @param call the call + * @param params the call params, can be NULL. + * @return true if successful, false otherwise. + */ + public boolean acceptEarlyMedia(LinphoneCall call); + + /** + * Accept an early media session for an incoming call. + * This is identical as calling linphone_core_accept_early_media_with_params() with NULL call parameters. + * @see linphone_core_accept_early_media_with_params() + * @param lc the core + * @param call the incoming call + * @return true if successful, false otherwise. + */ + public boolean acceptEarlyMediaWithParams(LinphoneCall call, LinphoneCallParams params); + + /** + * Creates a proxy config using the default values if they exists + * @return a default proxy config + */ + public LinphoneProxyConfig createProxyConfig(); + public LinphoneProxyConfig createProxyConfig(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException; + + /** + * Assign an audio file to played locally upon call failure, for a given reason. + * @param reason the #LinphoneReason representing the failure error code. + * @param path a wav file to be played when such call failure happens. + */ + public void setCallErrorTone(Reason reason, String path); + + /** + * Assign an audio file to be played locally in replacement of common telephony tone. + * This is typically used to internationalize tones. + * @param id a tone id + * @param wav a path to a 16 bit PCM linear wav file. + */ + public void setTone(ToneID id, String wavfile); + + /** + * Inform the core about the maximum transmission unit of the network. + * This is used for fragmenting video RTP packets to a size compatible with the network. + * @param mtu the MTU in bytes. + */ + public void setMtu(int mtu); + /** + * Returns the mtu value previously set by setMtu(). + * + * @return the MTU in bytes. + */ + public int getMtu(); + /** + Control when media offer is sent in SIP INVITE. + * @param enable true if INVITE has to be sent whitout SDP. + * */ + public void enableSdp200Ack(boolean enable); + /** + * Media offer control param for SIP INVITE. + * @return true if INVITE has to be sent whitout SDP. + */ + public boolean isSdp200AckEnabled(); + + /** + * Inconditionnaly disable incoming chat messages. + * @param lc the core + * @param deny_reason the deny reason (using ReasonNone has no effect). + **/ + public void disableChat(Reason denycode); + + /** + * Enable reception of incoming chat messages. + * By default it is enabled but it can be disabled with linphone_core_disable_chat(). + * @param lc the core + **/ + public void enableChat(); + + + /** + * Returns whether chat is enabled. + * @return true if chat is enabled, false otherwise. + **/ + public boolean chatEnabled(); + + /** + * 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. + **/ + public void stopRinging(); + + /** + * Set audio jitter buffer size in milliseconds. + * A value of zero disables the jitter buffer. + * The new value is taken into account immediately for all running or pending calls. + * @param value the jitter buffer size in milliseconds. + */ + public void setAudioJittcomp(int value); + + /** + * Set video jitter buffer size in milliseconds. + * A value of zero disables the jitter buffer. + * The new value is taken into account immediately for all running or pending calls. + * @param value the jitter buffer size in milliseconds. + */ + public void setVideoJittcomp(int value); + + /** + * Globaly set an http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. + * @param serverUrl URL of the file server like https://file.linphone.org/upload.php + */ + public void setFileTransferServer(String serverUrl); + + /** + * Get the globaly set http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. + * @return the serverUrl + */ + public String getFileTransferServer(); + + /** + * Create a media player + * @return An object that implement LinphonePlayer + */ + public LinphonePlayer createLocalPlayer(AndroidVideoWindowImpl window); + + /** + * Adds a new listener to be called by the core + * @param listener to add + */ + public void addListener(LinphoneCoreListener listener); + + /** + * Removes a listener previously added with addListener + * @param listener to remove + */ + public void removeListener(LinphoneCoreListener listener); + + /** + * Specifies a ring back tone to be played to far end during incoming calls, when early media is requested. + * @param file + */ + public void setRemoteRingbackTone(String file); + + /** + * Return the ringback tone file used when doing early media. It may be null. + * @return the ringback tone file path. + */ + String getRemoteRingbackTone(); + + /** + * Upload the log collection to the configured server url. + */ + public void uploadLogCollection(); + + /** + * Reset the log collection by removing the log files. + */ + public void resetLogCollection(); + + + /** + * Use to set multicast address to be used for audio stream. + * @param ip an ipv4/6 multicast address + * @return + * @thow LinphoneCoreException + **/ + public void setAudioMulticastAddr(String ip) throws LinphoneCoreException; + /** + * Use to set multicast address to be used for video stream. + * @param ip an ipv4/6 multicast address + * @thow LinphoneCoreException + **/ + public void setVideoMulticastAddr(String ip) throws LinphoneCoreException; + + /** + * Use to get multicast address to be used for audio stream. + * @return an ipv4/6 multicast address or default value + **/ + public String getAudioMulticastAddr(); + + /** + * Use to get multicast address to be used for video stream. + * @return an ipv4/6 multicast address, or default value + **/ + public String getVideoMulticastAddr(); + + /** + * Use to set multicast ttl to be used for audio stream. + * @param ttl value or -1 if not used. [0..255] default value is 1 + * @thow LinphoneCoreException + **/ + public void setAudioMulticastTtl(int ttl) throws LinphoneCoreException; + /** + * Use to set multicast ttl to be used for video stream. + * @param ttl value or -1 if not used. [0..255] default value is 1 + * @thow LinphoneCoreException + **/ + public void setVideoMulticastTtl(int ttl) throws LinphoneCoreException; + + /** + * Use to get multicast ttl to be used for audio stream. + * @return a time to leave value + * @thow LinphoneCoreException + * **/ + public int getAudioMulticastTtl(); + + /** + * Use to get multicast ttl to be used for video stream. + * @return a time to leave value + * @thow LinphoneCoreException + **/ + public int getVideoMulticastTtl(); + + + /** + * Use to enable multicast rtp for audio stream. + * * If enabled, outgoing calls put a multicast address from {@link linphone_core_get_video_multicast_addr} into audio cline. In case of outgoing call audio stream is sent to this multicast address. + *
    For incoming calls behavior is unchanged. + * @param yesno if yes, subsequent calls will propose multicast ip set by {@link linphone_core_set_audio_multicast_addr} + **/ + public void enableAudioMulticast(boolean yesno); + + /** + * Use to get multicast state of audio stream. + * @return true if subsequent calls will propose multicast ip set by {@link linphone_core_set_audio_multicast_addr} + **/ + public boolean audioMulticastEnabled(); + + /** + * Use to enable multicast rtp for video stream. + * If enabled, outgoing calls put a multicast address from {@link linphone_core_get_video_multicast_addr} into video cline. In case of outgoing call video stream is sent to this multicast address. + *
    For incoming calls behavior is unchanged. + * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by {@link linphone_core_set_video_multicast_addr} + **/ + public void enableVideoMulticast(boolean yesno); + /** + * Use to get multicast state of video stream. + * @return true if subsequent calls will propose multicast ip set by {@link linphone_core_set_video_multicast_addr} + **/ + public boolean videoMulticastEnabled(); + + /** + * Enable or disable DNS SRV resolution. + * @param yesno true to enable DNS SRV resolution, false to disable it. + */ + public void enableDnsSrv(boolean yesno); + + /** + * Tells whether DNS SRV resolution is enabled. + * @return true if DNS SRV resolution is enabled, false if disabled. + */ + public boolean dnsSrvEnabled(); + + /** + * Set the video preset to be used for video calls. + * @param lc LinphoneCore object + * @param preset The name of the video preset to be used (can be null to use the default video preset). + */ + public void setVideoPreset(String preset); + + /** + * Get the video preset used for video calls. + * @param lc LinphoneCore object + * @return The name of the video preset used for video calls (can be null if the default video preset is used). + */ + public String getVideoPreset(); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 399b9ec8d..8019ec7bd 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -22,6 +22,7 @@ package org.linphone.core; + abstract public class LinphoneCoreFactory { private static String factoryName = "org.linphone.core.LinphoneCoreFactoryImpl"; @@ -48,10 +49,43 @@ abstract public class LinphoneCoreFactory { } return theLinphoneCoreFactory; } - abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm); + /** + * create {@link LinphoneAuthInfo} + * @param username + * @param userid user id as set in auth header + * @param passwd + * */ + abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm, String domain); + /** + * create {@link LinphoneAuthInfo} + * @param username + * @param userid user id as set in auth header + * @param passwd + * @param ha1 + * @param 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; + /** + * Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application. + * @param listener listener to receive notifications from the core + * @param userConfig path where to read/write configuration (optional) + * @param factoryConfig path where to read factory configuration (optional) + * @param userdata any kind of application specific data + * @param context an application context, on android this MUST be the android.content.Context object used by the application. + * @return a LinphoneCore object. + * @throws LinphoneCoreException + */ + abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata, Object context) throws LinphoneCoreException; + /** + * Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application. + * @param listener listener to receive notifications from the core. + * @param context an application context, on android this MUST be the android.content.Context object used by the application. + * @return the LinphoneCore object. + * @throws LinphoneCoreException + */ + abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException; + /** * Constructs a LinphoneAddress object @@ -65,30 +99,72 @@ 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; /** * Enable verbose traces - * @param enable - * @param tag + * @param enable true to enable debug mode, false to disable it + * @param tag Tag which prefixes each log message. */ - abstract public void setDebugMode(boolean enable, String tag); + abstract public void setDebugMode(boolean enable, String tag); + + /** + * Enable the linphone core log collection to upload logs on a server. + */ + abstract public void enableLogCollection(boolean enable); + + /** + * Set the path where the log files will be written for log collection. + * @param path The path where the log files will be written. + */ + abstract public void setLogCollectionPath(String path); abstract public void setLogHandler(LinphoneLogHandler handler); + /** * Create a LinphoneFriend, similar to {@link #createLinphoneFriend()} + {@link LinphoneFriend#setAddress(LinphoneAddress)} * @param friendUri a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new LinphoneFriend with address initialized */ abstract public LinphoneFriend createLinphoneFriend(String friendUri); + /** * Create a new LinphoneFriend * @return */ 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..b7457a777 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -18,45 +18,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; +import java.nio.ByteBuffer; + /** * *This interface holds all callbacks that the application should implement. None is mandatory. */ public interface LinphoneCoreListener { + /**< Ask the application some authentication information * @return */ - void authInfoRequested(LinphoneCore lc,String realm,String username); - - /** General State notification - * @param state LinphoneCore.State - * @return - * */ - void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message); - - /** Call State notification - * @param state LinphoneCall.State - * @return - * */ - void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message); + void authInfoRequested(LinphoneCore lc, String realm, String username, String Domain); /** * Call stats notification */ void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats); - /** - * Callback to display change in encryption state. - * @param encrypted true if all streams of the call are encrypted - * @param authenticationToken token like ZRTP SAS that may be displayed to user - */ - void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, boolean encrypted, String authenticationToken); - - /** - * Registration state notification - * */ - void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage); - /** * Reports that a new subscription request has been received and wait for a decision. *Status on this subscription request is notified by changing policy for this friend @@ -74,23 +53,6 @@ public interface LinphoneCoreListener { */ void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf); - /** - * invoked when a new text message is received - * @param lc LinphoneCore - * @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room. - * @param from LinphoneAddress from - * @param message incoming message - */ - void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message); - - /** - * invoked when a new linphone chat message is received - * @param lc LinphoneCore - * @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room. - * @param message incoming linphone chat message message - */ - void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message); - /** * invoked when a new dtmf is received * @param lc LinphoneCore @@ -98,15 +60,7 @@ public interface LinphoneCoreListener { * @param dtmf value of the dtmf sent */ void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf); - - /** - * Invoked when echo cancalation calibration is completed - * @param lc LinphoneCore - * @param status - * @param delay_ms echo delay - * @param data - */ - void ecCalibrationStatus(LinphoneCore lc,LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data); + /** * Report Notified message received for this identity. * @param lc LinphoneCore @@ -117,10 +71,41 @@ 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 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 */ void show(LinphoneCore lc); + /**< @Deprecated Callback that notifies various events with human readable text. * @return */ void displayStatus(LinphoneCore lc,String message); @@ -133,5 +118,113 @@ public interface LinphoneCoreListener { * @return */ void displayWarning(LinphoneCore lc,String message); + /** + * Callback to be notified about the transfer progress. + * @param lc the LinphoneCore + * @param message the LinphoneChatMessage + * @param content the LinphoneContent + * @param progress percentage of the transfer done + */ + void fileTransferProgressIndication(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, int progress); + + /** + * Callback to be notified when new data has been received + * @param lc the LinphoneCore + * @param message the LinphoneChatMessage + * @param content the LinphoneContent + * @param buffer + * @param size + */ + void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, byte[] buffer, int size); + + /** + * Callback to be notified when new data needs to be sent + * @param lc the LinphoneCore + * @param message the LinphoneChatMessage + * @param content the LinphoneContent + * @param buffer + * @param size + * @return the number of bytes written into buffer + */ + int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, ByteBuffer buffer, int size); + + /** General State notification + * @param state LinphoneCore.State + * @return + * */ + void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message); + + /** + * Registration state notification + * */ + void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage); + + /** + * Notifies the changes about the remote provisioning step + * @param lc the LinphoneCore + * @param state the RemoteProvisioningState + * @param message the error message if state == Failed + */ + void configuringStatus(LinphoneCore lc, LinphoneCore.RemoteProvisioningState state, String message); + + /** + * invoked when a new linphone chat message is received + * @param lc LinphoneCore + * @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room. + * @param message incoming linphone chat message message + */ + void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message); + + + /** Call State notification + * @param state LinphoneCall.State + * @return + * */ + void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message); + + /** + * Callback to display change in encryption state. + * @param encrypted true if all streams of the call are encrypted + * @param authenticationToken token like ZRTP SAS that may be displayed to user + */ + void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, boolean encrypted, String authenticationToken); + + /** + * 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); + + /** + * invoked when a composing notification is received + * @param lc LinphoneCore + * @param room LinphoneChatRoom involved in the conversation. + */ + void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr); + + /** + * Invoked when echo cancalation calibration is completed + * @param lc LinphoneCore + * @param status + * @param delay_ms echo delay + * @param data + */ + void ecCalibrationStatus(LinphoneCore lc, LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data); + + /** + * Callback prototype for reporting log collection upload progress indication. + */ + void uploadProgressIndication(LinphoneCore lc, int offset, int total); + + /** + * Callback prototype for reporting log collection upload state change. + * @param lc LinphoneCore object + * @param state The state of the log collection upload + * @param info Additional information: error message in case of error state, URL of uploaded file in case of success. + */ + void uploadStateChanged(LinphoneCore lc, LinphoneCore.LogCollectionUploadState state, String info); } diff --git a/java/common/org/linphone/core/LinphoneCoreListenerBase.java b/java/common/org/linphone/core/LinphoneCoreListenerBase.java new file mode 100644 index 000000000..a7db59c11 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneCoreListenerBase.java @@ -0,0 +1,201 @@ +package org.linphone.core; + +import java.nio.ByteBuffer; + +import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCore.EcCalibratorStatus; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.LogCollectionUploadState; +import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; + +public class LinphoneCoreListenerBase implements LinphoneCoreListener { + + @Override + public void authInfoRequested(LinphoneCore lc, String realm, + String username, String Domain) { + // TODO Auto-generated method stub + + } + + @Override + public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, + LinphoneCallStats stats) { + // TODO Auto-generated method stub + + } + + @Override + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, + String url) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) { + // TODO Auto-generated method stub + + } + + @Override + public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneCall call, + LinphoneAddress from, byte[] event) { + // TODO Auto-generated method stub + + } + + @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 publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + + @Override + public void show(LinphoneCore lc) { + // TODO Auto-generated method stub + + } + + @Override + public void displayStatus(LinphoneCore lc, String message) { + // TODO Auto-generated method stub + + } + + @Override + public void displayMessage(LinphoneCore lc, String message) { + // TODO Auto-generated method stub + + } + + @Override + public void displayWarning(LinphoneCore lc, String message) { + // TODO Auto-generated method stub + + } + + @Override + public void fileTransferProgressIndication(LinphoneCore lc, + LinphoneChatMessage message, LinphoneContent content, int progress) { + // TODO Auto-generated method stub + + } + + @Override + public void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message, + LinphoneContent content, byte[] buffer, int size) { + // TODO Auto-generated method stub + + } + + @Override + public int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message, + LinphoneContent content, ByteBuffer buffer, int size) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void globalState(LinphoneCore lc, GlobalState state, String message) { + // TODO Auto-generated method stub + + } + + @Override + public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, + RegistrationState state, String smessage) { + // TODO Auto-generated method stub + + } + + @Override + public void configuringStatus(LinphoneCore lc, + RemoteProvisioningState state, String message) { + // TODO Auto-generated method stub + + } + + @Override + public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, + LinphoneChatMessage message) { + // TODO Auto-generated method stub + + } + + @Override + public void callState(LinphoneCore lc, LinphoneCall call, State state, + String message) { + // TODO Auto-generated method stub + + } + + @Override + public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, + boolean encrypted, String authenticationToken) { + // 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 isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // TODO Auto-generated method stub + + } + + @Override + public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status, + int delay_ms, Object data) { + // TODO Auto-generated method stub + + } + + @Override + public void uploadProgressIndication(LinphoneCore lc, int offset, int total) { + // TODO Auto-generated method stub + + } + + @Override + public void uploadStateChanged(LinphoneCore lc, + LogCollectionUploadState state, String info) { + // TODO Auto-generated method stub + + } + +} diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java new file mode 100644 index 000000000..cca9a3f2d --- /dev/null +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -0,0 +1,109 @@ +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(); + + /** + * In case of error notified, returns the full error details. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); + + /** + * 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(); + + /** + * Add a custom header to an outgoing susbscription or publish. + * @param name header's name + * @param value the header's value. + */ + void addCustomHeader(String name, String value); + + /** + * Obtain the value of a given header for an incoming subscription. + * @param name header's name + * @return the header's value or NULL if such header doesn't exist. + */ + String getCustomHeader(String name); + + /** + * Send a subscription previously created by linphone_core_create_subscribe(). + * @param body optional content to attach with the subscription. + */ + void sendSubscribe(LinphoneContent body); + + /** + * Send a publish created by linphone_core_create_publish(). + * @param body the new data to be published + */ + void sendPublish(LinphoneContent body); + + /** + * Get a back pointer to the LinphoneCore object managing this LinphoneEvent. + * @return + */ + LinphoneCore getCore(); +} diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java index 417c582d9..b9080bd94 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). @@ -127,4 +133,16 @@ public interface LinphoneFriend { * Return the native pointer for this object */ long getNativePtr(); + + /** + * Set the reference key of a friend. + * @param key The reference key to use for the friend. + **/ + void setRefKey(String key); + + /** + * Get the reference key of a friend. + * @return The reference key of the friend. + **/ + String getRefKey(); } 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/LinphonePlayer.java b/java/common/org/linphone/core/LinphonePlayer.java new file mode 100644 index 000000000..79d05dbb4 --- /dev/null +++ b/java/common/org/linphone/core/LinphonePlayer.java @@ -0,0 +1,95 @@ +/** + * Interface to manipulate different media players of Linphone + */ +package org.linphone.core; + +/** + * @author François Grisez + * + */ +public interface LinphonePlayer { + /** + * States that the player can be + * @author François Grisez + * + */ + public enum State { + closed, /*< No file is open */ + paused, /*< A file is open and playback is not running */ + playing; /*< A file is open and playback is running */ + + public static State fromValue(int value) { + if(value == 0) { + return closed; + } else if(value == 1) { + return paused; + } else if(value == 2) { + return playing; + } else { + return null; + } + } + }; + + /** + * Listener for Linphone players + * @author François Grisez + * + */ + public interface Listener { + /** + * Method called when a player reaches the end of a file + * @param player The player which called the method + */ + public void endOfFile(LinphonePlayer player); + } + + /** + * Open a file + * @param filename Name of the file to open + * @return 0 on success, -1 on failure + */ + public int open(String filename, Listener listener); + + /** + * Start playback + * @return 0 on success, -1 on failure + */ + public int start(); + + /** + * Get playback paused + * @return 0 on success, -1 on failure + */ + public int pause(); + + /** + * Go to a specific position in the timeline + * @param timeMs Time in milliseconds + * @return 0 on success, -1 on failure + */ + public int seek(int timeMs); + + /** + * Get the state of the player + * @return See State enumeration + */ + public State getState(); + + /** + * Get the duration of the media + * @return The duration in milliseconds + */ + public int getDuration(); + + /** + * Get the position of the playback + * @return The position in milliseconds + */ + public int getCurrentPosition(); + + /** + * Close a file + */ + public void close(); +} diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index b6b8919fb..e5381701e 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -18,19 +18,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; /** - * The LinphoneProxyConfig object represents a proxy configuration to be used by the LinphoneCore object. Its fields must not be used directly in favour of the accessors methods. + * The LinphoneProxyConfig object represents a proxy configuration to be used by the LinphoneCore object. Its fields must not be used directly in favour of the accessors methods. * Once created and filled properly the LinphoneProxyConfig can be given to LinphoneCore with {@link LinphoneCore#addProxyConfig(LinphoneProxyConfig)}. This will automatically triggers the registration, if enabled. *
    The proxy configuration are persistent to restarts because they are saved in the configuration file. As a consequence, after {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)} there might already be a default proxy that can be examined with {@link LinphoneCore#getDefaultProxyConfig()} . * */ public interface LinphoneProxyConfig { - + /** *Starts editing a proxy configuration. - *Because proxy configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify proxy configuration (such as identity, proxy address and so on). + *Because proxy configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify proxy configuration (such as identity, proxy address and so on). *Once the modifications are done, then the application must call {@link #done()} to commit the changes. */ - public void edit(); + public LinphoneProxyConfig edit(); /** * Commits modification made to the proxy configuration. */ @@ -58,21 +58,20 @@ public interface LinphoneProxyConfig { public void setProxy(String proxyUri) throws LinphoneCoreException; /** * get the proxy's SIP address. - * + * */ public String getProxy(); /** * Enable register for this proxy config. * Register message is issued after call to {@link #done()} * @param value - * @throws LinphoneCoreException - */ - public void enableRegister(boolean value) throws LinphoneCoreException; + */ + public LinphoneProxyConfig enableRegister(boolean value); /** * @return true if registration to the proxy is enabled. */ public boolean registerEnabled(); - + /** * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 * @param number @@ -84,20 +83,32 @@ 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)}). * @param value default value is false */ 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 */ public String getDomain(); /** - * + * * @return a boolean indicating that the user is successfully registered on the proxy. */ public boolean isRegistered(); @@ -108,7 +119,7 @@ public interface LinphoneProxyConfig { */ public void setRoute(String routeUri) throws LinphoneCoreException; /** - * + * * @return the route set for this proxy configuration. */ public String getRoute(); @@ -124,31 +135,187 @@ public interface LinphoneProxyConfig { * returns publish state for this proxy config (see {@link #enablePublish(boolean)} ) */ public boolean publishEnabled(); - - + + LinphoneCore.RegistrationState getState(); - + /** * Sets the registration expiration time. * @param delay expiration time in seconds */ void setExpires(int delay); - + /** - * Sets parameters for the contact - * @param parameters to add + * Gets the registration expiration time. + * @return delay expiration time in seconds. */ - public void setContactParameters(String params); - + 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(); + + /** + * Indicates whether AVPF/SAVPF must be used for calls using this proxy config. + * @param enable True to enable AVPF/SAVF, false to disable it. + */ + void enableAvpf(boolean enable); + + /** + * Whether AVPF is used for calls through this proxy. + * @return + */ + boolean avpfEnabled(); + + /** + * Set the interval between regular RTCP reports when using AVPF/SAVPF. + * @param interval The interval in seconds (between 0 and 5 seconds). + */ + void setAvpfRRInterval(int interval); + + /** + * Get the interval between regular RTCP reports when using AVPF/SAVPF. + * @return The interval in seconds. + */ + int getAvpfRRInterval(); + + /** + * Indicates whether quality reporting must be used for calls using this proxy config. + * @param enable True to enable quality reporting, false to disable it. + */ + void enableQualityReporting(boolean enable); + + + /** + * Whether quality reporting is used for calls through this proxy. + * @return + */ + boolean qualityReportingEnabled(); + + /** + * Set the interval between quality interval reports during a call when using quality reporting. + * @param interval The interval in seconds (should be greater than 120 seconds to avoid too much). + */ + void setQualityReportingInterval(int interval); + + /** + * Get the interval between quality interval reports during a call when using quality reporting. + * @return The interval in seconds. + */ + int getQualityReportingInterval(); + + /** + * Set the collector SIP URI to collect reports when using quality reporting. + * @param collector The collector SIP URI which should be configured server side too. + */ + void setQualityReportingCollector(String collector); + + /** + * Get the collector SIP URI collecting reports when using quality reporting. + * @return The SIP URI collector address. + */ + String getQualityReportingCollector(); + + /** + * Set the outbound proxy realm. It is used in digest authentication to avoid + * re-authentication if a previous token has already been provided. + * @param The new outbound proxy realm. + */ + void setRealm(String realm); + + /** + * Get the outbound proxy realm. + * @return The outbound proxy realm. + */ + String getRealm(); + + /** + * Set optional contact parameters that will be added to the contact information sent in the registration. + * @param contact_params a string containing the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or android push id. + * As an example, the contact address in the SIP register sent will look like ;android-push-id=43143-DFE23F-2323-FA2232. + **/ + public void setContactParameters(String contact_params); + + /** + * Get the contact's parameters. + * @return + */ + public String getContactParameters(); + + /** + * Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI. + * @param params a string containing the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. + * As an example, the contact address in the SIP register sent will look like . + **/ + public void setContactUriParameters(String params); + + /** + * Get the contact's URI parameters. + * @return + */ + public String getContactUriParameters(); + /** * Return the international prefix for the given country * @param country iso code */ public int lookupCCCFromIso(String iso); - + /** * Return the international prefix for the given country * @param e164 phone number */ public int lookupCCCFromE164(String e164); + + /** + * Return reason error code. + * @return reason code. + */ + public Reason getError(); + + /** + * Get full error information about last error occured on the proxy config. + * @return an ErrorInfo. + */ + public ErrorInfo getErrorInfo(); + + /** + * Set the publish expiration time in second. + * @param expires in second + */ + public void setPublishExpires(int expires); + /** + * @return the publish expiration time in second. Default value is the registration expiration value. + */ + public int getPublishExpires(); + + /** + * attached a user data to a proxy config + **/ + void setUserData(Object obj); + + /** + * Detect if the given input is a phone number or not. + * @param username string to parse. + * @return TRUE if input is a phone number, FALSE otherwise. + **/ + boolean isPhoneNumber(String username); + + /** + * Returns user data from a proxy config. return null if any + * @return an Object. + */ + Object getUserData(); } 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..b89c831eb --- /dev/null +++ b/java/common/org/linphone/core/PublishState.java @@ -0,0 +1,46 @@ +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()} + * [sip]->refresh_generic_subscribe property is set to 0. + */ + 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..0d7625a36 100644 --- a/java/common/org/linphone/core/Reason.java +++ b/java/common/org/linphone/core/Reason.java @@ -32,6 +32,62 @@ 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"); + /** + * Operation was rejected by remote, for example a LinphoneCore.updateCall() + */ + static public Reason NotAcceptable = new Reason(11,"NotAcceptable"); + /** + * Operation was rejected by remote due to request unmatched to any context. + */ + static public Reason NoMatch = new Reason(12,"NoMatch"); + /** + * Resource moved permanently + */ + static public Reason MovedPermanently = new Reason(13,"MovedPermanently"); + /** + * Resource no longer exists + */ + static public Reason Gone = new Reason(14,"Gone"); + /** + * Temporarily unavailable + */ + static public Reason TemporarilyUnavailable = new Reason(15,"TemporarilyUnavailable"); + /** + * Address incomplete + */ + static public Reason AddressIncomplete = new Reason(16,"AddressIncomplete"); + /** + * Not implemented + */ + static public Reason NotImplemented = new Reason(17,"NotImplemented"); + /** + * Bad gateway + */ + static public Reason BadGateway = new Reason(18,"BadGateway"); + /** + * Server timeout + */ + static public Reason ServerTimeout = new Reason(19,"ServerTimeout"); + /** + * Unknown + */ + static public Reason Unknown = new Reason(20,"Unknown"); 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..0a278556e --- /dev/null +++ b/java/common/org/linphone/core/SubscriptionState.java @@ -0,0 +1,55 @@ +package org.linphone.core; + +public enum SubscriptionState { + /** + * Initial state, should not be used. + */ + None(0), + /** + * An outgoing subcription was created. + */ + OutoingProgress(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), + + /** + * Subscription is about to expire, only notified if [sip]->refresh_generic_subscribe property is set to 0 + */ + Expiring(7); + 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 OutoingProgress; + case 2: return IncomingReceived; + case 3: return Pending; + case 4: return Active; + case 5: return Terminated; + case 6: return Error; + case 7: return Expiring; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for SubscriptionState"); + } + } +} diff --git a/java/common/org/linphone/core/ToneID.java b/java/common/org/linphone/core/ToneID.java new file mode 100644 index 000000000..6ef8be1ab --- /dev/null +++ b/java/common/org/linphone/core/ToneID.java @@ -0,0 +1,24 @@ +package org.linphone.core; + +public enum ToneID { + Undefined(0), + Busy(1), + CallWaiting(2), + CallOnHold(3), + CallLost(4); + protected final int mValue; + private ToneID(int value){ + mValue=value; + } + static protected ToneID fromInt(int value) throws LinphoneCoreException{ + switch(value){ + case 0: return Undefined; + case 1: return Busy; + case 2: return CallWaiting; + case 3: return CallOnHold; + case 4: return CallLost; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for LinphoneToneID"); + } + } +} diff --git a/java/common/org/linphone/core/VideoSize.java b/java/common/org/linphone/core/VideoSize.java index b9b3e0710..7685e20a0 100644 --- a/java/common/org/linphone/core/VideoSize.java +++ b/java/common/org/linphone/core/VideoSize.java @@ -26,6 +26,13 @@ public final class VideoSize { public static final int CIF = 1; public static final int HVGA = 2; public static final int QVGA = 3; + public static final VideoSize VIDEO_SIZE_QCIF = new VideoSize(176,144); + public static final VideoSize VIDEO_SIZE_CIF = new VideoSize(352,288); + public static final VideoSize VIDEO_SIZE_QVGA = new VideoSize(320,240); + public static final VideoSize VIDEO_SIZE_HVGA = new VideoSize(320,480); + public static final VideoSize VIDEO_SIZE_VGA = new VideoSize(640,480); + public static final VideoSize VIDEO_SIZE_720P = new VideoSize(1280,720); + public static final VideoSize VIDEO_SIZE_1020P = new VideoSize(1920,1080); public int width; public int height; @@ -36,6 +43,7 @@ public final class VideoSize { this.height = height; } + @Deprecated public static final VideoSize createStandard(int code, boolean inverted) { switch (code) { case QCIF: @@ -78,7 +86,9 @@ public final class VideoSize { return true; } - + public String toDisplayableString() { + return width + "x" + height; + } public String toString() { return "width = "+width + " height = " + height; } diff --git a/java/impl/org/linphone/core/ErrorInfoImpl.java b/java/impl/org/linphone/core/ErrorInfoImpl.java new file mode 100644 index 000000000..e9b6bd5f3 --- /dev/null +++ b/java/impl/org/linphone/core/ErrorInfoImpl.java @@ -0,0 +1,41 @@ +package org.linphone.core; + +public class ErrorInfoImpl implements ErrorInfo { + private Reason mReason; + private int mCode; + private String mPhrase; + private String mDetails; + + private native int getReason(long nativePtr); + private native int getProtocolCode(long nativePtr); + private native String getPhrase(long nativePtr); + private native String getDetails(long nativePtr); + + public ErrorInfoImpl(long nativePtr){ + mReason=Reason.fromInt(getReason(nativePtr)); + mCode=getProtocolCode(nativePtr); + mPhrase=getPhrase(nativePtr); + mDetails=getDetails(nativePtr); + } + + @Override + public Reason getReason() { + return mReason; + } + + @Override + public int getProtocolCode() { + return mCode; + } + + @Override + public String getPhrase() { + return mPhrase; + } + + @Override + public String getDetails() { + return mDetails; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index b9d290971..e5c2b53d8 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -21,34 +21,63 @@ 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 int getTransport(long ptr); + private native int getPort(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 void setTransport(long ptr, int transport); + private native void setPort(long ptr, int port); private native String toString(long ptr); - 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); @@ -59,42 +88,40 @@ public class LinphoneAddressImpl implements LinphoneAddress { public String getUserName() { return getUserName(nativePtr); } - - public String toString() { + public TransportType getTransport() { + return TransportType.fromInt(getTransport(nativePtr)); + } + public int getPort() { return getPort(nativePtr); } + + public String toString() { return toString(nativePtr); } public String toUri() { return toUri(nativePtr); } + + public String asString() { + return toString(); + } + public String asStringUriOnly() { + return toUri(nativePtr); + } + + public void clean() { + throw new RuntimeException("Not implemented"); + } + public void setDisplayName(String name) { setDisplayName(nativePtr,name); } - public String asString() { - return toString(); - } - public String asStringUriOnly() { - return toUri(nativePtr); - } - public void clean() { - throw new RuntimeException("Not implemented"); - } - public String getPort() { - return String.valueOf(getPortInt()); - } - public int getPortInt() { - return getPortInt(); - } public void setDomain(String domain) { - throw new RuntimeException("Not implemented"); - } - public void setPort(String port) { - throw new RuntimeException("Not implemented"); - } - public void setPortInt(int port) { - throw new RuntimeException("Not implemented"); + setDomain(nativePtr, domain); } + public void setPort(int port) { setPort(nativePtr, port); } public void setUserName(String username) { - throw new RuntimeException("Not implemented"); + setUserName(nativePtr,username); + } + public void setTransport(TransportType transport) { + setTransport(nativePtr, transport.toInt()); } - } diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java index 45fd8a45e..8efdcc144 100644 --- a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java @@ -20,36 +20,95 @@ package org.linphone.core; class LinphoneAuthInfoImpl implements LinphoneAuthInfo { protected final long nativePtr; - private native long newLinphoneAuthInfo(String username, String userid, String passwd, String ha1,String realm); + private native long newLinphoneAuthInfo(); private native void delete(long ptr); - protected LinphoneAuthInfoImpl(String username,String password, String realm) { - nativePtr = newLinphoneAuthInfo(username,"",password,"",""); + private native String getPassword(long ptr); + private native String getRealm(long ptr); + private native String getUsername(long ptr); + private native void setPassword(long ptr, String password); + private native void setRealm(long ptr, String realm); + private native void setUsername(long ptr, String username); + private native void setUserId(long ptr, String username); + 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); + + boolean ownPtr = false; + protected LinphoneAuthInfoImpl(String username,String password, String realm, String domain) { + this(username, null, password, null, realm, domain); + } + 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); + this.setRealm(realm); + ownPtr = true; + } + protected LinphoneAuthInfoImpl(long aNativePtr) { + nativePtr = aNativePtr; + ownPtr = false; } protected void finalize() throws Throwable { - delete(nativePtr); + if (ownPtr) delete(nativePtr); } public String getPassword() { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + return getPassword (nativePtr); } public String getRealm() { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + return getRealm (nativePtr); } public String getUsername() { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + return getUsername (nativePtr); } public void setPassword(String password) { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + setPassword(nativePtr,password); } public void setRealm(String realm) { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + setRealm(nativePtr,realm); } public void setUsername(String username) { - // TODO Auto-generated method stub - throw new RuntimeException("not implemeneted yet"); + setUsername(nativePtr,username); + } + @Override + public String getUserId() { + return getUserId(nativePtr); + } + @Override + public void setUserId(String userid) { + setUserId(nativePtr,userid); + + } + @Override + public String getHa1() { + return getHa1(nativePtr); + } + @Override + public void setHa1(String ha1) { + 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/LinphoneBufferImpl.java b/java/impl/org/linphone/core/LinphoneBufferImpl.java new file mode 100644 index 000000000..143fd1e17 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneBufferImpl.java @@ -0,0 +1,33 @@ +package org.linphone.core; + +public class LinphoneBufferImpl implements LinphoneBuffer { + private byte[] mData; + private int mSize; + + public LinphoneBufferImpl(byte[] data, int size) + { + mData = data; + mSize = size; + } + + @Override + public byte[] getContent() { + return mData; + } + + @Override + public void setContent(byte[] data) { + mData = data; + } + + @Override + public int getSize() { + return mSize; + } + + @Override + public void setSize(int size) { + mSize = size; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 30bcd528f..de9e25364 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -18,11 +18,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - class LinphoneCallImpl implements LinphoneCall { protected final long nativePtr; boolean ownPtr = false; + Object userData; private LinphoneCallStats audioStats; private LinphoneCallStats videoStats; @@ -43,6 +43,7 @@ class LinphoneCallImpl implements LinphoneCall { private native int getDuration(long nativePtr); private native float getCurrentQuality(long nativePtr); private native float getAverageQuality(long nativePtr); + private native boolean mediaInProgress(long nativePtr); /* * This method must always be called from JNI, nothing else. @@ -68,9 +69,11 @@ class LinphoneCallImpl implements LinphoneCall { videoStats = stats; } public LinphoneCallStats getAudioStats() { + if (audioStats!=null) ((LinphoneCallStatsImpl)audioStats).updateRealTimeStats(this); return audioStats; } public LinphoneCallStats getVideoStats() { + if (videoStats!=null) ((LinphoneCallStatsImpl)videoStats).updateRealTimeStats(this); return videoStats; } public CallDirection getDirection() { @@ -79,7 +82,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; } @@ -165,6 +168,8 @@ class LinphoneCallImpl implements LinphoneCall { return params.localConferenceMode(); } + public boolean mediaInProgress() { return mediaInProgress(nativePtr);} + @Override public String toString() { return "Call " + nativePtr; @@ -205,4 +210,49 @@ 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); + } + @Override + public Reason getReason() { + // TODO Auto-generated method stub + return null; + } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } + @Override + public void setUserData(Object obj) { + userData = obj; + } + @Override + public Object getUserData() { + return userData; + } + + private native long getPlayer(long callPtr); + @Override + public LinphonePlayer getPlayer() { + return new LinphonePlayerImpl(getPlayer(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..c4b356fa7 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -106,5 +106,69 @@ 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); + } + + private native void setSessionName(long nativePtr, String name); + @Override + public void setSessionName(String name) { + setSessionName(nativePtr,name); + } + + private native String getSessionName(long nativePtr); + @Override + public String getSessionName() { + return getSessionName(nativePtr); + } + + private native int[] getSentVideoSize(long nativePtr); + @Override + public VideoSize getSentVideoSize() { + int[] nativeSize = getSentVideoSize(nativePtr); + VideoSize vSize = new VideoSize(); + vSize.width = nativeSize[0]; + vSize.height = nativeSize[1]; + return vSize; + } + + private native int[] getReceivedVideoSize(long nativePtr); + @Override + public VideoSize getReceivedVideoSize() { + int[] nativeSize = getReceivedVideoSize(nativePtr); + VideoSize vSize = new VideoSize(); + vSize.width = nativeSize[0]; + vSize.height = nativeSize[1]; + return vSize; + } + private native void enableAudioMulticast(long ptr,boolean yesno); + @Override + public void enableAudioMulticast(boolean yesno) { + enableAudioMulticast(nativePtr,yesno); + } + private native boolean audioMulticastEnabled(long ptr); + @Override + public boolean audioMulticastEnabled() { + return audioMulticastEnabled(nativePtr); + } + private native void enableVideoMulticast(long ptr,boolean yesno); + @Override + public void enableVideoMulticast(boolean yesno) { + enableVideoMulticast(nativePtr,yesno); + } + private native boolean videoMulticastEnabled(long ptr); + @Override + public boolean videoMulticastEnabled() { + return videoMulticastEnabled(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneCallStatsImpl.java b/java/impl/org/linphone/core/LinphoneCallStatsImpl.java index 53fcb5ffd..4657ba01a 100644 --- a/java/impl/org/linphone/core/LinphoneCallStatsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallStatsImpl.java @@ -31,6 +31,9 @@ class LinphoneCallStatsImpl implements LinphoneCallStats { private float roundTripDelay; private long latePacketsCumulativeNumber; private float jitterBufferSize; + private float localLossRate; + private float localLateRate; + private long nativePtr; private native int getMediaType(long nativeStatsPtr); private native int getIceState(long nativeStatsPtr); @@ -43,8 +46,12 @@ class LinphoneCallStatsImpl implements LinphoneCallStats { private native float getRoundTripDelay(long nativeStatsPtr); private native long getLatePacketsCumulativeNumber(long nativeStatsPtr, long nativeCallPtr); private native float getJitterBufferSize(long nativeStatsPtr); + private native float getLocalLossRate(long nativeStatsPtr); + private native float getLocalLateRate(long nativeStatsPtr); + private native void updateStats(long nativeCallPtr, int mediaType); protected LinphoneCallStatsImpl(long nativeCallPtr, long nativeStatsPtr) { + nativePtr=nativeStatsPtr; mediaType = getMediaType(nativeStatsPtr); iceState = getIceState(nativeStatsPtr); downloadBandwidth = getDownloadBandwidth(nativeStatsPtr); @@ -56,6 +63,13 @@ class LinphoneCallStatsImpl implements LinphoneCallStats { roundTripDelay = getRoundTripDelay(nativeStatsPtr); latePacketsCumulativeNumber = getLatePacketsCumulativeNumber(nativeStatsPtr, nativeCallPtr); jitterBufferSize = getJitterBufferSize(nativeStatsPtr); + + } + + protected void updateRealTimeStats(LinphoneCall call){ + updateStats( ((LinphoneCallImpl)call).nativePtr, mediaType); + localLossRate=getLocalLossRate(nativePtr); + localLateRate=getLocalLateRate(nativePtr); } public MediaType getMediaType() { @@ -101,4 +115,12 @@ class LinphoneCallStatsImpl implements LinphoneCallStats { public float getJitterBufferSize() { return jitterBufferSize; } + + public float getLocalLossRate(){ + return localLossRate; + } + + public float getLocalLateRate(){ + return localLateRate; + } } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 1373708ca..8665e4049 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -1,42 +1,48 @@ package org.linphone.core; +import java.io.UnsupportedEncodingException; + public class LinphoneChatMessageImpl implements LinphoneChatMessage { protected final long nativePtr; - private native void setUserData(long ptr); - private native String getText(long ptr); + private native byte[] getText(long ptr); private native long getPeerAddress(long ptr); private native String getExternalBodyUrl(long ptr); 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); + private native void setFileTransferFilepath(long ptr, String path); + private native void downloadFile(long ptr); + private native void setListener(long ptr, LinphoneChatMessageListener listener); + private native void unref(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; - setUserData(); } public long getNativePtr() { return nativePtr; } - @Override - public Object getUserData() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setUserData() { - setUserData(nativePtr); - } - @Override public String getText() { - return getText(nativePtr); + byte rawText[]; + try { + rawText=getText(nativePtr); + if (rawText!=null) return new String(rawText, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; } @Override public LinphoneAddress getPeerAddress() { - return new LinphoneAddressImpl(getPeerAddress(nativePtr)); + return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } @Override @@ -51,7 +57,13 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { @Override public LinphoneAddress getFrom() { - return new LinphoneAddressImpl(getFrom(nativePtr)); + return new LinphoneAddressImpl(getFrom(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); + } + + private native long getTo(long ptr); + @Override + public LinphoneAddress getTo() { + return new LinphoneAddressImpl(getTo(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } private native void addCustomHeader(long nativePtr, String name, String value); @@ -64,4 +76,82 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public String getCustomHeader(String name) { return getCustomHeader(nativePtr,name); } + + 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); + } + + private native int getReason(long ptr); + + public Reason getReason() { + return Reason.fromInt(getReason(nativePtr)); + } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } + protected void finalize() throws Throwable{ + unref(nativePtr); + super.finalize(); + } + + private native Object getFileTransferInformation(long ptr); + @Override + public LinphoneContent getFileTransferInformation() { + return (LinphoneContent) getFileTransferInformation(nativePtr); + } + + private native void setAppData(long ptr, String data); + @Override + public void setAppData(String data) { + setAppData(nativePtr, data); + } + + private native String getAppData(long ptr); + @Override + public String getAppData() { + return getAppData(nativePtr); + } + + private native void cancelFileTransfer(long messagePtr); + @Override + public void cancelFileTransfer() { + cancelFileTransfer(nativePtr); + } + + @Override + public void setFileTransferFilepath(String path) { + setFileTransferFilepath(nativePtr, path); + } + + @Override + public void downloadFile() { + downloadFile(nativePtr); + } + + @Override + public void setListener(LinphoneChatMessageListener listener) { + setListener(nativePtr, listener); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 83141ad1c..7cf1fdbf7 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -18,35 +18,160 @@ 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; +@SuppressWarnings("deprecation") class LinphoneChatRoomImpl implements LinphoneChatRoom { protected final long nativePtr; private native long createLinphoneChatMessage(long ptr, String message); 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 void sendMessage2(long ptr, Object msg, long messagePtr, StateListener listener); + private native long[] getHistoryRange(long ptr, int begin, int end); + private native long[] getHistory(long ptr, int limit); + private native void destroy(long ptr); + private native int getUnreadMessagesCount(long ptr); + private native int getHistorySize(long ptr); + private native void deleteHistory(long ptr); + private native void compose(long ptr); + private native boolean isRemoteComposing(long ptr); + private native void markAsRead(long ptr); + private native void deleteMessage(long room, long message); + private native long createLinphoneChatMessage2(long ptr, String message, + String url, int state, long timestamp, boolean isRead, + boolean isIncoming); + private native void sendChatMessage(long ptr, Object message, long messagePtr); 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) { - sendMessage(nativePtr,message); + synchronized(getCore()){ + sendMessage(nativePtr,message); + } } - + @Override public void sendMessage(LinphoneChatMessage message, StateListener listener) { - sendMessage2(nativePtr, message.getNativePtr(), listener); - + synchronized(getCore()){ + sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener); + } } @Override public LinphoneChatMessage createLinphoneChatMessage(String message) { - return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); + synchronized(getCore()){ + return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); + } + } + + public LinphoneChatMessage[] getHistory() { + synchronized(getCore()){ + return getHistory(0); + } + } + + public LinphoneChatMessage[] getHistoryRange(int begin, int end) { + synchronized(getCore()){ + long[] typesPtr = getHistoryRange(nativePtr, begin, end); + return getHistoryPrivate(typesPtr); + } + } + + public LinphoneChatMessage[] getHistory(int limit) { + synchronized(getCore()){ + long[] typesPtr = getHistory(nativePtr, limit); + return getHistoryPrivate(typesPtr); + } + } + + public void destroy() { + destroy(nativePtr); + } + + public int getUnreadMessagesCount() { + synchronized(getCore()){ + return getUnreadMessagesCount(nativePtr); + } + } + + public int getHistorySize() { + synchronized(getCore()){ + return getHistorySize(nativePtr); + } + } + + public void deleteHistory() { + synchronized(getCore()){ + deleteHistory(nativePtr); + } + } + + public void compose() { + synchronized(getCore()){ + compose(nativePtr); + } + } + + public boolean isRemoteComposing() { + synchronized(getCore()){ + return isRemoteComposing(nativePtr); + } + } + + public void markAsRead() { + synchronized(getCore()){ + markAsRead(nativePtr); + } + } + + public void deleteMessage(LinphoneChatMessage message) { + synchronized(getCore()){ + if (message != null) + deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); + } + } + + @Override + public LinphoneChatMessage createLinphoneChatMessage(String message, + String url, State state, long timestamp, boolean isRead, + boolean isIncoming) { + synchronized(getCore()){ + return new LinphoneChatMessageImpl(createLinphoneChatMessage2( + nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + } + } + private native Object getCore(long nativePtr); + @Override + public synchronized LinphoneCore getCore() { + return (LinphoneCore)getCore(nativePtr); + } + private LinphoneChatMessage[] getHistoryPrivate(long[] typesPtr) { + 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; + } + + private native long createFileTransferMessage(long ptr, String name, String type, String subtype, int size); + @Override + public LinphoneChatMessage createFileTransferMessage(LinphoneContent content) { + synchronized(getCore()) { + return new LinphoneChatMessageImpl(createFileTransferMessage(nativePtr, content.getName(), content.getType(), content.getSubtype(), content.getRealSize())); + } + } + @Override + public void sendChatMessage(LinphoneChatMessage message) { + sendChatMessage(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr()); } } diff --git a/java/impl/org/linphone/core/LinphoneContentImpl.java b/java/impl/org/linphone/core/LinphoneContentImpl.java new file mode 100644 index 000000000..0231fd539 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneContentImpl.java @@ -0,0 +1,107 @@ +package org.linphone.core; + +public class LinphoneContentImpl implements LinphoneContent { + private String mType, mSubtype, mEncoding, mName; + private byte[] mData; + private int mExpectedSize; + + public LinphoneContentImpl(String type, String subtype, byte data[], String encoding){ + mType = type; + mSubtype = subtype; + mData = data; + mEncoding = encoding; + mName = null; + mExpectedSize = 0; + } + + public LinphoneContentImpl(String name, String type, String subtype, byte data[], String encoding, int expectedSize){ + mType = type; + mSubtype = subtype; + mData = data; + mEncoding = encoding; + mName = name; + mExpectedSize = expectedSize; + } + + @Override + public String getType() { + return mType; + } + + @Override + public String getSubtype() { + return mSubtype; + } + + @Override + public String getDataAsString() { + if (mData != null) + return new String(mData); + return null; + } + + @Override + public void setExpectedSize(int size) { + mExpectedSize = size; + } + + @Override + public int getExpectedSize() { + return mExpectedSize; + } + + @Override + public int getRealSize() { + if (mData != null) + return mData.length; + return 0; + } + + @Override + public void setType(String type) { + mType = type; + } + + @Override + public void setSubtype(String subtype) { + mSubtype = subtype; + } + + @Override + public void setStringData(String data) { + if (data != null) + mData = data.getBytes(); + else + mData = null; + } + + @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; + } + + @Override + public void setName(String name) { + mName = name; + } + + @Override + public String getName() { + return mName; + } +} diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 2e5c4cf59..0d6fc777b 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -20,8 +20,9 @@ package org.linphone.core; import java.io.File; import java.io.IOException; +import java.util.List; -import org.linphone.CpuUtils; +import org.linphone.mediastream.MediastreamerAndroidContext; import org.linphone.mediastream.Version; import android.util.Log; @@ -33,66 +34,46 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { System.loadLibrary(s); return true; } catch (Throwable e) { - Log.w("Unable to load optional library lib", s); + Log.w("LinphoneCoreFactoryImpl", "Unable to load optional library lib" + s); } return false; } static { - // FFMPEG (audio/video) - loadOptionalLibrary("avutil"); - loadOptionalLibrary("swscale"); - loadOptionalLibrary("avcore"); - - System.loadLibrary("neon"); - - if (!hasNeonInCpuFeatures()) { - boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon"); - if (!noNeonLibrariesLoaded) { - loadOptionalLibrary("avcodec"); + List cpuabis=Version.getCpuAbis(); + String ffmpegAbi; + boolean libLoaded=false; + Throwable firstException=null; + for (String abi : cpuabis){ + Log.i("LinphoneCoreFactoryImpl","Trying to load liblinphone for " + abi); + ffmpegAbi=abi; + // FFMPEG (audio/video) + if (abi.startsWith("armeabi")) { + ffmpegAbi="arm"; } - } else { - loadOptionalLibrary("avcodec"); - } - - // OPENSSL (cryptography) - // lin prefix avoids collision with libs in /system/lib - loadOptionalLibrary("lincrypto"); - loadOptionalLibrary("linssl"); - - // Secure RTP and key negotiation - loadOptionalLibrary("srtp"); - loadOptionalLibrary("zrtpcpp"); // GPLv3+ - - // Tunnel - loadOptionalLibrary("tunnelclient"); - - // g729 A implementation - loadOptionalLibrary("bcg729"); - - //Main library - if (!hasNeonInCpuFeatures()) { + loadOptionalLibrary("ffmpeg-linphone-"+ffmpegAbi); + //Main library try { - if (!isArmv7() && !Version.isX86()) { - System.loadLibrary("linphonearmv5"); - } else { - System.loadLibrary("linphonenoneon"); - } - Log.w("linphone", "No-neon liblinphone loaded"); - } catch (UnsatisfiedLinkError ule) { - Log.w("linphone", "Failed to load no-neon liblinphone, loading neon liblinphone"); - System.loadLibrary("linphone"); + System.loadLibrary("linphone-" + abi); + Log.i("LinphoneCoreFactoryImpl","Loading done with " + abi); + libLoaded=true; + break; + }catch(Throwable e) { + if (firstException == null) firstException=e; } - } else { - System.loadLibrary("linphone"); } - - Version.dumpCapabilities(); + + if (!libLoaded){ + throw new RuntimeException(firstException); + + }else{ + 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); } @@ -113,37 +94,40 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, - String userConfig, String factoryConfig, Object userdata) + String userConfig, String factoryConfig, Object userdata, Object context) throws LinphoneCoreException { try { - return new LinphoneCoreImpl(listener,new File(userConfig),new File(factoryConfig),userdata); + MediastreamerAndroidContext.setContext(context); + File user = userConfig == null ? null : new File(userConfig); + File factory = factoryConfig == null ? null : new File(factoryConfig); + LinphoneCore lc = new LinphoneCoreImpl(listener, user, factory, userdata); + if(context!=null) lc.setContext(context); + return lc; } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); } } @Override - public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException { + public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException { try { - return new LinphoneCoreImpl(listener); + MediastreamerAndroidContext.setContext(context); + LinphoneCore lc = new LinphoneCoreImpl(listener); + if(context!=null) lc.setContext(context); + return lc; } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); } } - @Override - public LinphoneProxyConfig createProxyConfig(String identity, String proxy, - String route, boolean enableRegister) throws LinphoneCoreException { - return new LinphoneProxyConfigImpl(identity,proxy,route,enableRegister); - } - @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 @@ -155,15 +139,58 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { public LinphoneFriend createLinphoneFriend() { return createLinphoneFriend(null); } - - public static boolean hasNeonInCpuFeatures() - { - CpuUtils cpu = new CpuUtils(); - return cpu.isCpuNeon(); - } + @Override + public native void enableLogCollection(boolean enable); + + @Override + public native void setLogCollectionPath(String path); + public static boolean isArmv7() { return System.getProperty("os.arch").contains("armv7"); } + + @Override + public LinphoneAuthInfo createAuthInfo(String username, String userid, + 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 == null ? null : 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 5a52f7559..3178e8d66 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -19,36 +19,42 @@ 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; import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCoreListener; import org.linphone.mediastream.Log; +import org.linphone.mediastream.Version; +import org.linphone.mediastream.video.AndroidVideoWindowImpl; import org.linphone.mediastream.video.capture.hwconf.Hacks; import android.content.Context; import android.media.AudioManager; - +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; +import android.net.wifi.WifiManager.WifiLock; class LinphoneCoreImpl implements LinphoneCore { private final LinphoneCoreListener mListener; //to make sure to keep a reference on this object - private long nativePtr = 0; + protected long nativePtr = 0; private Context mContext = null; private AudioManager mAudioManager = null; private boolean mSpeakerEnabled = false; private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata); private native void iterate(long nativePtr); - private native long getDefaultProxyConfig(long nativePtr); + private native LinphoneProxyConfig getDefaultProxyConfig(long nativePtr); 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 +77,12 @@ 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 boolean payloadTypeIsVbr(long nativePtr, long payloadType); + private native void enableAdaptiveRateControl(long nativePtr,boolean enable); + private native boolean isAdaptiveRateControlEnabled(long nativePtr); + private native String getAdaptiveRateAlgorithm(long nativePtr); + private native void setAdaptiveRateAlgorithm(long nativePtr, String alg); private native void enableEchoCancellation(long nativePtr,boolean enable); private native boolean isEchoCancellationEnabled(long nativePtr); private native Object getCurrentCall(long nativePtr) ; @@ -80,32 +92,46 @@ 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 LinphoneFriend[] getFriendList(long nativePtr); + 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); private native String getStunServer(long nativePtr); private native long createDefaultCallParams(long nativePtr); private native int updateCall(long ptrLc, long ptrCall, long ptrParams); + private native int getUploadBandwidth(long nativePtr); private native void setUploadBandwidth(long nativePtr, int bw); + private native int getDownloadBandwidth(long nativePtr); 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 void setRingback(long nativePtr, String path); private native long[] listVideoPayloadTypes(long nativePtr); - private native long[] getProxyConfigList(long nativePtr); + private native void setVideoCodecs(long nativePtr, long[] codecs); + private native LinphoneProxyConfig[] 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 setAudioCodecs(long nativePtr, long[] codecs); private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); private native int startEchoCalibration(long nativePtr,Object data); 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); @@ -129,19 +155,35 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setVideoPortRange(long nativePtr, int minPort, int maxPort); private native void setIncomingTimeout(long nativePtr, int timeout); private native void setInCallTimeout(long nativePtr, int timeout); + private native void setPrimaryContact2(long nativePtr, String contact); + private native String getPrimaryContact(long nativePtr); private native void setPrimaryContact(long nativePtr, String displayName, String username); - - LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { - mListener=listener; - nativePtr = newLinphoneCore(listener,userConfig.getCanonicalPath(),factoryConfig.getCanonicalPath(),userdata); + 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); + private native int migrateToMultiTransport(long nativePtr); + private native void setCallErrorTone(long nativePtr, int reason, String path); + private native void enableSdp200Ack(long nativePtr,boolean enable); + private native boolean isSdp200AckEnabled(long nativePtr); + private native void stopRinging(long nativePtr); + private native static void setAndroidPowerManager(Object pm); + private native void setAndroidWifiLock(long nativePtr,Object wifi_lock); + private native void setAndroidMulticastLock(long nativePtr,Object multicast_lock); + + 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); } - + protected void finalize() throws Throwable { - + if (nativePtr!=0) destroy(); } private boolean contextInitialized() { @@ -154,6 +196,19 @@ class LinphoneCoreImpl implements LinphoneCore { public void setContext(Object context) { mContext = (Context)context; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + setAndroidPowerManager(mContext.getSystemService(Context.POWER_SERVICE)); + if (Version.sdkAboveOrEqual(Version.API12_HONEYCOMB_MR1_31X)) { + WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + WifiLock lock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "linphonecore ["+ nativePtr+"] wifi-lock"); + lock.setReferenceCounted(true); + setAndroidWifiLock(nativePtr,lock); + } + if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) { + WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + MulticastLock lock = wifiManager.createMulticastLock("linphonecore ["+ nativePtr+"] multicast-lock"); + lock.setReferenceCounted(true); + setAndroidMulticastLock(nativePtr,lock); + } } public synchronized void addAuthInfo(LinphoneAuthInfo info) { @@ -161,14 +216,14 @@ 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); - if (lNativePtr!=0) { - return new LinphoneProxyConfigImpl(lNativePtr); - } else { - return null; - } + return getDefaultProxyConfig(nativePtr); } public synchronized LinphoneCall invite(String uri) { @@ -183,18 +238,23 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg) { isValid(); - setDefaultProxyConfig(nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr); + long proxyPtr=proxyCfg != null ? ((LinphoneProxyConfigImpl)proxyCfg).nativePtr : 0; + setDefaultProxyConfig(nativePtr, proxyPtr); } public synchronized void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException{ isValid(); if (addProxyConfig(proxyCfg,nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr) !=0) { throw new LinphoneCoreException("bad proxy config"); } + ((LinphoneProxyConfigImpl)proxyCfg).mCore=this; + } + 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 +270,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() { @@ -227,18 +287,18 @@ class LinphoneCoreImpl implements LinphoneCore { } public synchronized LinphoneCallLog[] getCallLogs() { isValid(); - LinphoneCallLog[] logs = new LinphoneCallLog[getNumberOfCallLogs(nativePtr)]; + LinphoneCallLog[] logs = new LinphoneCallLog[getNumberOfCallLogs(nativePtr)]; for (int i=0;i < getNumberOfCallLogs(nativePtr);i++) { logs[i] = new LinphoneCallLogImpl(getCallLog(nativePtr, i)); } return logs; } public synchronized void destroy() { - isValid(); + setAndroidPowerManager(null); delete(nativePtr); - nativePtr = 0; + nativePtr=0; } - + private void isValid() { if (nativePtr == 0) { throw new RuntimeException("object already destroyed"); @@ -249,7 +309,7 @@ class LinphoneCoreImpl implements LinphoneCore { } public synchronized void setPlaybackGain(float gain) { setPlaybackGain(nativePtr,gain); - + } public synchronized float getPlaybackGain() { return getPlaybackGain(nativePtr); @@ -261,12 +321,12 @@ 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+"]"); } } - public synchronized LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException { + public synchronized LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException { LinphoneCall call = (LinphoneCall)inviteAddress(nativePtr,((LinphoneAddressImpl)to).nativePtr); if (call!=null) { return call; @@ -299,8 +359,18 @@ class LinphoneCoreImpl implements LinphoneCore { if (enablePayloadType(nativePtr,((PayloadTypeImpl)pt).nativePtr,enable) != 0) { throw new LinphoneCoreException("cannot enable payload type ["+pt+"]"); } - + } + public synchronized boolean isPayloadTypeEnabled(PayloadType pt) { + isValid(); + return isPayloadTypeEnabled(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } + + public synchronized boolean payloadTypeIsVbr(PayloadType pt) { + isValid(); + return payloadTypeIsVbr(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } + public synchronized void enableEchoCancellation(boolean enable) { isValid(); enableEchoCancellation(nativePtr, enable); @@ -308,21 +378,21 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized boolean isEchoCancellationEnabled() { isValid(); return isEchoCancellationEnabled(nativePtr); - + } public synchronized LinphoneCall getCurrentCall() { isValid(); return (LinphoneCall)getCurrentCall(nativePtr); } - + public int getPlayLevel() { // TODO Auto-generated method stub return 0; } public void setPlayLevel(int level) { // TODO Auto-generated method stub - + } private void applyAudioHacks() { @@ -358,23 +428,37 @@ class LinphoneCoreImpl implements LinphoneCore { } public synchronized void playDtmf(char number, int duration) { playDtmf(nativePtr,number, duration); - + } public synchronized void stopDtmf() { stopDtmf(nativePtr); } - + public synchronized void addFriend(LinphoneFriend lf) throws LinphoneCoreException { 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 LinphoneFriend[] getFriendList() { + return getFriendList(nativePtr); } - public synchronized LinphoneChatRoom createChatRoom(String to) { - return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to)); + + @SuppressWarnings("deprecation") + public synchronized void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status) { + setPresenceInfo(nativePtr,minutes_away,alternative_contact,status.mValue); + + } + @SuppressWarnings("deprecation") + 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); @@ -385,13 +469,16 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void setDeviceRotation(int rotation) { setDeviceRotation(nativePtr, rotation); } - + public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) { enableVideo(nativePtr,vcap_enabled, display_enabled); } public synchronized boolean isVideoEnabled() { return isVideoEnabled(nativePtr); } + public synchronized boolean isVideoSupported() { + return isVideoSupported(nativePtr); + } public synchronized FirewallPolicy getFirewallPolicy() { return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr)); } @@ -404,15 +491,15 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void setStunServer(String stunServer) { setStunServer(nativePtr,stunServer); } - + public synchronized LinphoneCallParams createDefaultCallParameters() { return new LinphoneCallParamsImpl(createDefaultCallParams(nativePtr)); } - + public synchronized LinphoneCall inviteAddressWithParams(LinphoneAddress to, LinphoneCallParams params) throws LinphoneCoreException { long ptrDestination = ((LinphoneAddressImpl)to).nativePtr; long ptrParams =((LinphoneCallParamsImpl)params).nativePtr; - + LinphoneCall call = (LinphoneCall)inviteAddressWithParams(nativePtr, ptrDestination, ptrParams); if (call!=null) { return call; @@ -427,10 +514,19 @@ class LinphoneCoreImpl implements LinphoneCore { return updateCall(nativePtr, ptrCall, ptrParams); } + + public synchronized int getUploadBandwidth() { + return getUploadBandwidth(nativePtr); + } + public synchronized void setUploadBandwidth(int bw) { setUploadBandwidth(nativePtr, bw); } + public synchronized int getDownloadBandwidth() { + return getDownloadBandwidth(nativePtr); + } + public synchronized void setDownloadBandwidth(int bw) { setDownloadBandwidth(nativePtr, bw); } @@ -439,6 +535,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); @@ -453,28 +553,23 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized String getRing() { return getRing(nativePtr); } - + public synchronized void setRootCA(String path) { setRootCA(nativePtr, path); } - - public synchronized LinphoneProxyConfig[] getProxyConfigList() { - long[] typesPtr = getProxyConfigList(nativePtr); - if (typesPtr == null) return null; - - LinphoneProxyConfig[] proxies = new LinphoneProxyConfig[typesPtr.length]; - for (int i=0; i < proxies.length; i++) { - proxies[i] = new LinphoneProxyConfigImpl(typesPtr[i]); - } - - return proxies; + public synchronized void setRingback(String path) { + setRingback(nativePtr, path); } - + + public synchronized LinphoneProxyConfig[] getProxyConfigList() { + return getProxyConfigList(nativePtr); + } + public synchronized PayloadType[] getVideoCodecs() { long[] typesPtr = listVideoPayloadTypes(nativePtr); if (typesPtr == null) return null; - + PayloadType[] codecs = new PayloadType[typesPtr.length]; for (int i=0; i < codecs.length; i++) { @@ -483,10 +578,17 @@ class LinphoneCoreImpl implements LinphoneCore { return codecs; } + public synchronized void setVideoCodecs(PayloadType[] codecs) { + long[] typesPtr = new long[codecs.length]; + for (int i=0; i < codecs.length; i++) { + typesPtr[i] = ((PayloadTypeImpl)codecs[i]).nativePtr; + } + setVideoCodecs(nativePtr, typesPtr); + } public synchronized PayloadType[] getAudioCodecs() { long[] typesPtr = listAudioPayloadTypes(nativePtr); if (typesPtr == null) return null; - + PayloadType[] codecs = new PayloadType[typesPtr.length]; for (int i=0; i < codecs.length; i++) { @@ -495,21 +597,28 @@ class LinphoneCoreImpl implements LinphoneCore { return codecs; } + public synchronized void setAudioCodecs(PayloadType[] codecs) { + long[] typesPtr = new long[codecs.length]; + for (int i=0; i < codecs.length; i++) { + typesPtr[i] = ((PayloadTypeImpl)codecs[i]).nativePtr; + } + setAudioCodecs(nativePtr, typesPtr); + } public synchronized boolean isNetworkReachable() { return isNetworkStateReachable(nativePtr); } - + public synchronized void enableKeepAlive(boolean enable) { enableKeepAlive(nativePtr,enable); - + } public synchronized boolean isKeepAliveEnabled() { return isKeepAliveEnabled(nativePtr); } - public synchronized void startEchoCalibration(Object data) throws LinphoneCoreException { - startEchoCalibration(nativePtr, data); + public synchronized void startEchoCalibration(LinphoneCoreListener listener) throws LinphoneCoreException { + startEchoCalibration(nativePtr, listener); } - + public synchronized Transports getSignalingTransportPorts() { Transports transports = new Transports(); transports.udp = getSignalingTransportPort(nativePtr, 0); @@ -526,6 +635,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(). } @@ -541,7 +653,7 @@ class LinphoneCoreImpl implements LinphoneCore { } public synchronized void setDownloadPtime(int ptime) { setDownloadPtime(nativePtr,ptime); - + } public synchronized void setUploadPtime(int ptime) { setUploadPtime(nativePtr,ptime); @@ -553,23 +665,23 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void enableEchoLimiter(boolean val) { enableEchoLimiter(nativePtr,val); } - public void setVideoDevice(int id) { + public synchronized void setVideoDevice(int id) { Log.i("Setting camera id :", id); if (setVideoDevice(nativePtr, id) != 0) { Log.e("Failed to set video device to id:", id); } } - public int getVideoDevice() { + public synchronized int getVideoDevice() { return getVideoDevice(nativePtr); } - private native void leaveConference(long nativePtr); + private native void leaveConference(long nativePtr); public synchronized void leaveConference() { leaveConference(nativePtr); } - private native boolean enterConference(long nativePtr); + private native boolean enterConference(long nativePtr); public synchronized boolean enterConference() { return enterConference(nativePtr); } @@ -607,12 +719,12 @@ class LinphoneCoreImpl implements LinphoneCore { private native void addAllToConference(long nativePtr); public synchronized void addAllToConference() { addAllToConference(nativePtr); - + } private native void addToConference(long nativePtr, long nativePtrLcall); public synchronized void addToConference(LinphoneCall call) { addToConference(nativePtr, getCallPtr(call)); - + } private native void removeFromConference(long nativePtr, long nativeCallPtr); public synchronized void removeFromConference(LinphoneCall call) { @@ -622,7 +734,7 @@ class LinphoneCoreImpl implements LinphoneCore { private long getCallPtr(LinphoneCall call) { return ((LinphoneCallImpl)call).nativePtr; } - + private long getCallParamsPtr(LinphoneCallParams callParams) { return ((LinphoneCallParamsImpl)callParams).nativePtr; } @@ -650,7 +762,7 @@ class LinphoneCoreImpl implements LinphoneCore { return isMediaEncryptionMandatory(nativePtr); } public synchronized void setMediaEncryption(MediaEncryption menc) { - setMediaEncryption(nativePtr, menc.mValue); + setMediaEncryption(nativePtr, menc.mValue); } public synchronized void setMediaEncryptionMandatory(boolean yesno) { setMediaEncryptionMandatory(nativePtr, yesno); @@ -702,6 +814,18 @@ class LinphoneCoreImpl implements LinphoneCore { tunnelAddServerAndMirror(nativePtr, host, port, mirror, ms); } + private native void tunnelAddServer(long nativePtr, TunnelConfig config); + @Override + public synchronized void tunnelAddServer(TunnelConfig config) { + tunnelAddServer(nativePtr, config); + } + + private native final TunnelConfig[] tunnelGetServers(long nativePtr); + @Override + public synchronized final TunnelConfig[] tunnelGetServers() { + return tunnelGetServers(nativePtr); + } + private native void tunnelAutoDetect(long nativePtr); @Override public synchronized void tunnelAutoDetect() { @@ -719,10 +843,34 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void tunnelEnable(boolean enable) { tunnelEnable(nativePtr, enable); } + + private native void tunnelSetMode(long nativePtr, int mode); + @Override + public synchronized void tunnelSetMode(LinphoneCore.TunnelMode mode) { + tunnelSetMode(nativePtr, TunnelMode.enumToInt(mode)); + } + + private native int tunnelGetMode(long nativePtr); + @Override + public synchronized LinphoneCore.TunnelMode tunnelGetMode() { + return LinphoneCore.TunnelMode.intToEnum(tunnelGetMode(nativePtr)); + } + + private native void tunnelEnableSip(long nativePtr, boolean enable); + @Override + public void tunnelEnableSip(boolean enable) { + tunnelEnableSip(nativePtr, enable); + } + + private native boolean tunnelSipEnabled(long nativePtr); + @Override + public boolean tunnelSipEnabled() { + return tunnelSipEnabled(nativePtr); + } @Override public native boolean isTunnelAvailable(); - + private native void acceptCallWithParams(long nativePtr, long aCall, long params); @Override @@ -730,14 +878,14 @@ class LinphoneCoreImpl implements LinphoneCore { LinphoneCallParams params) throws LinphoneCoreException { acceptCallWithParams(nativePtr, getCallPtr(aCall), getCallParamsPtr(params)); } - + private native void acceptCallUpdate(long nativePtr, long aCall, long params); @Override public synchronized void acceptCallUpdate(LinphoneCall aCall, LinphoneCallParams params) throws LinphoneCoreException { - acceptCallUpdate(nativePtr, getCallPtr(aCall), getCallParamsPtr(params)); + acceptCallUpdate(nativePtr, getCallPtr(aCall), getCallParamsPtr(params)); } - + private native void deferCallUpdate(long nativePtr, long aCall); @Override public synchronized void deferCallUpdate(LinphoneCall aCall) @@ -745,17 +893,20 @@ class LinphoneCoreImpl implements LinphoneCore { deferCallUpdate(nativePtr, getCallPtr(aCall)); } - public synchronized void startRinging() { - if (!contextInitialized()) return; - if (Hacks.needGalaxySAudioHack()) { - mAudioManager.setMode(MODE_RINGTONE); - } - } - + private native void setVideoPolicy(long nativePtr, boolean autoInitiate, boolean autoAccept); 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); @@ -771,11 +922,11 @@ class LinphoneCoreImpl implements LinphoneCore { { setCpuCountNative(count); } - + public synchronized int getMissedCallsCount() { return getMissedCallsCount(nativePtr); } - + public synchronized void removeCallLog(LinphoneCallLog log) { removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr()); } @@ -783,90 +934,119 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void resetMissedCallsCount() { resetMissedCallsCount(nativePtr); } - + private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port, String username, String password); @Override - public void tunnelSetHttpProxy(String proxy_host, int port, + public synchronized void tunnelSetHttpProxy(String proxy_host, int port, String username, String password) { tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password); } - + private native void refreshRegisters(long nativePtr); public synchronized void refreshRegisters() { refreshRegisters(nativePtr); } - + @Override public String getVersion() { return getVersion(nativePtr); } - + /** + * Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algorithm + */ + static int FIND_PAYLOAD_IGNORE_RATE = -1; + /** + * Wildcard value used by #linphone_core_find_payload_type to ignore channel in search algorithm + */ + static int FIND_PAYLOAD_IGNORE_CHANNELS = -1; @Override public synchronized PayloadType findPayloadType(String mime, int clockRate) { - return findPayloadType(mime, clockRate, 1); + return findPayloadType(mime, clockRate, FIND_PAYLOAD_IGNORE_CHANNELS); } - + private native void removeFriend(long ptr, long lf); @Override public synchronized void removeFriend(LinphoneFriend lf) { removeFriend(nativePtr, lf.getNativePtr()); } - - private native long getFriendByAddress(long ptr, String sipUri); + + private native LinphoneFriend getFriendByAddress(long ptr, String sipUri); @Override public synchronized LinphoneFriend findFriendByAddress(String sipUri) { - long ptr = getFriendByAddress(nativePtr, sipUri); - if (ptr == 0) { - return null; - } - return new LinphoneFriendImpl(ptr); + return getFriendByAddress(nativePtr, sipUri); } - + public synchronized void setAudioPort(int port) { setAudioPort(nativePtr, port); } - + public synchronized void setVideoPort(int port) { setVideoPort(nativePtr, port); } - + public synchronized void setAudioPortRange(int minPort, int maxPort) { setAudioPortRange(nativePtr, minPort, maxPort); } - + public synchronized void setVideoPortRange(int minPort, int maxPort) { setVideoPortRange(nativePtr, minPort, maxPort); } - + public synchronized void setIncomingTimeout(int timeout) { setIncomingTimeout(nativePtr, timeout); } - + public synchronized void setInCallTimeout(int timeout) { setInCallTimeout(nativePtr, timeout); } - + private native void setMicrophoneGain(long ptr, float gain); public synchronized void setMicrophoneGain(float gain) { setMicrophoneGain(nativePtr, gain); } - + + public synchronized void setPrimaryContact(String address) { + setPrimaryContact2(nativePtr, address); + } + + public synchronized String getPrimaryContact() { + return getPrimaryContact(nativePtr); + } + public synchronized void setPrimaryContact(String displayName, String username) { 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() { long configPtr=getConfig(nativePtr); @@ -877,35 +1057,449 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized boolean needsEchoCalibration() { return needsEchoCalibration(nativePtr); } + private native boolean hasBuiltInEchoCanceler(long ptr); + @Override + public synchronized boolean hasBuiltInEchoCanceler() { + return hasBuiltInEchoCanceler(nativePtr); + } private native void declineCall(long coreptr, long callptr, int reason); @Override public synchronized void declineCall(LinphoneCall aCall, Reason reason) { declineCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr,reason.mValue); } - + private native boolean upnpAvailable(long ptr); - public boolean upnpAvailable() { + public synchronized boolean upnpAvailable() { return upnpAvailable(nativePtr); - } + } private native int getUpnpState(long ptr); - public UpnpState getUpnpState() { - return UpnpState.fromInt(getUpnpState(nativePtr)); + public synchronized UpnpState getUpnpState() { + return UpnpState.fromInt(getUpnpState(nativePtr)); } - + private native String getUpnpExternalIpaddress(long ptr); - public String getUpnpExternalIpaddress() { + public synchronized String getUpnpExternalIpaddress() { return getUpnpExternalIpaddress(nativePtr); } private native int startConferenceRecording(long nativePtr, String path); @Override - public void startConferenceRecording(String path) { + public synchronized void startConferenceRecording(String path) { startConferenceRecording(nativePtr,path); } - + private native int stopConferenceRecording(long nativePtr); @Override - public void stopConferenceRecording() { + public synchronized void stopConferenceRecording() { stopConferenceRecording(nativePtr); } + @Override + public synchronized PayloadType findPayloadType(String mime) { + return findPayloadType(mime, FIND_PAYLOAD_IGNORE_RATE); + } + + private native void setSipDscp(long nativePtr, int dscp); + @Override + public synchronized void setSipDscp(int dscp) { + setSipDscp(nativePtr,dscp); + } + + private native int getSipDscp(long nativePtr); + @Override + public synchronized int getSipDscp() { + return getSipDscp(nativePtr); + } + private native void setAudioDscp(long nativePtr, int dscp); + @Override + public synchronized void setAudioDscp(int dscp) { + setAudioDscp(nativePtr, dscp); + } + + private native int getAudioDscp(long nativePtr); + @Override + public synchronized int getAudioDscp() { + return getAudioDscp(nativePtr); + } + + private native void setVideoDscp(long nativePtr, int dscp); + @Override + public synchronized void setVideoDscp(int dscp) { + setVideoDscp(nativePtr,dscp); + } + + private native int getVideoDscp(long nativePtr); + @Override + public synchronized int getVideoDscp() { + return getVideoDscp(nativePtr); + } + + private native long createInfoMessage(long nativeptr); + @Override + public synchronized 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 synchronized 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 synchronized 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); + } + + private native Object createSubscribe(long core, long addr, String event, int expires); + @Override + public synchronized LinphoneEvent createSubscribe(LinphoneAddress resource, + String event, int expires) { + return (LinphoneEvent)createSubscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); + } + private native Object createPublish(long core, long addr, String event, int expires); + @Override + public synchronized LinphoneEvent createPublish(LinphoneAddress resource, + String event, int expires) { + return (LinphoneEvent)createPublish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); + } + + public synchronized 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 synchronized 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 synchronized LinphoneAuthInfo findAuthInfo(String username, String realm, String domain) { + long ptr = findAuthInfos(nativePtr, username, realm, domain); + if (ptr == 0) + return null; + + return new LinphoneAuthInfoImpl(ptr); + } + private native LinphoneCall startReferedCall(long corePtr, long callptr, long paramsPtr); + @Override + public synchronized LinphoneCall startReferedCall(LinphoneCall call, + LinphoneCallParams params) { + long ptrParams =((LinphoneCallParamsImpl)params).nativePtr; + return startReferedCall(nativePtr, getCallPtr(call), ptrParams); + } + + private native String[] listSupportedVideoResolutions(long ptr); + @Override + public synchronized String[] getSupportedVideoSizes() { + return listSupportedVideoResolutions(nativePtr); + } + + @Override + public synchronized int migrateToMultiTransport() { + return migrateToMultiTransport(nativePtr); + } + + private native boolean acceptEarlyMedia(long lc, long call); + @Override + public synchronized boolean acceptEarlyMedia(LinphoneCall call) { + return acceptEarlyMedia(nativePtr, getCallPtr(call)); + } + + private native boolean acceptEarlyMediaWithParams(long lc, long call, long params); + @Override + public synchronized boolean acceptEarlyMediaWithParams(LinphoneCall call, + LinphoneCallParams params) { + long ptrParams = params != null ? ((LinphoneCallParamsImpl) params).nativePtr : 0; + return acceptEarlyMediaWithParams(nativePtr, getCallPtr(call), ptrParams); + } + @Override + public synchronized LinphoneProxyConfig createProxyConfig() { + return new LinphoneProxyConfigImpl(this); + } + @Override + public synchronized LinphoneProxyConfig createProxyConfig(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException { + isValid(); + try { + return new LinphoneProxyConfigImpl(this,identity,proxy,route,enableRegister); + } catch(LinphoneCoreException e){ + return null; + } + } + @Override + public synchronized void setCallErrorTone(Reason reason, String path) { + setCallErrorTone(nativePtr, reason.mValue, path); + } + private native void setMtu(long nativePtr, int mtu); + @Override + public synchronized void setMtu(int mtu) { + setMtu(nativePtr,mtu); + } + private native int getMtu(long nativePtr); + @Override + public synchronized int getMtu() { + return getMtu(nativePtr); + } + @Override + public synchronized void enableSdp200Ack(boolean enable) { + enableSdp200Ack(nativePtr,enable); + } + @Override + public synchronized boolean isSdp200AckEnabled() { + return isSdp200AckEnabled(nativePtr); + } + private native void setTone(long nativePtr, int id, String wavfile); + @Override + public synchronized void setTone(ToneID id, String wavfile) { + setTone(nativePtr, id.mValue, wavfile); + } + private native void disableChat(long ptr, int denycode); + @Override + public synchronized void disableChat(Reason denycode) { + disableChat(nativePtr,denycode.mValue); + } + private native void enableChat(long ptr); + @Override + public synchronized void enableChat() { + enableChat(nativePtr); + } + private native boolean chatEnabled(long ptr); + @Override + public synchronized boolean chatEnabled() { + return chatEnabled(nativePtr); + } + + @Override + public synchronized void stopRinging() { + stopRinging(nativePtr); + } + private native void setPayloadTypeBitrate(long coreptr, long payload_ptr, int bitrate); + @Override + public synchronized void setPayloadTypeBitrate(PayloadType pt, int bitrate) { + setPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr, bitrate); + } + private native int getPayloadTypeBitrate(long coreptr, long payload_ptr); + @Override + public synchronized int getPayloadTypeBitrate(PayloadType pt) { + return getPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } + + private native void setPayloadTypeNumber(long coreptr, long payload_ptr, int number); + @Override + public synchronized void setPayloadTypeNumber(PayloadType pt, int number) { + setPayloadTypeNumber(nativePtr, ((PayloadTypeImpl)pt).nativePtr, number); + } + private native int getPayloadTypeNumber(long coreptr, long payload_ptr); + @Override + public synchronized int getPayloadTypeNumber(PayloadType pt) { + return getPayloadTypeNumber(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } + + @Override + public synchronized void enableAdaptiveRateControl(boolean enable) { + enableAdaptiveRateControl(nativePtr,enable); + + } + @Override + public synchronized boolean isAdaptiveRateControlEnabled() { + return isAdaptiveRateControlEnabled(nativePtr); + } + public synchronized AdaptiveRateAlgorithm getAdaptiveRateAlgorithm() { + return AdaptiveRateAlgorithm.fromString(getAdaptiveRateAlgorithm(nativePtr)); + } + public synchronized void setAdaptiveRateAlgorithm(AdaptiveRateAlgorithm alg) { + setAdaptiveRateAlgorithm(nativePtr, alg.toString()); + } + + + private native void setAudioJittcomp(long ptr, int value); + @Override + public synchronized void setAudioJittcomp(int value) { + setAudioJittcomp(nativePtr,value); + } + private native void setVideoJittcomp(long ptr, int value); + @Override + public synchronized void setVideoJittcomp(int value) { + setVideoJittcomp(nativePtr,value); + } + + private native void setFileTransferServer(long ptr, String serverUrl); + @Override + public synchronized void setFileTransferServer(String serverUrl) { + setFileTransferServer(nativePtr, serverUrl); + } + + private native String getFileTransferServer(long ptr); + @Override + public synchronized String getFileTransferServer() { + return getFileTransferServer(nativePtr); + } + + private native long createLocalPlayer(long nativePtr, AndroidVideoWindowImpl window); + @Override + public synchronized LinphonePlayer createLocalPlayer(AndroidVideoWindowImpl window) { + long playerPtr = createLocalPlayer(nativePtr, window); + if(playerPtr != 0) { + return new LinphonePlayerImpl(playerPtr); + } else { + return null; + } + } + + private native void addListener(long nativePtr, LinphoneCoreListener listener); + @Override + public void addListener(LinphoneCoreListener listener) { + addListener(nativePtr, listener); + } + + private native void removeListener(long nativePtr, LinphoneCoreListener listener); + @Override + public void removeListener(LinphoneCoreListener listener) { + removeListener(nativePtr, listener); + } + private native void setRemoteRingbackTone(long nativePtr, String file); + @Override + public void setRemoteRingbackTone(String file) { + setRemoteRingbackTone(nativePtr,file); + } + private native String getRemoteRingbackTone(long nativePtr); + @Override + public String getRemoteRingbackTone() { + return getRemoteRingbackTone(nativePtr); + } + + private native void uploadLogCollection(long nativePtr); + @Override + public void uploadLogCollection() { + uploadLogCollection(nativePtr); + } + + @Override + public native void resetLogCollection(); + + private native void setPreferredFramerate(long nativePtr, float fps); + @Override + public void setPreferredFramerate(float fps) { + setPreferredFramerate(nativePtr,fps); + } + private native float getPreferredFramerate(long nativePtr); + @Override + public float getPreferredFramerate() { + return getPreferredFramerate(nativePtr); + } + + + private native int setAudioMulticastAddr(long nativePtr, String ip); + @Override + public void setAudioMulticastAddr(String ip) throws LinphoneCoreException { + if (setAudioMulticastAddr(nativePtr, ip)!=0) + throw new LinphoneCoreException("bad ip address ["+ip+"]"); + } + private native int setVideoMulticastAddr(long nativePtr, String ip); + @Override + public void setVideoMulticastAddr(String ip) throws LinphoneCoreException { + if (setVideoMulticastAddr(nativePtr, ip)!=0) + throw new LinphoneCoreException("bad ip address ["+ip+"]"); + } + private native String getAudioMulticastAddr(long ptr); + @Override + public String getAudioMulticastAddr() { + return getAudioMulticastAddr(nativePtr) ; + } + private native String getVideoMulticastAddr(long ptr); + @Override + public String getVideoMulticastAddr() { + return getVideoMulticastAddr(nativePtr); + } + private native int setAudioMulticastTtl(long ptr,int ttl); + @Override + public void setAudioMulticastTtl(int ttl) throws LinphoneCoreException { + if (setAudioMulticastTtl(nativePtr, ttl)!=0) + throw new LinphoneCoreException("bad ttl value ["+ttl+"]"); + + } + private native int setVideoMulticastTtl(long ptr,int ttl); + @Override + public void setVideoMulticastTtl(int ttl) throws LinphoneCoreException { + if (setVideoMulticastTtl(nativePtr, ttl)!=0) + throw new LinphoneCoreException("bad ttl value ["+ttl+"]"); + } + private native int getAudioMulticastTtl(long ptr); + @Override + public int getAudioMulticastTtl() { + return getAudioMulticastTtl(nativePtr); + } + private native int getVideoMulticastTtl(long ptr); + @Override + public int getVideoMulticastTtl() { + return getVideoMulticastTtl(nativePtr); + } + private native void enableAudioMulticast(long ptr,boolean yesno); + @Override + public void enableAudioMulticast(boolean yesno) { + enableAudioMulticast(nativePtr,yesno); + } + private native boolean audioMulticastEnabled(long ptr); + @Override + public boolean audioMulticastEnabled() { + return audioMulticastEnabled(nativePtr); + } + private native void enableVideoMulticast(long ptr,boolean yesno); + + @Override + public void enableVideoMulticast(boolean yesno) { + enableVideoMulticast(nativePtr,yesno); + } + private native boolean videoMulticastEnabled(long ptr); + @Override + public boolean videoMulticastEnabled() { + return videoMulticastEnabled(nativePtr); + } + + private native void enableDnsSrv(long ptr, boolean yesno); + @Override + public void enableDnsSrv(boolean yesno) { + enableDnsSrv(nativePtr, yesno); + } + private native boolean dnsSrvEnabled(long ptr); + @Override + public boolean dnsSrvEnabled() { + return dnsSrvEnabled(nativePtr); + } + + private native void setVideoPreset(long nativePtr, String preset); + @Override + public void setVideoPreset(String preset) { + setVideoPreset(nativePtr, preset); + } + + private native String getVideoPreset(long nativePtr); + @Override + public String getVideoPreset() { + return getVideoPreset(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java new file mode 100644 index 000000000..c78b5da40 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -0,0 +1,149 @@ +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 synchronized String getEventName() { + return getEventName(mNativePtr); + } + + private native int acceptSubscription(long nativeptr); + @Override + public synchronized void acceptSubscription() { + synchronized(getCore()){ + acceptSubscription(mNativePtr); + } + } + + private native int denySubscription(long nativeptr, int reason); + @Override + public synchronized void denySubscription(Reason reason) { + synchronized(getCore()){ + denySubscription(mNativePtr,reason.mValue); + } + } + + private native int notify(long nativeptr, String type, String subtype, byte data[], String encoding); + @Override + public void notify(LinphoneContent content) { + synchronized(getCore()){ + 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) { + synchronized(getCore()){ + 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) { + synchronized(getCore()){ + updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + } + } + + private native int terminate(long nativePtr); + @Override + public void terminate() { + synchronized(getCore()){ + terminate(mNativePtr); + } + } + + private native int getReason(long nativePtr); + @Override + public synchronized Reason getReason() { + return Reason.fromInt(getReason(mNativePtr)); + } + + @Override + public synchronized void setUserContext(Object obj) { + mUserContext=obj; + } + + @Override + public synchronized Object getUserContext() { + return mUserContext; + } + + private native int getSubscriptionDir(long nativeptr); + @Override + public synchronized SubscriptionDir getSubscriptionDir() { + return SubscriptionDir.fromInt(getSubscriptionDir(mNativePtr)); + } + + private native int getSubscriptionState(long nativeptr); + @Override + public synchronized 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); + } + + private native void addCustomHeader(long ptr, String name, String value); + @Override + public synchronized void addCustomHeader(String name, String value) { + addCustomHeader(mNativePtr, name, value); + } + + private native String getCustomHeader(long ptr, String name); + @Override + public synchronized String getCustomHeader(String name) { + return getCustomHeader(mNativePtr, name); + } + + private native void sendSubscribe(long ptr, String type, String subtype, byte data [], String encoding); + @Override + public void sendSubscribe(LinphoneContent body) { + synchronized(getCore()){ + if (body != null) + sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendSubscribe(mNativePtr, null, null, null, null); + } + } + + private native void sendPublish(long ptr, String type, String subtype, byte data [], String encoding); + @Override + public void sendPublish(LinphoneContent body) { + synchronized(getCore()){ + if (body != null) + sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendPublish(mNativePtr, null, null, null, null); + } + } + private native long getErrorInfo(long nativePtr); + @Override + public synchronized ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(mNativePtr)); + } + + private native Object getCore(long nativePtr); + @Override + public synchronized LinphoneCore getCore() { + return (LinphoneCore)getCore(mNativePtr); + } + +} diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index 6e7aa2db1..ba47eccb4 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -22,6 +22,7 @@ import java.io.Serializable; class LinphoneFriendImpl implements LinphoneFriend, Serializable { protected final long nativePtr; + private native void finalize(long nativePtr); private native long newLinphoneFriend(String friendUri); private native void setAddress(long nativePtr,long friend); private native long getAddress(long nativePtr); @@ -30,38 +31,49 @@ 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); - - private native void delete(long ptr); - boolean ownPtr = false; + private native Object getCore(long ptr); + private native void setRefKey(long nativePtr, String key); + private native String getRefKey(long nativePtr); + protected LinphoneFriendImpl() { nativePtr = newLinphoneFriend(null); - } + } protected LinphoneFriendImpl(String friendUri) { nativePtr = newLinphoneFriend(friendUri); } + + /*reserved for JNI */ protected LinphoneFriendImpl(long aNativePtr) { nativePtr = aNativePtr; - ownPtr=false; } protected void finalize() throws Throwable { - if (ownPtr) delete(nativePtr); + if (nativePtr != 0) { + finalize(nativePtr); + } + super.finalize(); } public void setAddress(LinphoneAddress anAddress) { 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); + synchronized(getSyncObject()){ + setIncSubscribePolicy(nativePtr,policy.mValue); + } } public SubscribePolicy getIncSubscribePolicy() { return SubscribePolicy.fromInt(getIncSubscribePolicy(nativePtr)) ; } public void enableSubscribes(boolean enable) { - enableSubscribes(nativePtr, enable); + synchronized(getSyncObject()){ + enableSubscribes(nativePtr, enable); + } } public boolean isSubscribesEnabled() { return isSubscribesEnabled(nativePtr); @@ -69,13 +81,41 @@ 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); + synchronized(getSyncObject()){ + edit(nativePtr); + } } public void done() { - done(nativePtr); + synchronized(getSyncObject()){ + done(nativePtr); + } } public long getNativePtr() { return nativePtr; } + + /* + * Returns a java object to synchronize this friend with. + * Indeed some operation must be synchronized with the LinphoneCore object. + * If the friend is not associated with a LinphoneCore object, it returns itself in order to avoid writing code for case where no synchronization is necessary. + */ + private Object getSyncObject(){ + Object core=getCore(nativePtr); + if (core!=null) return core; + else return this; + } + + public void setRefKey(String key){ + synchronized(getSyncObject()){ + setRefKey(nativePtr,key); + } + } + + public String getRefKey(){ + return getRefKey(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/LinphonePlayerImpl.java b/java/impl/org/linphone/core/LinphonePlayerImpl.java new file mode 100644 index 000000000..fe486321e --- /dev/null +++ b/java/impl/org/linphone/core/LinphonePlayerImpl.java @@ -0,0 +1,70 @@ +/** + * + */ +package org.linphone.core; + +/** + * @author François Grisez + * + */ +public class LinphonePlayerImpl implements LinphonePlayer { + private long nativePtr = 0; + + LinphonePlayerImpl(long nativePtr) { + this.nativePtr = nativePtr; + } + + private native int open(long nativePtr, String filename, Listener listener); + @Override + public synchronized int open(String filename, Listener listener) { + return open(nativePtr, filename, listener); + } + + private native int start(long nativePtr); + @Override + public synchronized int start() { + return start(nativePtr); + } + + private native int pause(long nativePtr); + @Override + public synchronized int pause() { + return pause(nativePtr); + } + + private native int seek(long nativePtr, int timeMs); + @Override + public synchronized int seek(int timeMs) { + return seek(nativePtr, timeMs); + } + + private native int getState(long nativePtr); + @Override + public synchronized State getState() { + return LinphonePlayer.State.fromValue(getState(nativePtr)); + } + + private native int getDuration(long nativePtr); + @Override + public synchronized int getDuration() { + return getDuration(nativePtr); + } + + private native int getCurrentPosition(long nativePtr); + @Override + public synchronized int getCurrentPosition() { + return getCurrentPosition(nativePtr); + } + + private native void close(long nativePtr); + @Override + public synchronized void close() { + close(nativePtr); + } + + private native void destroy(long nativePtr); + @Override + protected void finalize() { + destroy(nativePtr); + } +} diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 649d46fe3..33ac36f8f 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -15,147 +15,365 @@ 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; import org.linphone.core.LinphoneCore.RegistrationState; - - - - class LinphoneProxyConfigImpl implements LinphoneProxyConfig { protected final long nativePtr; + protected LinphoneCoreImpl mCore; + Object userData; + private native void finalize(long ptr); private native int getState(long nativePtr); private native void setExpires(long nativePtr, int delay); + private native int getExpires(long nativePtr); + private native long createProxyConfig( long nativePtr); - boolean ownPtr = false; - protected LinphoneProxyConfigImpl(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException { - nativePtr = newLinphoneProxyConfig(); + protected LinphoneProxyConfigImpl(LinphoneCoreImpl core,String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException { + mCore=core; + nativePtr = createProxyConfig(core.nativePtr); setIdentity(identity); setProxy(proxy); + setRoute(route); enableRegister(enableRegister); - ownPtr=true; } - protected LinphoneProxyConfigImpl(long aNativePtr) { + + protected LinphoneProxyConfigImpl(LinphoneCoreImpl core) { + mCore=core; + nativePtr = createProxyConfig(core.nativePtr); + } + /*reserved for JNI */ + protected LinphoneProxyConfigImpl(LinphoneCoreImpl core, long aNativePtr) { + mCore=core; nativePtr = aNativePtr; - ownPtr=false; } + + private void isValid() { + if (nativePtr == 0) { + throw new RuntimeException("proxy config removed"); + } + } + protected void finalize() throws Throwable { - //Log.e(LinphoneService.TAG,"fixme, should release underlying proxy config"); - if (ownPtr) delete(nativePtr); + if (nativePtr != 0) { + finalize(nativePtr); + } + super.finalize(); } private native long newLinphoneProxyConfig(); - private native void delete(long ptr); private native void edit(long ptr); private native void done(long ptr); - + private native void setIdentity(long ptr,String identity); private native String getIdentity(long ptr); private native int setProxy(long ptr,String proxy); private native String getProxy(long ptr); - + private native void enableRegister(long ptr,boolean value); private native boolean isRegisterEnabled(long ptr); - + 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); private native void enablePublish(long ptr,boolean enable); private native boolean publishEnabled(long ptr); private native void setContactParameters(long ptr, String params); - + private native int lookupCCCFromIso(long nativePtr, String iso); private native int lookupCCCFromE164(long nativePtr, String e164); - - public void enableRegister(boolean value) { + + public LinphoneProxyConfig enableRegister(boolean value) { + isValid(); enableRegister(nativePtr,value); + return this; } public void done() { - done(nativePtr); + isValid(); + Object mutex=mCore!=null ? mCore : this; + synchronized(mutex){ + done(nativePtr); + } } - public void edit() { - edit(nativePtr); + public LinphoneProxyConfig edit() { + isValid(); + Object mutex=mCore!=null ? mCore : this; + synchronized(mutex){ + edit(nativePtr); + } + return this; } public void setIdentity(String identity) throws LinphoneCoreException { + isValid(); setIdentity(nativePtr,identity); } public void setProxy(String proxyUri) throws LinphoneCoreException { + isValid(); if (setProxy(nativePtr,proxyUri)!=0) { throw new LinphoneCoreException("Bad proxy address ["+proxyUri+"]"); } } public String normalizePhoneNumber(String number) { + isValid(); return normalizePhoneNumber(nativePtr,number); } public void setDialPrefix(String prefix) { + isValid(); setDialPrefix(nativePtr, prefix); } + public String getDialPrefix() { + isValid(); + return getDialPrefix(nativePtr); + } public String getDomain() { + isValid(); return getDomain(nativePtr); } public void setDialEscapePlus(boolean value) { - setDialEscapePlus(nativePtr,value); + isValid(); + setDialEscapePlus(nativePtr,value); + } + public boolean getDialEscapePlus() { + isValid(); + return getDialEscapePlus(nativePtr); } public String getIdentity() { + isValid(); return getIdentity(nativePtr); } public String getProxy() { + isValid(); return getProxy(nativePtr); } public boolean isRegistered() { + isValid(); return isRegistered(nativePtr); } public boolean registerEnabled() { + isValid(); return isRegisterEnabled(nativePtr); } public String getRoute() { + isValid(); return getRoute(nativePtr); } public void setRoute(String routeUri) throws LinphoneCoreException { + isValid(); if (setRoute(nativePtr, routeUri) != 0) { throw new LinphoneCoreException("cannot set route ["+routeUri+"]"); } } public void enablePublish(boolean enable) { + isValid(); enablePublish(nativePtr,enable); } public RegistrationState getState() { + isValid(); return RegistrationState.fromInt(getState(nativePtr)); } public void setExpires(int delay) { + isValid(); setExpires(nativePtr, delay); } + public int getExpires() { + isValid(); + return getExpires(nativePtr); + } public boolean publishEnabled() { - return publishEnabled(nativePtr); + isValid(); + return publishEnabled(nativePtr); } @Override public void setContactParameters(String params) { + isValid(); setContactParameters(nativePtr, params); } @Override public int lookupCCCFromIso(String iso) { + isValid(); return lookupCCCFromIso(nativePtr, iso); } @Override public int lookupCCCFromE164(String e164) { + isValid(); return lookupCCCFromE164(nativePtr, e164); } + private native int getError(long nativeptr); + @Override + public Reason getError() { + isValid(); + return Reason.fromInt(getError(nativePtr)); + } + private native void setPrivacy(long nativePtr, int mask); + @Override + public void setPrivacy(int privacy_mask) { + isValid(); + setPrivacy(nativePtr,privacy_mask); + } + + private native int getPrivacy(long nativePtr); + @Override + public int getPrivacy() { + isValid(); + return getPrivacy(nativePtr); + } + + private native void enableAvpf(long nativePtr, boolean enable); + @Override + public void enableAvpf(boolean enable) { + isValid(); + enableAvpf(nativePtr, enable); + } + + private native boolean avpfEnabled(long nativePtr); + @Override + public boolean avpfEnabled() { + isValid(); + return avpfEnabled(nativePtr); + } + + private native void setAvpfRRInterval(long nativePtr, int interval); + @Override + public void setAvpfRRInterval(int interval) { + isValid(); + setAvpfRRInterval(nativePtr, interval); + } + + private native int getAvpfRRInterval(long nativePtr); + @Override + public int getAvpfRRInterval() { + isValid(); + return getAvpfRRInterval(nativePtr); + } + + private native String getContactParameters(long ptr); + @Override + public String getContactParameters() { + isValid(); + return getContactParameters(nativePtr); + } + + private native void setContactUriParameters(long ptr, String params); + @Override + public void setContactUriParameters(String params) { + isValid(); + setContactUriParameters(nativePtr,params); + } + + private native String getContactUriParameters(long ptr); + @Override + public String getContactUriParameters() { + isValid(); + return getContactUriParameters(nativePtr); + } + + private native long getErrorInfo(long nativePtr); + + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } + + private native void enableQualityReporting(long nativePtr, boolean enable); + @Override + public void enableQualityReporting(boolean enable) { + isValid(); + enableQualityReporting(nativePtr, enable); + } + + private native boolean qualityReportingEnabled(long nativePtr); + @Override + public boolean qualityReportingEnabled() { + isValid(); + return avpfEnabled(nativePtr); + } + + private native void setQualityReportingInterval(long nativePtr, int interval); + @Override + public void setQualityReportingInterval(int interval) { + isValid(); + setQualityReportingInterval(nativePtr, interval); + } + private native int getQualityReportingInterval(long nativePtr); + @Override + public int getQualityReportingInterval() { + isValid(); + return getQualityReportingInterval(nativePtr); + } + + private native void setQualityReportingCollector(long nativePtr, String collector); + @Override + public void setQualityReportingCollector(String collector) { + isValid(); + setQualityReportingCollector(nativePtr, collector); + } + private native String getQualityReportingCollector(long nativePtr); + @Override + public String getQualityReportingCollector() { + + isValid(); + return getQualityReportingCollector(nativePtr); + } + + private native void setRealm(long nativePtr, String realm); + @Override + public void setRealm(String realm) { + isValid(); + setRealm(nativePtr, realm); + } + private native String getRealm(long nativePtr); + @Override + public String getRealm() { + + isValid(); + return getRealm(nativePtr); + } + + private native void setPublishExpires(long nativePtr, int expires); + @Override + public void setPublishExpires(int expires) { + isValid(); + setPublishExpires(nativePtr, expires); + } + private native int getPublishExpires(long nativePtr); + @Override + public int getPublishExpires() { + + isValid(); + return getPublishExpires(nativePtr); + } + + private native boolean isPhoneNumber(long nativePtr,String username); + @Override + public boolean isPhoneNumber(String username){ + return isPhoneNumber(nativePtr,username); + } + + @Override + public void setUserData(Object obj) { + userData = obj; + } + @Override + public Object getUserData() { + return userData; + } } 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..b882f1ecb 100644 --- a/java/impl/org/linphone/core/PayloadTypeImpl.java +++ b/java/impl/org/linphone/core/PayloadTypeImpl.java @@ -21,7 +21,7 @@ package org.linphone.core; class PayloadTypeImpl implements PayloadType { - protected final long nativePtr; + public final long nativePtr; private native String toString(long ptr); private native String getMime(long ptr); @@ -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/core/TunnelConfig.java b/java/impl/org/linphone/core/TunnelConfig.java new file mode 100644 index 000000000..9801f0fbd --- /dev/null +++ b/java/impl/org/linphone/core/TunnelConfig.java @@ -0,0 +1,40 @@ +package org.linphone.core; + +public class TunnelConfig { + private String host = null; + private int port = 443; + private int remoteUdpMirrorPort = 12345; + private int delay = 1000; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getRemoteUdpMirrorPort() { + return remoteUdpMirrorPort; + } + + public void setRemoteUdpMirrorPort(int remoteUdpMirrorPort) { + this.remoteUdpMirrorPort = remoteUdpMirrorPort; + } + + public int getDelay() { + return delay; + } + + public void setDelay(int delay) { + this.delay = delay; + } +} diff --git a/java/impl/org/linphone/tools/Lpc2Xml.java b/java/impl/org/linphone/tools/Lpc2Xml.java index 97ef99637..2f3d90751 100644 --- a/java/impl/org/linphone/tools/Lpc2Xml.java +++ b/java/impl/org/linphone/tools/Lpc2Xml.java @@ -59,7 +59,7 @@ public class Lpc2Xml { static { try { System.loadLibrary("xml2"); - System.loadLibrary("lpc2xml"); + //System.loadLibrary("lpc2xml"); mAvailable = true; } catch (Throwable e) { mAvailable = false; diff --git a/java/impl/org/linphone/tools/Xml2Lpc.java b/java/impl/org/linphone/tools/Xml2Lpc.java index 9f6cb0f27..8e3a9faa0 100644 --- a/java/impl/org/linphone/tools/Xml2Lpc.java +++ b/java/impl/org/linphone/tools/Xml2Lpc.java @@ -61,9 +61,10 @@ public class Xml2Lpc { // Load library static { - try { - System.loadLibrary("xml2"); - System.loadLibrary("xml2lpc"); + try { + new Xml2Lpc(); + //System.loadLibrary("xml2"); + //System.loadLibrary("xml2lpc"); mAvailable = true; } catch (Throwable e) { mAvailable = false; diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 1df0777a6..8a77ad29b 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -1,16 +1,19 @@ ./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/libpolarssl-0.dll +./bin/libbellesip-0.dll +./bin/libantlr3c.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 ./bin/libgpg-error-0.dll ./bin/libgnutls-26.dll ./bin/libtasn1-3.dll +./bin/libsqlite3-0.dll +./bin/libopus-0.dll +./bin/libbzrtp-0.dll diff --git a/linphone.iss.in b/linphone.iss.in index de88854d3..aa700200c 100644 --- a/linphone.iss.in +++ b/linphone.iss.in @@ -16,13 +16,21 @@ ShowLanguageDialog=yes UninstallDisplayIcon={app}\bin\linphone.exe [Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" -Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"; -Name: "french"; MessagesFile: "compiler:Languages\French.isl" -Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl" -Name: "german"; MessagesFile: "compiler:Languages\German.isl" -Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" - +Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl" +Name: "english"; MessagesFile: "compiler:Default.isl" +Name: "french"; MessagesFile: "compiler:Languages\French.isl" +Name: "german"; MessagesFile: "compiler:Languages\German.isl" +Name: "hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl" +Name: "hungarian"; MessagesFile: "compiler:Languages\Hungarian.isl" +Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"; +Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl" +Name: "norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl" +Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl" +Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl" +Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl" +Name: "slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl" +Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" +Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked diff --git a/linphone.spec.in b/linphone.spec.in index 86929b575..f9e954945 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 @@ -38,7 +38,7 @@ over the internet. It has a gtk+ and console interface. Summary: Development libraries for linphone Group: Development/Libraries Requires: %{name} = %{version}-%{release} -Requires: ortp-devel = @ORTP_VERSION@ +Requires: ortp-devel = 1:@ORTP_VERSION@ Requires: mediastreamer-devel = @MS2_VERSION@ Requires: glib2-devel @@ -47,23 +47,19 @@ 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 --enable-ldap %__make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT -install -p -m 0644 pixmaps/linphone.png $RPM_BUILD_ROOT%{_datadir}/pixmaps %find_lang %{name} desktop-file-install \ --delete-original \ @@ -85,24 +81,30 @@ 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}/applications/audio-assistant.desktop %{_datadir}/pixmaps/linphone %{_datadir}/linphone -%{_datadir}/pixmaps/linphone.png +%{_datadir}/icons/* %{_datadir}/sounds/linphone +%{_datadir}/appdata/linphone.appdata.xml %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/exosip.m4 b/m4/exosip.m4 index 31769e00d..e7c72647d 100644 --- a/m4/exosip.m4 +++ b/m4/exosip.m4 @@ -20,6 +20,19 @@ EXOSIP_LIBS="$OSIP_LIBS -leXosip2 " CPPFLAGS_save=$CPPFLAGS CPPFLAGS="$OSIP_CFLAGS $CPPFLAGS" AC_CHECK_HEADER([eXosip2/eXosip.h], ,AC_MSG_ERROR([Could not find eXosip2 headers !])) + +dnl check exosip support of DSCP in exosip +AC_MSG_CHECKING([for DSCP support in exosip]) +AC_TRY_COMPILE([#include ], + [int dscp=0;eXosip_set_option(EXOSIP_OPT_SET_DSCP,&dscp);], + has_exosip_dscp=yes, + has_exosip_dscp=no +) +AC_MSG_RESULT($has_exosip_dscp) +if test "$has_exosip_dscp" = "yes" ; then + AC_DEFINE( HAVE_EXOSIP_DSCP, 1, [Define if exosip dscp available] ) +fi + CPPFLAGS=$CPPFLAGS_save 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/m4/readline.m4 b/m4/readline.m4 index ebb7656cd..24cb1d71e 100644 --- a/m4/readline.m4 +++ b/m4/readline.m4 @@ -5,23 +5,27 @@ AC_DEFUN([LP_CHECK_READLINE],[ AC_ARG_WITH( readline, - [ --with-readline Set prefix where gnu readline headers and libs can be found (ex:/usr, /usr/local, none) [default=/usr] ], - [ readline_prefix=${withval}],[ readline_prefix="/usr" ]) + [ --with-readline Set prefix where gnu readline headers and libs can be found (ex:/usr, /usr/local, none) [default=/usr] ], + [ readline_prefix=${withval} ], + [ readline_prefix="/usr/local" ], + [ readline_prefix="/opt/local" ], + [ readline_prefix="/usr" ] +) -if test "$readline_prefix" != "none"; then +if test "$readline_prefix" != "none" -a "$readline_prefix" != "no"; then if test "$readline_prefix" != "/usr"; then READLINE_CFLAGS="-I$readline_prefix/include" READLINE_LIBS="-L$readline_prefix/lib" fi - + CPPFLAGS_save=$CPPFLAGS LIBS_save=$LIBS CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" LIBS="$LIBS $READLINE_LIBS" AC_CHECK_HEADERS(readline.h readline/readline.h, readline_h_found=yes) AC_CHECK_HEADERS(history.h readline/history.h) - + for termcap_lib in "" -ltermcap -lcurses -lncurses; do unset ac_cv_lib_readline_readline AC_CHECK_LIB(readline, readline, [readline_libs_found=yes],[],[$termcap_lib]) @@ -33,14 +37,14 @@ if test "$readline_prefix" != "none"; then LIBS=$LIBS_save CPPFLAGS=$CPPFLAGS_save - + if test "$readline_libs_found$readline_h_found" != "yesyes" ; then AC_MSG_WARN([Could not find libreadline headers or library, linphonec will have limited prompt features]) else AC_DEFINE([HAVE_READLINE],1,[defined when compiling with readline support]) fi - - + + AC_SUBST(READLINE_CFLAGS) AC_SUBST(READLINE_LIBS) diff --git a/mediastreamer2 b/mediastreamer2 index 8d85a5ded..203c5bbca 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8d85a5ded3b18e2d3d4ba22ee75e0f1ef9c0f739 +Subproject commit 203c5bbca581db81abc6d6e64e3e0cd0c948c3d3 diff --git a/oRTP b/oRTP index b055a5050..7e89236af 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b055a505042c4420e104ce81a09790c5373f62bb +Subproject commit 7e89236af6552140d0d6fa3b6878bc13addd8f7d diff --git a/pixmaps/CMakeLists.txt b/pixmaps/CMakeLists.txt new file mode 100644 index 000000000..c90f789eb --- /dev/null +++ b/pixmaps/CMakeLists.txt @@ -0,0 +1,58 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +set(ICONS_INSTALL_DIR ${PACKAGE_DATA_DIR}/icons/hicolor) + +file(GLOB PIXMAPS "*.png" "linphone.icns") + +install(FILES ${PIXMAPS} + DESTINATION ${PACKAGE_DATA_DIR}/pixmaps/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +install(FILES svg/linphone-micro-muted.svg + svg/linphone-speaker-muted.svg + svg/linphone-micro-enabled.svg + svg/linphone-speaker-enabled.svg + DESTINATION ${ICONS_INSTALL_DIR}/scalable/status + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ +) + +install(FILES linphone-micro-muted.png + linphone-speaker-muted.png + linphone-micro-enabled.png + linphone-speaker-enabled.png + DESTINATION ${ICONS_INSTALL_DIR}/48x48/status + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ +) + +install(FILES linphone.png + DESTINATION ${ICONS_INSTALL_DIR}/48x48/apps + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +if(WIN32) + install(FILES index.theme + DESTINATION ${ICONS_INSTALL_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) +endif() diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index 2386d68cf..afa9f411f 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -1,25 +1,41 @@ - - pixmapdir=$(datadir)/pixmaps/linphone +dist_pixmap_DATA= \ + hold_on.png hold_off.png \ + linphone.png linphone-banner.png \ + status-green.png \ + status-orange.png \ + status-red.png \ + status-offline.png \ + call.png \ + chat.png chat_start.png active_chat.png composing_chat.png composing_active_chat.png\ + chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\ + contact-orange.png history-orange.png\ + call_start.png startcall-small.png stopcall-red.png stopcall-small.png call_add.png linphone.icns \ + contact_starred.png contact_unstarred.png \ + call_status_incoming.png call_status_outgoing.png \ + ok.png \ + dialer.png \ + notok.png -pixmap_DATA= \ -hold_on.png hold_off.png \ -mic_muted.png mic_active.png \ -linphone.png linphone-banner.png \ -status-green.png \ -status-orange.png \ -status-red.png \ -status-offline.png \ -call.png \ -chat.png active_chat.png\ -chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\ -contact-orange.png dialer-orange.png history-orange.png\ -startcall-green.png startcall-small.png stopcall-red.png stopcall-small.png addcall-green.png linphone.icns \ -contact_starred.png contact_unstarred.png \ -speaker.png \ -call_status_incoming.png call_status_outgoing.png \ -ok.png \ -dialer.png \ -notok.png +iconsdir=$(datadir)/icons/hicolor +if BUILD_WIN32 + dist_icons_DATA=index.theme +endif + +appiconsdir=$(iconsdir)/48x48/apps +dist_appicons_DATA= linphone.png + +status48iconsdir=$(iconsdir)/48x48/status +dist_status48icons_DATA= \ + linphone-micro-muted.png \ + linphone-speaker-muted.png \ + linphone-micro-enabled.png \ + linphone-speaker-enabled.png + +statussvgiconsdir=$(iconsdir)/scalable/status +dist_statussvgicons_DATA= \ + svg/linphone-micro-muted.svg \ + svg/linphone-speaker-muted.svg \ + svg/linphone-micro-enabled.svg \ + svg/linphone-speaker-enabled.svg -EXTRA_DIST=$(pixmap_DATA) diff --git a/pixmaps/active_chat.png b/pixmaps/active_chat.png index e428845d5..ef3cedd1d 100644 Binary files a/pixmaps/active_chat.png and b/pixmaps/active_chat.png differ diff --git a/pixmaps/addcall-green.png b/pixmaps/addcall-green.png deleted file mode 100644 index 9de8463ca..000000000 Binary files a/pixmaps/addcall-green.png and /dev/null differ diff --git a/pixmaps/call_add.png b/pixmaps/call_add.png new file mode 100644 index 000000000..9e2cbb18e Binary files /dev/null and b/pixmaps/call_add.png differ diff --git a/pixmaps/call_start.png b/pixmaps/call_start.png new file mode 100644 index 000000000..77b264d72 Binary files /dev/null and b/pixmaps/call_start.png differ diff --git a/pixmaps/chat_start.png b/pixmaps/chat_start.png new file mode 100644 index 000000000..3de673211 Binary files /dev/null and b/pixmaps/chat_start.png differ diff --git a/pixmaps/composing_active_chat.png b/pixmaps/composing_active_chat.png new file mode 100644 index 000000000..77da9e37f Binary files /dev/null and b/pixmaps/composing_active_chat.png differ diff --git a/pixmaps/composing_chat.png b/pixmaps/composing_chat.png new file mode 100644 index 000000000..2d329ed21 Binary files /dev/null and b/pixmaps/composing_chat.png differ diff --git a/pixmaps/contact_unstarred.png b/pixmaps/contact_unstarred.png index ad041095b..38fdbbb77 100644 Binary files a/pixmaps/contact_unstarred.png and b/pixmaps/contact_unstarred.png differ diff --git a/pixmaps/dialer-orange.png b/pixmaps/dialer-orange.png deleted file mode 100644 index 2d715eac0..000000000 Binary files a/pixmaps/dialer-orange.png and /dev/null differ diff --git a/pixmaps/dialer.png b/pixmaps/dialer.png index 5da3ad70d..bb9747a90 100644 Binary files a/pixmaps/dialer.png and b/pixmaps/dialer.png differ diff --git a/pixmaps/index.theme b/pixmaps/index.theme new file mode 100644 index 000000000..d17354741 --- /dev/null +++ b/pixmaps/index.theme @@ -0,0 +1,1836 @@ +[Icon Theme] +Name=Hicolor +Comment=Fallback icon theme +Hidden=true +Directories=16x16/actions,16x16/animations,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/filesystems,16x16/intl,16x16/mimetypes,16x16/places,16x16/status,16x16/stock/chart,16x16/stock/code,16x16/stock/data,16x16/stock/form,16x16/stock/image,16x16/stock/io,16x16/stock/media,16x16/stock/navigation,16x16/stock/net,16x16/stock/object,16x16/stock/table,16x16/stock/text,22x22/actions,22x22/animations,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/filesystems,22x22/intl,22x22/mimetypes,22x22/places,22x22/status,22x22/stock/chart,22x22/stock/code,22x22/stock/data,22x22/stock/form,22x22/stock/image,22x22/stock/io,22x22/stock/media,22x22/stock/navigation,22x22/stock/net,22x22/stock/object,22x22/stock/table,22x22/stock/text,24x24/actions,24x24/animations,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/filesystems,24x24/intl,24x24/mimetypes,24x24/places,24x24/status,24x24/stock/chart,24x24/stock/code,24x24/stock/data,24x24/stock/form,24x24/stock/image,24x24/stock/io,24x24/stock/media,24x24/stock/navigation,24x24/stock/net,24x24/stock/object,24x24/stock/table,24x24/stock/text,32x32/actions,32x32/animations,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/filesystems,32x32/intl,32x32/mimetypes,32x32/places,32x32/status,32x32/stock/chart,32x32/stock/code,32x32/stock/data,32x32/stock/form,32x32/stock/image,32x32/stock/io,32x32/stock/media,32x32/stock/navigation,32x32/stock/net,32x32/stock/object,32x32/stock/table,32x32/stock/text,36x36/actions,36x36/animations,36x36/apps,36x36/categories,36x36/devices,36x36/emblems,36x36/emotes,36x36/filesystems,36x36/intl,36x36/mimetypes,36x36/places,36x36/status,36x36/stock/chart,36x36/stock/code,36x36/stock/data,36x36/stock/form,36x36/stock/image,36x36/stock/io,36x36/stock/media,36x36/stock/navigation,36x36/stock/net,36x36/stock/object,36x36/stock/table,36x36/stock/text,48x48/actions,48x48/animations,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/filesystems,48x48/intl,48x48/mimetypes,48x48/places,48x48/status,48x48/stock/chart,48x48/stock/code,48x48/stock/data,48x48/stock/form,48x48/stock/image,48x48/stock/io,48x48/stock/media,48x48/stock/navigation,48x48/stock/net,48x48/stock/object,48x48/stock/table,48x48/stock/text,64x64/actions,64x64/animations,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/filesystems,64x64/intl,64x64/mimetypes,64x64/places,64x64/status,64x64/stock/chart,64x64/stock/code,64x64/stock/data,64x64/stock/form,64x64/stock/image,64x64/stock/io,64x64/stock/media,64x64/stock/navigation,64x64/stock/net,64x64/stock/object,64x64/stock/table,64x64/stock/text,72x72/actions,72x72/animations,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/filesystems,72x72/intl,72x72/mimetypes,72x72/places,72x72/status,72x72/stock/chart,72x72/stock/code,72x72/stock/data,72x72/stock/form,72x72/stock/image,72x72/stock/io,72x72/stock/media,72x72/stock/navigation,72x72/stock/net,72x72/stock/object,72x72/stock/table,72x72/stock/text,96x96/actions,96x96/animations,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/filesystems,96x96/intl,96x96/mimetypes,96x96/places,96x96/status,96x96/stock/chart,96x96/stock/code,96x96/stock/data,96x96/stock/form,96x96/stock/image,96x96/stock/io,96x96/stock/media,96x96/stock/navigation,96x96/stock/net,96x96/stock/object,96x96/stock/table,96x96/stock/text,128x128/actions,128x128/animations,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/filesystems,128x128/intl,128x128/mimetypes,128x128/places,128x128/status,128x128/stock/chart,128x128/stock/code,128x128/stock/data,128x128/stock/form,128x128/stock/image,128x128/stock/io,128x128/stock/media,128x128/stock/navigation,128x128/stock/net,128x128/stock/object,128x128/stock/table,128x128/stock/text,192x192/actions,192x192/animations,192x192/apps,192x192/categories,192x192/devices,192x192/emblems,192x192/emotes,192x192/filesystems,192x192/intl,192x192/mimetypes,192x192/places,192x192/status,192x192/stock/chart,192x192/stock/code,192x192/stock/data,192x192/stock/form,192x192/stock/image,192x192/stock/io,192x192/stock/media,192x192/stock/navigation,192x192/stock/net,192x192/stock/object,192x192/stock/table,192x192/stock/text,256x256/actions,256x256/animations,256x256/apps,256x256/categories,256x256/devices,256x256/emblems,256x256/emotes,256x256/filesystems,256x256/intl,256x256/mimetypes,256x256/places,256x256/status,256x256/stock/chart,256x256/stock/code,256x256/stock/data,256x256/stock/form,256x256/stock/image,256x256/stock/io,256x256/stock/media,256x256/stock/navigation,256x256/stock/net,256x256/stock/object,256x256/stock/table,256x256/stock/text,512x512/actions,512x512/animations,512x512/apps,512x512/categories,512x512/devices,512x512/emblems,512x512/emotes,512x512/filesystems,512x512/intl,512x512/mimetypes,512x512/places,512x512/status,512x512/stock/chart,512x512/stock/code,512x512/stock/data,512x512/stock/form,512x512/stock/image,512x512/stock/io,512x512/stock/media,512x512/stock/navigation,512x512/stock/net,512x512/stock/object,512x512/stock/table,512x512/stock/text,scalable/actions,scalable/animations,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/filesystems,scalable/intl,scalable/mimetypes,scalable/places,scalable/status,scalable/stock/chart,scalable/stock/code,scalable/stock/data,scalable/stock/form,scalable/stock/image,scalable/stock/io,scalable/stock/media,scalable/stock/navigation,scalable/stock/net,scalable/stock/object,scalable/stock/table,scalable/stock/text,symbolic/apps + + +[16x16/actions] +Size=16 +Context=Actions +Type=Threshold + +[16x16/animations] +Size=16 +Context=Animations +Type=Threshold + +[16x16/apps] +Size=16 +Context=Applications +Type=Threshold + +[16x16/categories] +Size=16 +Context=Categories +Type=Threshold + +[16x16/devices] +Size=16 +Context=Devices +Type=Threshold + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Threshold + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Threshold + +[16x16/filesystems] +Size=16 +Context=FileSystems +Type=Threshold + +[16x16/intl] +Size=16 +Context=International +Type=Threshold + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Threshold + +[16x16/places] +Size=16 +Context=Places +Type=Threshold + +[16x16/status] +Size=16 +Context=Status +Type=Threshold + +[16x16/stock/chart] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/code] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/data] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/form] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/image] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/io] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/media] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/navigation] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/net] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/object] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/table] +Size=16 +Context=Stock +Type=Threshold + +[16x16/stock/text] +Size=16 +Context=Stock +Type=Threshold + +[22x22/actions] +Size=22 +Context=Actions +Type=Threshold + +[22x22/animations] +Size=22 +Context=Animations +Type=Threshold + +[22x22/apps] +Size=22 +Context=Applications +Type=Threshold + +[22x22/categories] +Size=22 +Context=Categories +Type=Threshold + +[22x22/devices] +Size=22 +Context=Devices +Type=Threshold + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Threshold + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Threshold + +[22x22/filesystems] +Size=22 +Context=FileSystems +Type=Threshold + +[22x22/intl] +Size=22 +Context=International +Type=Threshold + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Threshold + +[22x22/places] +Size=22 +Context=Places +Type=Threshold + +[22x22/status] +Size=22 +Context=Status +Type=Threshold + +[22x22/stock/chart] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/code] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/data] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/form] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/image] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/io] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/media] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/navigation] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/net] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/object] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/table] +Size=22 +Context=Stock +Type=Threshold + +[22x22/stock/text] +Size=22 +Context=Stock +Type=Threshold + +[24x24/actions] +Size=24 +Context=Actions +Type=Threshold + +[24x24/animations] +Size=24 +Context=Animations +Type=Threshold + +[24x24/apps] +Size=24 +Context=Applications +Type=Threshold + +[24x24/categories] +Size=24 +Context=Categories +Type=Threshold + +[24x24/devices] +Size=24 +Context=Devices +Type=Threshold + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Threshold + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Threshold + +[24x24/filesystems] +Size=24 +Context=FileSystems +Type=Threshold + +[24x24/intl] +Size=24 +Context=International +Type=Threshold + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Threshold + +[24x24/places] +Size=24 +Context=Places +Type=Threshold + +[24x24/status] +Size=24 +Context=Status +Type=Threshold + +[24x24/stock/chart] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/code] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/data] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/form] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/image] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/io] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/media] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/navigation] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/net] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/object] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/table] +Size=24 +Context=Stock +Type=Threshold + +[24x24/stock/text] +Size=24 +Context=Stock +Type=Threshold + +[32x32/actions] +Size=32 +Context=Actions +Type=Threshold + +[32x32/animations] +Size=32 +Context=Animations +Type=Threshold + +[32x32/apps] +Size=32 +Context=Applications +Type=Threshold + +[32x32/categories] +Size=32 +Context=Categories +Type=Threshold + +[32x32/devices] +Size=32 +Context=Devices +Type=Threshold + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Threshold + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Threshold + +[32x32/filesystems] +Size=32 +Context=FileSystems +Type=Threshold + +[32x32/intl] +Size=32 +Context=International +Type=Threshold + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Threshold + +[32x32/places] +Size=32 +Context=Places +Type=Threshold + +[32x32/status] +Size=32 +Context=Status +Type=Threshold + +[32x32/stock/chart] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/code] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/data] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/form] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/image] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/io] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/media] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/navigation] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/net] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/object] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/table] +Size=32 +Context=Stock +Type=Threshold + +[32x32/stock/text] +Size=32 +Context=Stock +Type=Threshold + +[36x36/actions] +Size=36 +Context=Actions +Type=Threshold + +[36x36/animations] +Size=36 +Context=Animations +Type=Threshold + +[36x36/apps] +Size=36 +Context=Applications +Type=Threshold + +[36x36/categories] +Size=36 +Context=Categories +Type=Threshold + +[36x36/devices] +Size=36 +Context=Devices +Type=Threshold + +[36x36/emblems] +Size=36 +Context=Emblems +Type=Threshold + +[36x36/emotes] +Size=36 +Context=Emotes +Type=Threshold + +[36x36/filesystems] +Size=36 +Context=FileSystems +Type=Threshold + +[36x36/intl] +Size=36 +Context=International +Type=Threshold + +[36x36/mimetypes] +Size=36 +Context=MimeTypes +Type=Threshold + +[36x36/places] +Size=36 +Context=Places +Type=Threshold + +[36x36/status] +Size=36 +Context=Status +Type=Threshold + +[36x36/stock/chart] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/code] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/data] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/form] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/image] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/io] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/media] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/navigation] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/net] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/object] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/table] +Size=36 +Context=Stock +Type=Threshold + +[36x36/stock/text] +Size=36 +Context=Stock +Type=Threshold + +[48x48/actions] +Size=48 +Context=Actions +Type=Threshold + +[48x48/animations] +Size=48 +Context=Animations +Type=Threshold + +[48x48/apps] +Size=48 +Context=Applications +Type=Threshold + +[48x48/categories] +Size=48 +Context=Categories +Type=Threshold + +[48x48/devices] +Size=48 +Context=Devices +Type=Threshold + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Threshold + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Threshold + +[48x48/filesystems] +Size=48 +Context=FileSystems +Type=Threshold + +[48x48/intl] +Size=48 +Context=International +Type=Threshold + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Threshold + +[48x48/places] +Size=48 +Context=Places +Type=Threshold + +[48x48/status] +Size=48 +Context=Status +Type=Threshold + +[48x48/stock/chart] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/code] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/data] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/form] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/image] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/io] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/media] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/navigation] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/net] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/object] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/table] +Size=48 +Context=Stock +Type=Threshold + +[48x48/stock/text] +Size=48 +Context=Stock +Type=Threshold + +[64x64/actions] +Size=64 +Context=Actions +Type=Threshold + +[64x64/animations] +Size=64 +Context=Animations +Type=Threshold + +[64x64/apps] +Size=64 +Context=Applications +Type=Threshold + +[64x64/categories] +Size=64 +Context=Categories +Type=Threshold + +[64x64/devices] +Size=64 +Context=Devices +Type=Threshold + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Threshold + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Threshold + +[64x64/filesystems] +Size=64 +Context=FileSystems +Type=Threshold + +[64x64/intl] +Size=64 +Context=International +Type=Threshold + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Threshold + +[64x64/places] +Size=64 +Context=Places +Type=Threshold + +[64x64/status] +Size=64 +Context=Status +Type=Threshold + +[64x64/stock/chart] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/code] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/data] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/form] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/image] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/io] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/media] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/navigation] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/net] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/object] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/table] +Size=64 +Context=Stock +Type=Threshold + +[64x64/stock/text] +Size=64 +Context=Stock +Type=Threshold +[72x72/actions] +Size=72 +Context=Actions +Type=Threshold + +[72x72/animations] +Size=72 +Context=Animations +Type=Threshold + +[72x72/apps] +Size=72 +Context=Applications +Type=Threshold + +[72x72/categories] +Size=72 +Context=Categories +Type=Threshold + +[72x72/devices] +Size=72 +Context=Devices +Type=Threshold + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Threshold + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Threshold + +[72x72/filesystems] +Size=72 +Context=FileSystems +Type=Threshold + +[72x72/intl] +Size=72 +Context=International +Type=Threshold + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Threshold + +[72x72/places] +Size=72 +Context=Places +Type=Threshold + +[72x72/status] +Size=72 +Context=Status +Type=Threshold + +[72x72/stock/chart] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/code] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/data] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/form] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/image] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/io] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/media] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/navigation] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/net] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/object] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/table] +Size=72 +Context=Stock +Type=Threshold + +[72x72/stock/text] +Size=72 +Context=Stock +Type=Threshold + +[96x96/actions] +Size=96 +Context=Actions +Type=Threshold + +[96x96/animations] +Size=96 +Context=Animations +Type=Threshold + +[96x96/apps] +Size=96 +Context=Applications +Type=Threshold + +[96x96/categories] +Size=96 +Context=Categories +Type=Threshold + +[96x96/devices] +Size=96 +Context=Devices +Type=Threshold + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Threshold + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Threshold + +[96x96/filesystems] +Size=96 +Context=FileSystems +Type=Threshold + +[96x96/intl] +Size=96 +Context=International +Type=Threshold + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Threshold + +[96x96/places] +Size=96 +Context=Places +Type=Threshold + +[96x96/status] +Size=96 +Context=Status +Type=Threshold + +[96x96/stock/chart] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/code] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/data] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/form] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/image] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/io] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/media] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/navigation] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/net] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/object] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/table] +Size=96 +Context=Stock +Type=Threshold + +[96x96/stock/text] +Size=96 +Context=Stock +Type=Threshold + +[128x128/actions] +Size=128 +Context=Actions +Type=Threshold + +[128x128/animations] +Size=128 +Context=Animations +Type=Threshold + +[128x128/apps] +Size=128 +Context=Applications +Type=Threshold + +[128x128/categories] +Size=128 +Context=Categories +Type=Threshold + +[128x128/devices] +Size=128 +Context=Devices +Type=Threshold + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Threshold + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Threshold + +[128x128/filesystems] +Size=128 +Context=FileSystems +Type=Threshold + +[128x128/intl] +Size=128 +Context=International +Type=Threshold + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Threshold + +[128x128/places] +Size=128 +Context=Places +Type=Threshold + +[128x128/status] +Size=128 +Context=Status +Type=Threshold + +[128x128/stock/chart] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/code] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/data] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/form] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/image] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/io] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/media] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/navigation] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/net] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/object] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/table] +Size=128 +Context=Stock +Type=Threshold + +[128x128/stock/text] +Size=128 +Context=Stock +Type=Threshold + +[192x192/actions] +Size=192 +Context=Actions +Type=Threshold + +[192x192/animations] +Size=192 +Context=Animations +Type=Threshold + +[192x192/apps] +Size=192 +Context=Applications +Type=Threshold + +[192x192/categories] +Size=192 +Context=Categories +Type=Threshold + +[192x192/devices] +Size=192 +Context=Devices +Type=Threshold + +[192x192/emblems] +Size=192 +Context=Emblems +Type=Threshold + +[192x192/emotes] +Size=192 +Context=Emotes +Type=Threshold + +[192x192/filesystems] +Size=192 +Context=FileSystems +Type=Threshold + +[192x192/intl] +Size=192 +Context=International +Type=Threshold + +[192x192/mimetypes] +Size=192 +Context=MimeTypes +Type=Threshold + +[192x192/places] +Size=192 +Context=Places +Type=Threshold + +[192x192/status] +Size=192 +Context=Status +Type=Threshold + +[192x192/stock/chart] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/code] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/data] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/form] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/image] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/io] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/media] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/navigation] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/net] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/object] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/table] +Size=192 +Context=Stock +Type=Threshold + +[192x192/stock/text] +Size=192 +Context=Stock +Type=Threshold + +[256x256/actions] +MinSize=64 +Size=256 +MaxSize=256 +Context=Actions +Type=Scalable + +[256x256/animations] +MinSize=64 +Size=256 +MaxSize=256 +Context=Animations +Type=Scalable + +[256x256/apps] +MinSize=64 +Size=256 +MaxSize=256 +Context=Applications +Type=Scalable + +[256x256/categories] +MinSize=64 +Size=256 +MaxSize=256 +Context=Categories +Type=Scalable + +[256x256/devices] +MinSize=64 +Size=256 +MaxSize=256 +Context=Devices +Type=Scalable + +[256x256/emblems] +MinSize=64 +Size=256 +MaxSize=256 +Context=Emblems +Type=Scalable + +[256x256/emotes] +MinSize=64 +Size=256 +MaxSize=256 +Context=Emotes +Type=Scalable + +[256x256/filesystems] +MinSize=64 +Size=256 +MaxSize=256 +Context=FileSystems +Type=Scalable + +[256x256/intl] +MinSize=64 +Size=256 +MaxSize=256 +Context=International +Type=Scalable + +[256x256/mimetypes] +MinSize=64 +Size=256 +MaxSize=256 +Context=MimeTypes +Type=Scalable + +[256x256/places] +MinSize=64 +Size=256 +MaxSize=256 +Context=Places +Type=Scalable + +[256x256/status] +MinSize=64 +Size=256 +MaxSize=256 +Context=Status +Type=Scalable + +[256x256/stock/chart] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/code] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/data] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/form] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/image] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/io] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/media] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/navigation] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/net] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/object] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/table] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[256x256/stock/text] +MinSize=64 +Size=256 +MaxSize=256 +Context=Stock +Type=Scalable + +[512x512/actions] +MinSize=64 +Size=512 +MaxSize=512 +Context=Actions +Type=Scalable + +[512x512/animations] +MinSize=64 +Size=512 +MaxSize=512 +Context=Animations +Type=Scalable + +[512x512/apps] +MinSize=64 +Size=512 +MaxSize=512 +Context=Applications +Type=Scalable + +[512x512/categories] +MinSize=64 +Size=512 +MaxSize=512 +Context=Categories +Type=Scalable + +[512x512/devices] +MinSize=64 +Size=512 +MaxSize=512 +Context=Devices +Type=Scalable + +[512x512/emblems] +MinSize=64 +Size=512 +MaxSize=512 +Context=Emblems +Type=Scalable + +[512x512/emotes] +MinSize=64 +Size=512 +MaxSize=512 +Context=Emotes +Type=Scalable + +[512x512/filesystems] +MinSize=64 +Size=512 +MaxSize=512 +Context=FileSystems +Type=Scalable + +[512x512/intl] +MinSize=64 +Size=512 +MaxSize=512 +Context=International +Type=Scalable + +[512x512/mimetypes] +MinSize=64 +Size=512 +MaxSize=512 +Context=MimeTypes +Type=Scalable + +[512x512/places] +MinSize=64 +Size=512 +MaxSize=512 +Context=Places +Type=Scalable + +[512x512/status] +MinSize=64 +Size=512 +MaxSize=512 +Context=Status +Type=Scalable + +[512x512/stock/chart] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/code] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/data] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/form] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/image] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/io] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/media] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/navigation] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/net] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/object] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/table] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[512x512/stock/text] +MinSize=64 +Size=512 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/actions] +MinSize=1 +Size=128 +MaxSize=256 +Context=Actions +Type=Scalable + +[scalable/animations] +MinSize=1 +Size=128 +MaxSize=256 +Context=Animations +Type=Scalable + +[scalable/apps] +MinSize=1 +Size=128 +MaxSize=256 +Context=Applications +Type=Scalable + +[scalable/categories] +MinSize=1 +Size=128 +MaxSize=256 +Context=Categories +Type=Scalable + +[scalable/devices] +MinSize=1 +Size=128 +MaxSize=512 +Context=Devices +Type=Scalable + +[scalable/emblems] +MinSize=1 +Size=128 +MaxSize=256 +Context=Emblems +Type=Scalable + +[scalable/emotes] +MinSize=1 +Size=128 +MaxSize=512 +Context=Emotes +Type=Scalable + +[scalable/filesystems] +MinSize=1 +Size=128 +MaxSize=256 +Context=FileSystems +Type=Scalable + +[scalable/intl] +MinSize=1 +Size=128 +MaxSize=512 +Context=International +Type=Scalable + +[scalable/mimetypes] +MinSize=1 +Size=128 +MaxSize=256 +Context=MimeTypes +Type=Scalable + +[scalable/places] +MinSize=1 +Size=128 +MaxSize=512 +Context=Places +Type=Scalable + +[scalable/status] +MinSize=1 +Size=128 +MaxSize=256 +Context=Status +Type=Scalable + +[scalable/stock/chart] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/code] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[scalable/stock/data] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/form] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[scalable/stock/image] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/io] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[scalable/stock/media] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/navigation] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[scalable/stock/net] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/object] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[scalable/stock/table] +MinSize=1 +Size=128 +MaxSize=512 +Context=Stock +Type=Scalable + +[scalable/stock/text] +MinSize=1 +Size=128 +MaxSize=256 +Context=Stock +Type=Scalable + +[symbolic/apps] +MinSize=8 +Size=16 +MaxSize=512 +Context=Applications +Type=Scalable diff --git a/pixmaps/linphone-banner.png b/pixmaps/linphone-banner.png index 0abff3ebf..6fe99ab77 100644 Binary files a/pixmaps/linphone-banner.png and b/pixmaps/linphone-banner.png differ diff --git a/pixmaps/linphone-micro-enabled.png b/pixmaps/linphone-micro-enabled.png new file mode 100644 index 000000000..44ba551af Binary files /dev/null and b/pixmaps/linphone-micro-enabled.png differ diff --git a/pixmaps/linphone-micro-muted.png b/pixmaps/linphone-micro-muted.png new file mode 100644 index 000000000..cf666ebd0 Binary files /dev/null and b/pixmaps/linphone-micro-muted.png differ diff --git a/pixmaps/linphone-speaker-enabled.png b/pixmaps/linphone-speaker-enabled.png new file mode 100644 index 000000000..0c8d7a951 Binary files /dev/null and b/pixmaps/linphone-speaker-enabled.png differ diff --git a/pixmaps/linphone-speaker-muted.png b/pixmaps/linphone-speaker-muted.png new file mode 100644 index 000000000..91e96eddb Binary files /dev/null and b/pixmaps/linphone-speaker-muted.png differ diff --git a/pixmaps/linphone.png b/pixmaps/linphone.png index 722593e65..4031d7205 100644 Binary files a/pixmaps/linphone.png and b/pixmaps/linphone.png differ diff --git a/pixmaps/mic_active.png b/pixmaps/mic_active.png deleted file mode 100644 index ee6b9038c..000000000 Binary files a/pixmaps/mic_active.png and /dev/null differ diff --git a/pixmaps/mic_muted.png b/pixmaps/mic_muted.png deleted file mode 100644 index 60fd18761..000000000 Binary files a/pixmaps/mic_muted.png and /dev/null differ diff --git a/pixmaps/speaker.png b/pixmaps/speaker.png deleted file mode 100644 index acc92dbcf..000000000 Binary files a/pixmaps/speaker.png and /dev/null differ diff --git a/pixmaps/startcall-small.png b/pixmaps/startcall-small.png index 30b32789a..d5726e12c 100644 Binary files a/pixmaps/startcall-small.png and b/pixmaps/startcall-small.png differ diff --git a/pixmaps/svg/.directory b/pixmaps/svg/.directory new file mode 100644 index 000000000..c99a6191a --- /dev/null +++ b/pixmaps/svg/.directory @@ -0,0 +1,4 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2015,8,3,13,7,36 +Version=3 diff --git a/pixmaps/svg/linphone-micro-enabled.svg b/pixmaps/svg/linphone-micro-enabled.svg new file mode 100644 index 000000000..a23354bc1 --- /dev/null +++ b/pixmaps/svg/linphone-micro-enabled.svg @@ -0,0 +1,78 @@ + + + + + + image/svg+xml + + micro_default + + + + + + micro_default + Created with Sketch. + + + + + + diff --git a/pixmaps/svg/linphone-micro-muted.svg b/pixmaps/svg/linphone-micro-muted.svg new file mode 100644 index 000000000..09d505c59 --- /dev/null +++ b/pixmaps/svg/linphone-micro-muted.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + micro_default + + + + + + micro_default + Created with Sketch. + + + + + + + + + + diff --git a/pixmaps/svg/linphone-speaker-enabled.svg b/pixmaps/svg/linphone-speaker-enabled.svg new file mode 100644 index 000000000..8a122795d --- /dev/null +++ b/pixmaps/svg/linphone-speaker-enabled.svg @@ -0,0 +1,87 @@ + + + + + + image/svg+xml + + speaker_default + + + + + + speaker_default + Created with Sketch. + + + + + + + + + + diff --git a/pixmaps/svg/linphone-speaker-muted.svg b/pixmaps/svg/linphone-speaker-muted.svg new file mode 100644 index 000000000..1e85b85be --- /dev/null +++ b/pixmaps/svg/linphone-speaker-muted.svg @@ -0,0 +1,76 @@ + + + + + + image/svg+xml + + speaker_default + + + + + + speaker_default + Created with Sketch. + + + + + diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 000000000..52f36bb40 --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1,32 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +if(GETTEXT_FOUND) + foreach(language ${LINPHONE_ALL_LANGS_LIST}) + GETTEXT_PROCESS_PO_FILES(${language} ALL PO_FILES ${language}.po) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${language}.gmo + DESTINATION ${PACKAGE_LOCALE_DIR}/${language}/LC_MESSAGES + RENAME linphone.mo + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) + endforeach() +endif() diff --git a/po/POTFILES.in b/po/POTFILES.in index 4a4497cbd..ebfa3dff3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,8 @@ gtk/buddylookup.c gtk/setupwizard.c gtk/incall_view.c gtk/loginframe.c +gtk/config-fetching.c +gtk/audio_assistant.c [type: gettext/glade]gtk/main.ui [type: gettext/glade]gtk/about.ui [type: gettext/glade]gtk/contact.ui @@ -27,12 +29,21 @@ gtk/loginframe.c [type: gettext/glade]gtk/call_statistics.ui [type: gettext/glade]gtk/tunnel_config.ui [type: gettext/glade]gtk/keypad.ui +[type: gettext/glade]gtk/ldap.ui +[type: gettext/glade]gtk/config-uri.ui +[type: gettext/glade]gtk/provisioning-fetch.ui +[type: gettext/glade]gtk/chatroom_frame.ui +[type: gettext/glade]gtk/callee_frame.ui +[type: gettext/glade]gtk/conf_frame.ui +[type: gettext/glade]gtk/in_call_frame.ui +[type: gettext/glade]gtk/login_frame.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c coreapi/friend.c coreapi/proxy.c coreapi/callbacks.c -coreapi/sal_eXosip2.c coreapi/linphonecall.c +coreapi/call_log.c +gtk/videowindow.c diff --git a/po/POTFILES.skip b/po/POTFILES.skip index e254f124a..32dcd19f2 100755 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -47,3 +47,7 @@ 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 +build/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs +mediastreamer2/build/wp8/mediastreamer2-tester-wp8/Resources/AppResources.Designer.cs +share/linphone.desktop.in diff --git a/po/README b/po/README new file mode 100644 index 000000000..68c47a874 --- /dev/null +++ b/po/README @@ -0,0 +1,13 @@ +How to add a translation file +***************************** +To add a translation file in linphone project you should first : + - add the file .po in the directory /po + - run ./autogen.sh + +Update the translation files +*************************** +To update all the translation files, in the directory /po run the following command + $ make update-po + + + diff --git a/po/ar.po b/po/ar.po new file mode 100644 index 000000000..182dc5b2b --- /dev/null +++ b/po/ar.po @@ -0,0 +1,2137 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# محيي الدين , 2014 +# محيي الدين , 2014-2015 +msgid "" +msgstr "" +"Project-Id-Version: linphone-gtk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-21 23:38+0000\n" +"Last-Translator: محيي الدين \n" +"Language-Team: Arabic (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/ar/)\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" + +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "اتصل بـ %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "أرسل رسالة إلى %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "المكالمات الفائتة (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "—" + +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "أُلغيت" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "فائتة" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "مرفوضة" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "%i دقيقة" +msgstr[1] "دقيقة واحدة" +msgstr[2] "دقيقتان" +msgstr[3] "%i دقائق" +msgstr[4] "%i دقيقة" +msgstr[5] "%i دقيقة" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "%i ثانية" +msgstr[1] "ثانية واحدة" +msgstr[2] "ثانيتان" +msgstr[3] "%i ثوان" +msgstr[4] "%i ثانية" +msgstr[5] "%i ثانية" + +#: ../gtk/calllogs.c:338 +#, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" +"%s\tالجودة : %s\n" +"%s\t%s\t" + +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 +msgid "Conference" +msgstr "اجتماع" + +#: ../gtk/conference.c:46 +msgid "Me" +msgstr "أنا" + +#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "أيقونة غير موجودة : %s" + +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 +msgid "log to stdout some debug information while running." +msgstr "أظهِرْ بعض معلومات التنقيح خلال التشغيل." + +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "عرض الإصدار ثم المغادرة" + +#: ../gtk/main.c:140 +msgid "path to a file to write logs into." +msgstr "الدليل إلى الملف الذي سيُكتَب فيه سجل الوقائع." + +#: ../gtk/main.c:141 +msgid "Start linphone with video disabled." +msgstr "ابدأ لِنْفُونْ لكن دون تفعيل الفيديو." + +#: ../gtk/main.c:142 +msgid "Start only in the system tray, do not show the main interface." +msgstr "شغِّله مُصغَّرا، ولا تُظهِر الواجهة الرئيسية." + +#: ../gtk/main.c:143 +msgid "address to call right now" +msgstr "العنوان المُراد الاتصال به الآن" + +#: ../gtk/main.c:144 +msgid "" +"Specifiy a working directory (should be the base of the installation, eg: c:" +"\\Program Files\\Linphone)" +msgstr "" +"حدِّد مجلد العمل (الذي سيكون مجلد التثبيت، مثلا c:\\Program Files\\Linphone)" + +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "ملف التهيئة" + +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "ابدأ مرشد الصوت" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "شغِّل الاختبار الذاتي ثم اخرِجْ 0 إذا نجح" + +#: ../gtk/main.c:1058 +#, c-format +msgid "" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" +"If you answer no, this person will be temporarily blacklisted." +msgstr "" +"يود %s إضافتك إلى جهات اتصاله.\n" +"هل تريد إضافته إلى جهات اتصالك والسماح له برؤية حالة حضورك ؟\n" +"إن كان الجواب بالرفض، سوف يجري حظر هذا الشخص مؤقتا." + +#: ../gtk/main.c:1135 +#, c-format +msgid "" +"Please enter your password for username %s\n" +" at realm %s:" +msgstr "" +"ادخل كلمة السر لـ %s\n" +" في نطاق %s:" + +#: ../gtk/main.c:1256 +msgid "Call error" +msgstr "خطأ في المكالمة" + +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 +msgid "Call ended" +msgstr "إنتهت المكالمة" + +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 +msgid "Incoming call" +msgstr "مكالمة واردة" + +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 +msgid "Answer" +msgstr "أجِبْ" + +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 +msgid "Decline" +msgstr "ارفضْ" + +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "المكالمة متوقفة" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "بواسطة %s" + +#: ../gtk/main.c:1342 +#, c-format +msgid "%s proposed to start video. Do you accept ?" +msgstr "يود %s تشغيل الفيديو. هل تقبل ذلك ؟" + +#: ../gtk/main.c:1508 +msgid "Website link" +msgstr "وصلة إلى الموقع وِبْ" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "لِنْفُونْ" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "الهاتف المرئي عبر الإنترنت" + +#: ../gtk/main.c:1627 +#, c-format +msgid "%s (Default)" +msgstr "%s (افتراضي)" + +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 +#, c-format +msgid "We are transferred to %s" +msgstr "التحويل إلى %s" + +#: ../gtk/main.c:1983 +msgid "" +"No sound cards have been detected on this computer.\n" +"You won't be able to send or receive audio calls." +msgstr "" +"لا وجود للوحة الصوت على هذا الحاسوب.\n" +"لن تتمكن من تلقي أو إجراء أي مكالمة." + +#: ../gtk/main.c:2127 +msgid "A free SIP video-phone" +msgstr "هاتف SIP المرئي الحر" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "أهلا\n" + +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "أضف إلى دفتر العناوين" + +#: ../gtk/friendlist.c:692 +msgid "Presence status" +msgstr "معلومة الحضور" + +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 +msgid "Name" +msgstr "الاسم" + +#: ../gtk/friendlist.c:722 +msgid "Call" +msgstr "اتصل" + +#: ../gtk/friendlist.c:727 +msgid "Chat" +msgstr "محادثة" + +#: ../gtk/friendlist.c:757 +#, c-format +msgid "Search in %s directory" +msgstr "ابحث في دليل %s" + +#: ../gtk/friendlist.c:926 +msgid "Invalid sip contact !" +msgstr "جهة اتصال sip غير صالحة !" + +#: ../gtk/friendlist.c:978 +#, c-format +msgid "Edit contact '%s'" +msgstr "حرر جهة الاتصال '%s'" + +#: ../gtk/friendlist.c:979 +#, c-format +msgid "Delete contact '%s'" +msgstr "احذف جهة الاتصال '%s'" + +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "احذف تاريخ دردشات '%s'" + +#: ../gtk/friendlist.c:1031 +#, c-format +msgid "Add new contact from %s directory" +msgstr "اضف جهة اتصال انطلاقا من الدليل %s" + +#: ../gtk/propertybox.c:597 +msgid "Rate (Hz)" +msgstr "التردد (هرتز)" + +#: ../gtk/propertybox.c:603 +msgid "Status" +msgstr "الحالة" + +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "صبيب IP (ك.بِتْ/ثانية)" + +#: ../gtk/propertybox.c:627 +msgid "Parameters" +msgstr "الإعدادات" + +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 +msgid "Enabled" +msgstr "مفعَّل" + +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 +msgid "Disabled" +msgstr "غير مفعَّل" + +#: ../gtk/propertybox.c:901 +msgid "Account" +msgstr "الحساب" + +#: ../gtk/propertybox.c:1169 +msgid "English" +msgstr "English" + +#: ../gtk/propertybox.c:1170 +msgid "French" +msgstr "Français" + +#: ../gtk/propertybox.c:1171 +msgid "Swedish" +msgstr "Svenska" + +#: ../gtk/propertybox.c:1172 +msgid "Italian" +msgstr "Italiano" + +#: ../gtk/propertybox.c:1173 +msgid "Spanish" +msgstr "Español" + +#: ../gtk/propertybox.c:1174 +msgid "Brazilian Portugese" +msgstr "Português do Brasil" + +#: ../gtk/propertybox.c:1175 +msgid "Polish" +msgstr "Polski" + +#: ../gtk/propertybox.c:1176 +msgid "German" +msgstr "Deutsch" + +#: ../gtk/propertybox.c:1177 +msgid "Russian" +msgstr "Русский" + +#: ../gtk/propertybox.c:1178 +msgid "Japanese" +msgstr "日本語" + +#: ../gtk/propertybox.c:1179 +msgid "Dutch" +msgstr "Nederlands" + +#: ../gtk/propertybox.c:1180 +msgid "Hungarian" +msgstr "Magyar" + +#: ../gtk/propertybox.c:1181 +msgid "Czech" +msgstr "Čeština" + +#: ../gtk/propertybox.c:1182 +msgid "Chinese" +msgstr "简体中文" + +#: ../gtk/propertybox.c:1183 +msgid "Traditional Chinese" +msgstr "繁体中文" + +#: ../gtk/propertybox.c:1184 +msgid "Norwegian" +msgstr "Norsk bokmål" + +#: ../gtk/propertybox.c:1185 +msgid "Hebrew" +msgstr "עברית" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Српски" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "العربية" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "Türkçe" + +#: ../gtk/propertybox.c:1245 +msgid "" +"You need to restart linphone for the new language selection to take effect." +msgstr "يجب إعادة تشغيل لِنْفُونْ لكي تٌفعَّل اللغة المختارة." + +#: ../gtk/propertybox.c:1325 +msgid "None" +msgstr "بدون" + +#: ../gtk/propertybox.c:1329 +msgid "SRTP" +msgstr "SRTP" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 +msgid "ZRTP" +msgstr "ZRTP" + +#: ../gtk/update.c:80 +#, c-format +msgid "" +"A more recent version is availalble from %s.\n" +"Would you like to open a browser to download it ?" +msgstr "" +"يوجد إصدار حديث من طرف %s.\n" +"هل تريد فتح المتصفح لتنزيله ؟" + +#: ../gtk/update.c:91 +msgid "You are running the lastest version." +msgstr "أنت تستخدم الإصدار الأحدث." + +#: ../gtk/buddylookup.c:85 +msgid "Firstname, Lastname" +msgstr "الاسم، اللقب" + +#: ../gtk/buddylookup.c:160 +msgid "Error communicating with server." +msgstr "خطأ في الاتصال مع الخادم." + +#: ../gtk/buddylookup.c:164 +msgid "Connecting..." +msgstr "يجري الاتصال..." + +#: ../gtk/buddylookup.c:168 +msgid "Connected" +msgstr "متصل" + +#: ../gtk/buddylookup.c:172 +msgid "Receiving data..." +msgstr "يجري تلقي البيانات..." + +#: ../gtk/buddylookup.c:180 +#, c-format +msgid "Found %i contact" +msgid_plural "Found %i contacts" +msgstr[0] "لم يُعثَر على أي جهة اتصال" +msgstr[1] "عُثِر على جهة اتصال واحدة" +msgstr[2] "عُثِر على جهتي اتصال" +msgstr[3] "عُثِر على %i جهات اتصال" +msgstr[4] "عُثِر على %i جهة اتصال" +msgstr[5] "عُثِر على %i جهة اتصال" + +#: ../gtk/setupwizard.c:160 +msgid "" +"Welcome!\n" +"This assistant will help you to use a SIP account for your calls." +msgstr "" +"مرحبا !\n" +"سيمكنك هذا المرشد من إعداد حسابك SIP لإجراء المكالمات." + +#: ../gtk/setupwizard.c:169 +msgid "Create an account on linphone.org" +msgstr "إنشاء حساب في linphone.org" + +#: ../gtk/setupwizard.c:170 +msgid "I have already a linphone.org account and I just want to use it" +msgstr "أتوفر مسبقا على حساب في linphone.org وأريد فقط استخدامه" + +#: ../gtk/setupwizard.c:171 +msgid "I have already a sip account and I just want to use it" +msgstr "أتوفر مسبقا على حساب sip وأريد فقط استخدامه" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "أريد تحديد عنوان التهيئة عن بعد" + +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "ادخل معلومات حسابك" + +#: ../gtk/setupwizard.c:221 +msgid "Username*" +msgstr "اسم المستخدم*" + +#: ../gtk/setupwizard.c:222 +msgid "Password*" +msgstr "كلمة السر*" + +#: ../gtk/setupwizard.c:225 +msgid "Domain*" +msgstr "النطاق*" + +#: ../gtk/setupwizard.c:226 +msgid "Proxy" +msgstr "الوكيل" + +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "أدخِل اسم المستخدم في linphone.org" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "اسم المستخدم :" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "كلمة السر :" + +#: ../gtk/setupwizard.c:419 +msgid "(*) Required fields" +msgstr "(*) حقول ضرورية" + +#: ../gtk/setupwizard.c:420 +msgid "Username: (*)" +msgstr "اسم المستخدم* : (*)" + +#: ../gtk/setupwizard.c:422 +msgid "Password: (*)" +msgstr "كلمة السر* : (*)" + +#: ../gtk/setupwizard.c:424 +msgid "Email: (*)" +msgstr "البريد الالكتروني : (*)" + +#: ../gtk/setupwizard.c:426 +msgid "Confirm your password: (*)" +msgstr "أكِّد كلمة السر : (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "أحطني علما بتحديثات لِنْفُونْ" + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "يُرجى الانتظار، يجري الآن إنشاء حسابك." + +#: ../gtk/setupwizard.c:494 +msgid "" +"Please validate your account by clicking on the link we just sent you by " +"email.\n" +"Then come back here and press Next button." +msgstr "" +"يُرجى تأكيد حسابك وذلك بالضغط على الوصلة التي أرسلناها لك بالبريد " +"الإلكتروني.\n" +"ثم ارجع إلى هنا واضغط على زر التالي." + +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "يُرجى الانتظار، يجري الآن فحص التحقق من صحة حسابك." + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"خطأ، لم يتم تأكيد الحساب، سبق استخدام اسم المستخدم أو تعذر الوصول للخادم.\n" +"يُرجى إعادة المحاولة لاحقا." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "شكرا لك، لقد جرت تهيئة حسابك وهو الآن قابل للاستخدام." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "مرشد تهيئة حساب SIP" + +#: ../gtk/setupwizard.c:578 +msgid "Welcome to the account setup assistant" +msgstr "مرحبا بك في مرشد إعداد الحساب" + +#: ../gtk/setupwizard.c:583 +msgid "Account setup assistant" +msgstr "مرشد تهيئة الحساب" + +#: ../gtk/setupwizard.c:588 +msgid "Configure your account (step 1/1)" +msgstr "تهيئة حسابك (المرحلة 1/1)" + +#: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "أدخل اسم المستخدم SIP (المرحلة 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "أدخل معلومات حسابك (المرحلة 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "إنشاء الحساب في تقدم" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "تأكيد (المرحلة 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "التحقق من الحساب في تقدم" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "خطأ" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "في طور الإنهاء" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "مكالمة #%i" + +#: ../gtk/incall_view.c:155 +#, c-format +msgid "Transfer to call #%i with %s" +msgstr "حوِّل إلى المكالمة #%i مع %s" + +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 +msgid "Not used" +msgstr "غير مستخدَم" + +#: ../gtk/incall_view.c:221 +msgid "ICE not activated" +msgstr "ICE غير مفعَّل" + +#: ../gtk/incall_view.c:223 +msgid "ICE failed" +msgstr "فَشِل ICE" + +#: ../gtk/incall_view.c:225 +msgid "ICE in progress" +msgstr "تجري مساومة ICE" + +#: ../gtk/incall_view.c:227 +msgid "Going through one or more NATs" +msgstr "المرور عبد واحد أو عدة NAT" + +#: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "مباشر" + +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "عبر خادم بديل" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP غير مفعَّل" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "يجري uPnP" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnP غير متوفر" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP مشغَّل" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "فَشِل uPnP" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "مباشرة أو عبر خادم" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 +#, c-format +msgid "" +"download: %f\n" +"upload: %f (kbit/s)" +msgstr "" +"التنزيل % f\n" +"الرفع : %f (ك.بِتْ/الثانية)" + +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f fps" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f ثانية" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "ضع السماعة" + +#: ../gtk/incall_view.c:510 +msgid "Calling..." +msgstr "يجري الاتصال..." + +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" + +#: ../gtk/incall_view.c:524 +msgid "Incoming call" +msgstr "المكالمة الواردة" + +#: ../gtk/incall_view.c:561 +msgid "good" +msgstr "جيدة" + +#: ../gtk/incall_view.c:563 +msgid "average" +msgstr "متوسطة" + +#: ../gtk/incall_view.c:565 +msgid "poor" +msgstr "ضعيفة" + +#: ../gtk/incall_view.c:567 +msgid "very poor" +msgstr "ضعيفة جدا" + +#: ../gtk/incall_view.c:569 +msgid "too bad" +msgstr "سيِّئة جيدا" + +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 +msgid "unavailable" +msgstr "غير متاحة" + +#: ../gtk/incall_view.c:715 +msgid "Secured by SRTP" +msgstr "آمن بواسطة SRTP" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "مُؤمَّن بواسطة DTLS" + +#: ../gtk/incall_view.c:727 +#, c-format +msgid "Secured by ZRTP - [auth token: %s]" +msgstr "آمن بواسطة ZRTP - [شارة الهوية : %s]" + +#: ../gtk/incall_view.c:733 +msgid "Set unverified" +msgstr "أكِّدْ عدم تحقُّقك" + +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 +msgid "Set verified" +msgstr "أكِّدْ تحقُّقَك" + +#: ../gtk/incall_view.c:762 +msgid "In conference" +msgstr "في اجتماع" + +#: ../gtk/incall_view.c:762 +msgid "In call" +msgstr "المكالمة جارية" + +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "المكالمة متوقفة مؤقتا" + +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "إنتهت المكالمة." + +#: ../gtk/incall_view.c:865 +msgid "Transfer in progress" +msgstr "يجري الإرسال" + +#: ../gtk/incall_view.c:868 +msgid "Transfer done." +msgstr "انتهى الإرسال." + +#: ../gtk/incall_view.c:871 +msgid "Transfer failed." +msgstr "فَشِل الإرسال." + +#: ../gtk/incall_view.c:904 +msgid "Resume" +msgstr "استأنِفْ" + +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 +msgid "Pause" +msgstr "إيقاف مؤقت" + +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"يسجل في\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(متوقف)" + +#: ../gtk/loginframe.c:75 +#, c-format +msgid "Please enter login information for %s" +msgstr "يُرجى إدخال معلومات الولوج ل %s" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "يجلب من %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "فَشِل تنزيل التهيئة عن بعد من %s ." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "لم يكتشف صوتاً" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "خافِت" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "جيد" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "صاخب" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "هل سمعت ثلاث رنات ؟" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "لم يعثر على تفضيلات الصوت" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "لم يتمكن من تشغيل التحكم في الصوت للنظام" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"مرحبا !\n" +"سيمكنك هذا المرشد من تهيئة إعدادات الصوت من أجل لِنْفُونْ" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "جهاز الالتقاط" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "الحجم المسجَّل" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "صامت" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "تفضيلات الصوت للنظام" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "جهاز السماع" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "شغِّل ثلاث رنَّات" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "اضغط على زر التسجيل وانطق ببعض الكلمات" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "استمع لصوتك المسجَّل" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "تسجيل" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "تشغيل" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "لنُشغِّل لِنْفُونْ الآن" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "مرشد الصوت" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "مرشد الصوت" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "معايرة كسب الميكروفون" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "معايرة شدة مكبر الصوت" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "سَجِّل واقرأ " + +#: ../gtk/main.ui.h:1 +msgid "All users" +msgstr "كل المستخدمين" + +#: ../gtk/main.ui.h:2 +msgid "Online users" +msgstr "المستخدمون المتصلون" + +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 +msgid "Fiber Channel" +msgstr "قناة الألياف الضوئية" + +#: ../gtk/main.ui.h:5 +msgid "Default" +msgstr "افتراضي" + +#: ../gtk/main.ui.h:6 +msgid "Delete" +msgstr "احذف" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "الخ_يارات" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "عنوان URI للتهيئة" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "شغِّل الفيديو دائما" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "فعِّل رؤية نفسي" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "ال_مساعدة" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "أظهِر نافذة التنقيح" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "موق_ع الوِبْ" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "تحقق من التح_ديثات" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "مرشد الحساب" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "عنوان SIP أو رقم الهاتف :" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "ابدأ مكالمة جديدة" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "جهات الاتصال" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "بحث" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "إضافة جهات الاتصال من الدليل" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "إضافة جهة الاتصال" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "المكالمات السابقة" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "هويتي الحالية :" + +#: ../gtk/about.ui.h:1 +msgid "About Linphone" +msgstr "حول لِنْفُونْ" + +#: ../gtk/about.ui.h:2 +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" + +#: ../gtk/about.ui.h:4 +msgid "An internet video phone using the standard SIP (rfc3261) protocol." +msgstr "الهاتف المرئي للإنترنت الموافق للبروتوكول المعياري SIP (rfc3261)‎." + +#: ../gtk/about.ui.h:5 +msgid "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" +msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" +"ar: Muhiyeddine Cherik \n" + +#: ../gtk/contact.ui.h:2 +msgid "SIP Address" +msgstr "عنوان SIP" + +#: ../gtk/contact.ui.h:3 +msgid "Show this contact presence status" +msgstr "رؤية حالة حضور جهة الاتصال هذه" + +#: ../gtk/contact.ui.h:4 +msgid "Allow this contact to see my presence status" +msgstr "السماح لجهة الاتصال هذه برؤية حالة حضوري" + +#: ../gtk/contact.ui.h:5 +msgid "Contact information" +msgstr "معلومات جهة الاتصال" + +#: ../gtk/log.ui.h:1 +msgid "Linphone debug window" +msgstr "نافذة تنقيح لِنْفُونْ" + +#: ../gtk/log.ui.h:2 +msgid "Scroll to end" +msgstr "مرِّر إلى الآخر" + +#: ../gtk/password.ui.h:1 +msgid "Linphone - Authentication required" +msgstr "لِنْفُونْ - يجب التحقق من الهوية" + +#: ../gtk/password.ui.h:2 +msgid "Please enter the domain password" +msgstr "أدخل كلمة سر النطاق" + +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 +msgid "UserID" +msgstr "مُعرِّف المستخدم" + +#: ../gtk/call_logs.ui.h:1 +msgid "Call history" +msgstr "تاريخ المكالمات" + +#: ../gtk/call_logs.ui.h:2 +msgid "Clear all" +msgstr "أفْرِغ الكل" + +#: ../gtk/call_logs.ui.h:3 +msgid "Call back" +msgstr "إعادة الاتصال" + +#: ../gtk/sip_account.ui.h:1 +msgid "Linphone - Configure a SIP account" +msgstr "لِنْفُونْ - تهيئة حساب SIP" + +#: ../gtk/sip_account.ui.h:2 +msgid "Your SIP identity:" +msgstr "هوية SIP لديك :" + +#: ../gtk/sip_account.ui.h:3 +msgid "Looks like sip:@" +msgstr "يشبه sip:@" + +#: ../gtk/sip_account.ui.h:4 +msgid "sip:" +msgstr "sip:" + +#: ../gtk/sip_account.ui.h:5 +msgid "SIP Proxy address:" +msgstr "عنوان وكيل SIP :" + +#: ../gtk/sip_account.ui.h:6 +msgid "Looks like sip:" +msgstr "يشبه sip:" + +#: ../gtk/sip_account.ui.h:7 +msgid "Registration duration (sec):" +msgstr "مدة التسجيل (بالثواني) :" + +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "إعدادات جهة الاتصال (اختيارية) :" + +#: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "مجال RTCP الاعتيادي ل AVPF (بالثواني) :" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "التوجيه (اختياري) :" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "النقل" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "التسجيل" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "انشر معلومات الحضور" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "فعِّل AVPF " + +#: ../gtk/sip_account.ui.h:15 +msgid "Configure a SIP account" +msgstr "تهيئة حساب SIP" + +#: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "مجهول" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 +msgid "default soundcard" +msgstr "لوحة الصوت الافتراضية" + +#: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "لوحة الصوت" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "الكاميرا الافتراضية" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" + +#: ../gtk/parameters.ui.h:8 +msgid "Audio codecs" +msgstr "مرمازات الصوت" + +#: ../gtk/parameters.ui.h:9 +msgid "Video codecs" +msgstr "مرمازات الفيديو" + +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "SIP (UDP)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "SIP (TCP)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "SIP (TLS)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "افتراضي" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "صبيب الإطارات مرتفع" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "مخصص" + +#: ../gtk/parameters.ui.h:17 +msgid "Settings" +msgstr "الإعدادات" + +#: ../gtk/parameters.ui.h:18 +msgid "This section defines your SIP address when not using a SIP account" +msgstr "هذه الفقرة تحدد عنوانك SIP إن كنت لا تستخدم حساب SIP" + +#: ../gtk/parameters.ui.h:19 +msgid "Your display name (eg: John Doe):" +msgstr "اسمك المعروض (مثلا : زيد عمرو) :" + +#: ../gtk/parameters.ui.h:20 +msgid "Your username:" +msgstr "اسم المستخدم :" + +#: ../gtk/parameters.ui.h:21 +msgid "Your resulting SIP address:" +msgstr "عنوانك SIP :" + +#: ../gtk/parameters.ui.h:22 +msgid "Default identity" +msgstr "الهوية الافتراضية" + +#: ../gtk/parameters.ui.h:23 +msgid "Wizard" +msgstr "المرشد" + +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "إضافة" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "حرر" + +#: ../gtk/parameters.ui.h:26 +msgid "Remove" +msgstr "أزل" + +#: ../gtk/parameters.ui.h:27 +msgid "Proxy accounts" +msgstr "حسابات الوكيل" + +#: ../gtk/parameters.ui.h:28 +msgid "Erase all passwords" +msgstr "احذف جميع كلمات السر" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "الأمان" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "الإجابة تلقائيا فور تلقي المكالمة" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "التأخير قبل الإجابة (ميلي ث,)" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "الإجابة تلقائيا" + +#: ../gtk/parameters.ui.h:33 +msgid "Manage SIP Accounts" +msgstr "إدارة حسابات SIP" + +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "صوت الجرس :" + +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "عتاد ALSA الخصوصي (اختياري) :" + +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "جهاز الالتقاط :" + +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "جهاز الرنين :" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "جهاز السمع :" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "فعِّل إزالة الصدى" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "الصوت" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "جهاز إدخال الفيديو :" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "المقدار المُراد لدقة الفيديو :" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "طريقة إخراج الفيديو :" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "اظهر معاينة الكاميرا" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "الفيديو المُسبَق :" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "المقدار المُراد لمعدل إطارات الفيديو :" + +#: ../gtk/parameters.ui.h:47 +msgid "0 stands for \"unlimited\"" +msgstr "حدِّد 0 لعدم وضع أي حد" + +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "الفيديو" + +#: ../gtk/parameters.ui.h:49 +msgid "Upload speed limit in Kbit/sec:" +msgstr "حد سرعة الرفع بالكيلوبِتْ/الثانية :" + +#: ../gtk/parameters.ui.h:50 +msgid "Download speed limit in Kbit/sec:" +msgstr "حد سرعة التنزيل بالكيلوبِتْ/الثانية :" + +#: ../gtk/parameters.ui.h:51 +msgid "Enable adaptive rate control" +msgstr "فعِّل التحكم المتكيف مع الصبيب" + +#: ../gtk/parameters.ui.h:52 +msgid "" +"Adaptive rate control is a technique to dynamically guess the available " +"bandwidth during a call." +msgstr "" +"التحكم المتكيف مع الصبيب هو تقنية لملائمة جودة الصوت والصورة بناءً على سعة " +"قناة الاتصال المتاحة خلال المكالمة." + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "إدارة سعة القناة" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "إعدادات الوسائط المتعددة" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "حدِّد Maximum Transmission Unit :" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "أرسِل الأرقام الهاتفية على هيئة SIP INFO" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "السماح باستخدام IPv6" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "النقل" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "منفذ SIP/UDP" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "عشوائي" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "منفذ SIP/TCP" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "صوت RTP/UDP :" + +#: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "ثابت" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "فيديو RTP/UDP :" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "نوع وسيط التعمية" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "وسيط التعمية إجباري" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "النفق" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "حقول DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "بروتوكول الشبكة والمنافذ" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "الاتصال مباشر بالإنترنت" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "وراء جدار ناري (حدِّد عنوان IP البوابة)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "وراء جدار ناري (استخدم STUN)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "وراء جدار ناري (استخدم ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "وراء جدار ناري (استخدم uPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "عنوان IP العمومي :" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "خادم STUN :" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "إعدادات حول الجدار الناري" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "إعدادات الشبكة" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "فعِّل" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "إلغاء التفعيل" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "مرمازات الصوت" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "مرمازات الفيديو" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "المراميز" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "اللغة" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "أظهر الإعدادات المتقدمة" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "المستوى" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "واجهة المستخدم" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "عنوان الخادم :" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "طريقة التحقق من الهوية :" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "تهيئة LDAP" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 +msgid "Done" +msgstr "أغلق" + +#: ../gtk/buddylookup.ui.h:1 +msgid "Search contacts in directory" +msgstr "البحث عن جهات الاتصال في الدليل" + +#: ../gtk/buddylookup.ui.h:2 +msgid "Add to my list" +msgstr "الإضافة إلى قائمتي" + +#: ../gtk/buddylookup.ui.h:3 +msgid "Search somebody" +msgstr "البحث عن شخص" + +#: ../gtk/waiting.ui.h:2 +msgid "Please wait" +msgstr "يُرجى الانتظار" + +#: ../gtk/dscp_settings.ui.h:1 +msgid "DSCP settings" +msgstr "إعدادات DSCP" + +#: ../gtk/dscp_settings.ui.h:2 +msgid "SIP" +msgstr "SIP" + +#: ../gtk/dscp_settings.ui.h:3 +msgid "Audio RTP stream" +msgstr "تدفق RTP الصوتي" + +#: ../gtk/dscp_settings.ui.h:4 +msgid "Video RTP stream" +msgstr "تدفق RTP المرئي" + +#: ../gtk/dscp_settings.ui.h:5 +msgid "Set DSCP values (in hexadecimal)" +msgstr "حدد قيم DSCP (بالنظام الست-عشري)" + +#: ../gtk/call_statistics.ui.h:1 +msgid "Call statistics" +msgstr "إحصاء المكالمات" + +#: ../gtk/call_statistics.ui.h:2 +msgid "Audio codec" +msgstr "مرمازات الصوت" + +#: ../gtk/call_statistics.ui.h:3 +msgid "Video codec" +msgstr "مرمازات الفيديو" + +#: ../gtk/call_statistics.ui.h:4 +msgid "Audio IP bandwidth usage" +msgstr "سعة القناة الصوتية" + +#: ../gtk/call_statistics.ui.h:5 +msgid "Audio Media connectivity" +msgstr "اتصالات الصوت" + +#: ../gtk/call_statistics.ui.h:6 +msgid "Video IP bandwidth usage" +msgstr "سعة قناة الفيديو" + +#: ../gtk/call_statistics.ui.h:7 +msgid "Video Media connectivity" +msgstr "اتصالات الفيديو" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "مدة الذهاب والإياب" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "حجم الفيديو المستلَم" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "حجم الفيديو المرسَل" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "تشكيلة RTP" + +#: ../gtk/call_statistics.ui.h:12 +msgid "Call statistics and information" +msgstr "إحصاء المكالمات والمعلومات" + +#: ../gtk/tunnel_config.ui.h:1 +msgid "Configure VoIP tunnel" +msgstr "تهيئة نفق VoIP" + +#: ../gtk/tunnel_config.ui.h:2 +msgid "Host" +msgstr "المضيف" + +#: ../gtk/tunnel_config.ui.h:3 +msgid "Port" +msgstr "المنفذ" + +#: ../gtk/tunnel_config.ui.h:6 +msgid "Configure tunnel" +msgstr "تهيئة النفق" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "اسم المستخدم" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "كلمة السر" + +#: ../gtk/tunnel_config.ui.h:9 +msgid "Configure http proxy (optional)" +msgstr "تهيئة وكيل http (اختياري)" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "إعدادات LDAP" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "استخدم TLS" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "غير متاح" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "الاتصال " + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "ربط DN" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "اسم الهوية" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "النطاق" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "الكائن الأساسي :" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "رشِّح (%s كاسم) :" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "خاصية الاسم :" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "خاصية عنوان SIP :" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "الخاصيات المبحوث عنها :" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "البحث" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "المهلة القصوى للبحث :" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "العدد الأقصى للنتائج :" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "متابعة الكنية" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "متفرقات" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "مجهول الهوية" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "بسيط" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "DIGEST-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "تحديد عنوان URI التهيئة عن بعد" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" +"يسمح لك مربع الحوار هذا بإعداد عنوان http أو https الذي من خلاله تود جلب " +"التهيئة عند بدء البرنامج.\n" +"أدخل العنوان أسفله. بعد تأكيد الأمر، ستجري إعادة تشغيل لِنْفُونْ تلقائيا من أجل " +"جلب والأخذ بعين الاعتبار الإعدادات الحديثة." + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "تجري التهيئة..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "رجاءً انتظر ريثما ينتهي من جلب الإعدادات من الخادم..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "أرسِلْ" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "اسم المنادَى" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "أنْهِ الاجتماع" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "سَجِّل هذه المكالمة في ملف صوتي" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "مرئي" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "اصمُتْ" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "إرسال" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "المكالمة جارية" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "المدة" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "تقييم جودة المكالمة" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "الاتصال بالإنترنت :" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "سَجِّل دخولي تلقائيا" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "معلومات الولوج" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "مرحبا !" + +#: ../coreapi/linphonecore.c:1483 +msgid "Ready" +msgstr "جاهز" + +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "تجري التهيئة" + +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 +msgid "Contacting" +msgstr "يتصل ب" + +#: ../coreapi/linphonecore.c:2805 +msgid "Could not call" +msgstr "لم يتمكن من الاتصال" + +#: ../coreapi/linphonecore.c:2956 +msgid "Sorry, we have reached the maximum number of simultaneous calls" +msgstr "آسف، وصل عدد المكالمات الآنية إلى حده الأقصى" + +#: ../coreapi/linphonecore.c:3114 +msgid "is contacting you" +msgstr "يتصل بك" + +#: ../coreapi/linphonecore.c:3115 +msgid " and asked autoanswer." +msgstr "ويطلب ردا تلقائيا." + +#: ../coreapi/linphonecore.c:3241 +msgid "Modifying call parameters..." +msgstr "يجري تعديل إعدادات المكالمة..." + +#: ../coreapi/linphonecore.c:3625 +msgid "Connected." +msgstr "متصل." + +#: ../coreapi/linphonecore.c:3650 +msgid "Call aborted" +msgstr "أُلغيت المكالمة" + +#: ../coreapi/linphonecore.c:3847 +msgid "Could not pause the call" +msgstr "لم يتمكن من توقيف المكالمة مؤقتا" + +#: ../coreapi/linphonecore.c:3850 +msgid "Pausing the current call..." +msgstr "وضع المكالمة قيد الانتظار..." + +#: ../coreapi/misc.c:436 +msgid "Stun lookup in progress..." +msgstr "يجري بحث STUN..." + +#: ../coreapi/misc.c:617 +msgid "ICE local candidates gathering in progress..." +msgstr "يجري جلب مرشَّحي ICE المحلين..." + +#: ../coreapi/friend.c:33 +msgid "Online" +msgstr "على الخط" + +#: ../coreapi/friend.c:36 +msgid "Busy" +msgstr "مشغول" + +#: ../coreapi/friend.c:39 +msgid "Be right back" +msgstr "سأعود" + +#: ../coreapi/friend.c:42 +msgid "Away" +msgstr "غائب" + +#: ../coreapi/friend.c:45 +msgid "On the phone" +msgstr "على الهاتف" + +#: ../coreapi/friend.c:48 +msgid "Out to lunch" +msgstr "أمام مائدة الطعام" + +#: ../coreapi/friend.c:51 +msgid "Do not disturb" +msgstr "لا تزعجني" + +#: ../coreapi/friend.c:54 +msgid "Moved" +msgstr "ذهبتُ" + +#: ../coreapi/friend.c:57 +msgid "Using another messaging service" +msgstr "أستخدم خدمة أخرى للتراسل الفوري" + +#: ../coreapi/friend.c:60 +msgid "Offline" +msgstr "غير متصل" + +#: ../coreapi/friend.c:63 +msgid "Pending" +msgstr "قيد الانتظار" + +#: ../coreapi/friend.c:66 +msgid "Vacation" +msgstr "في عطلة" + +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "حالة مجهولة" + +#: ../coreapi/proxy.c:295 +msgid "" +"The sip proxy address you entered is invalid, it must start with \"sip:\" " +"followed by a hostname." +msgstr "" +"إن عنوان SIP الذي أدخلت غير صحيح، يجب أن يبدأ بـ \"sip:‎\" متبوعا باسم المضيف." + +#: ../coreapi/proxy.c:301 +msgid "" +"The sip identity you entered is invalid.\n" +"It should look like sip:username@proxydomain, such as sip:alice@example.net" +msgstr "" +"إن هوية SIP التي أدخلت غير صحيحة.\n" +"يجب أن تكون بهذا النمط sip:username@proxydomain، مثلا sip:alice@example.net" + +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "يجري البحث عن وجهة رقم الهاتف..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "لم يتمكن من إيجاد هذا الرقم." + +#: ../coreapi/proxy.c:1407 +#, c-format +msgid "Could not login as %s" +msgstr "تعذر الولوج بالهوية %s" + +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "يجلب من %s" + +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "يرن الجرس عن بعد..." + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "يرن الجرس عن بعد..." + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "أخذ المكالمة مبكرا." + +#: ../coreapi/callbacks.c:548 +#, c-format +msgid "Call with %s is paused." +msgstr "المكاملة مع %s متوقفة." + +#: ../coreapi/callbacks.c:561 +#, c-format +msgid "Call answered by %s - on hold." +msgstr "يجيب %s عن المكالمة - في وضع الانتظار." + +#: ../coreapi/callbacks.c:571 +msgid "Call resumed." +msgstr "استُعيدت المكالمة." + +#: ../coreapi/callbacks.c:575 +#, c-format +msgid "Call answered by %s." +msgstr "أجاب عن المكالمة %s." + +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "غير موائم، تحقق من المراميز أو إعدادات الأمان..." + +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "إعدادات الوسائط غير موائمة." + +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "استُأنِفت المكالمة." + +#. we are being paused +#: ../coreapi/callbacks.c:642 +msgid "We are paused by other party." +msgstr "وُقِّفت المكالمة مؤقتا من طرف آخر." + +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 +msgid "Call is updated by remote." +msgstr "حُدِّث الاتصال من البعيد." + +#: ../coreapi/callbacks.c:797 +msgid "Call terminated." +msgstr "أُنهيت المكالمة." + +#: ../coreapi/callbacks.c:825 +msgid "User is busy." +msgstr "المستخدم مشغول." + +#: ../coreapi/callbacks.c:826 +msgid "User is temporarily unavailable." +msgstr "المستخدم غير متاح مؤقتا." + +#. char *retrymsg=_("%s. Retry after %i minute(s)."); +#: ../coreapi/callbacks.c:828 +msgid "User does not want to be disturbed." +msgstr "لا يريد المستخدم أي إزعاج." + +#: ../coreapi/callbacks.c:829 +msgid "Call declined." +msgstr "تم تجاهل المكالمة." + +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "انتهت مهلة الطلب." + +#: ../coreapi/callbacks.c:875 +msgid "Redirected" +msgstr "مُوجَّه" + +#: ../coreapi/callbacks.c:930 +msgid "Call failed." +msgstr "فشل الاتصال." + +#: ../coreapi/callbacks.c:1008 +#, c-format +msgid "Registration on %s successful." +msgstr "تم التسجيل في %s بنجاح." + +#: ../coreapi/callbacks.c:1009 +#, c-format +msgid "Unregistration on %s done." +msgstr "أُلغي التسجيل في %s ." + +#: ../coreapi/callbacks.c:1027 +msgid "no response timeout" +msgstr "لا إجابة قبل انتهاء المهلة" + +#: ../coreapi/callbacks.c:1030 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "فَشِل التسجيل في %s: %s" + +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "خدمة غير متاحة، تجري الإعادة" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "شارة التحقق من الهوية هي %s" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "عُدِّلت معاملات المكالمات بنجاج." + +#: ../coreapi/linphonecall.c:3904 +#, c-format +msgid "You have missed %i call." +msgid_plural "You have missed %i calls." +msgstr[0] "لم تفتك أي مكالمة." +msgstr[1] "فاتتك مكالمة واحدة." +msgstr[2] "فاتتك مكالمتان." +msgstr[3] "فاتتك %i مكالمات." +msgstr[4] "فاتتك %i مكالمة." +msgstr[5] "فاتتك %i مكالمة." + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "أُجهِضت" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "اكتملت" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "فاتت" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "مجهول" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s في %s\n" +"من : %s\n" +"إلى : %s\n" +"الحالة : %s\n" +"المدة : %i دقيقة %i ثانية\n" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "المكالمة الصادرة" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "لم يتمكن من تشغيل %s" diff --git a/po/cs.po b/po/cs.po index 4f499ac9b..3b8d4b0f9 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,86 +1,92 @@ -# translation of linphone.po to cs_CZ -# This file is distributed under the same license as the linphone package. -# Copyright (C) 2009 Simon Morlat (msgids) -# Klara Cihlarova , 2005. -# Petr Pisar , 2006, 2007, 2008, 2009, 2010, 2011. -# -# XXX: Don't translate gtk-* messages. They will be replaced from GTK+ -# catalogue. -# -# On hold → odložen -# Pause call → odložit hovor -# Resume call → obnovit hovor -# token → klíč -# Transfer → přepojit +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Klara Cihlarova , 2005 +# Petr Pisar , 2006-2011,2013 msgid "" msgstr "" -"Project-Id-Version: linphone-3.4.99.4\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2011-11-04 22:30+0100\n" -"Last-Translator: Petr Pisar \n" -"Language-Team: Czech \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Czech (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/cs/)\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: ../gtk/calllogs.c:82 -#, fuzzy -msgid "Aborted" -msgstr "přerušen" - -#: ../gtk/calllogs.c:85 -#, fuzzy -msgid "Missed" -msgstr "promeškán" - -#: ../gtk/calllogs.c:88 -#, fuzzy -msgid "Declined" -msgstr "Odmítnout" - -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 #, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgid "Call %s" +msgstr "Volat komu: %s" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 #, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgid "Send text to %s" +msgstr "Poslat text komu: %s" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:233 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" -msgstr "" +msgid "Recent calls (%i)" +msgstr "Nedávné hovory (%i)" -#: ../gtk/calllogs.c:102 +#: ../gtk/calllogs.c:315 msgid "n/a" msgstr "–" -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "Přerušen" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "Zmeškán" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "Odmítnut" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "%i minuta" +msgstr[1] "%i minuty" +msgstr[2] "%i minut" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "%i sekunda" +msgstr[1] "%i sekundy" +msgstr[2] "%i sekund" + +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" +"%s\tKvalita: %s\n" +"%s\t%s\t" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "Konference" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "Já" @@ -89,31 +95,35 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "Za běhu vypisuje některé ladicí informace na standardní výstup." -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "Soubor, kam zapisovat protokol." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Spustí linphone se zakázaným obrazem." -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "Spustí se pouze do systémové oblasti, nezobrazí hlavní okno." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "Zavolá právě teď na tuto adresu" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "je-li nastaveno, automaticky zvedne příchozí hovor" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -121,86 +131,91 @@ msgstr "" "Zadejte pracovní adresář (měl by být základní instalační adresář, například " "c:\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Hovor s %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s si vás chce přidat do svého adresáře.\n" -"Dovolíte mu, aby viděl váš stav přítomnosti, nebo si ho také chcete přidat " -"do svého adresáře?\n" -"Odpovíte-li ne, tato osobo bude dočasně blokována." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"Prosím, zadejte heslo pro uživatele %s\n" -"v doméně %s:" -#: ../gtk/main.c:1051 +#: ../gtk/main.c:1256 msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "Odpovědět" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Odmítnout" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 msgid "Call paused" msgstr "Hovor odložen" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "kým: %s" +msgid "by %s" +msgstr "kým: %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s navrhuje začít videohovor. Přijímáte?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "Odkaz na webovou stránku" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Lipnhone – internetový videofon" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (Výchozí)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "Byly jsme přepojeni na %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -208,177 +223,190 @@ msgstr "" "Na tomto počítači nebyla objevena žádná zvuková karta.\n" "Nebudete moci vytáčet a přijímat a zvukové hovory." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "Volný SIP videofon" -#: ../gtk/friendlist.c:335 -#, fuzzy -msgid "Add to addressbook" -msgstr "Zobrazit adresář" +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "Přidat do adresáře" + +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Stav" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Jméno" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Volat komu: %s" +msgstr "Zavolat" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Diskuzní skupina" +msgstr "Diskuze" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Hledat v adresáři %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "Neplatný sipový kontakt!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "Volat komu: %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Poslat text komu: %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Upravit kontakt „%s“" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Odstranit historii diskuze u kontaktu „%s“" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Přidat nový kontakt z adresáře %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Kmitočet (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Stav" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min. rychlost (kb/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parametry" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Povoleno" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Zakázáno" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Účet" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "angličtina" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "francouzština" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "švédština" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "italština" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "španělština" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "brazilská portugalština" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "polština" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "němčina" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "ruština" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "japonština" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "dánština" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "maďarština" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "čínština" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "tradiční čínština" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "norština" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" +msgstr "hebrejština" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "srbština" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Aby se projevil výběr nového jazyka, je nutné znovu spustit linphone." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "Žádná" +msgstr "Žádné" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "ZRTP" @@ -423,524 +451,564 @@ msgstr[0] "Nalezen %i kontakt" msgstr[1] "Nalezeny %i kontakty" msgstr[2] "Nalezeno %i kontaktů" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"Vítejte!\n" -"Tento průvodce vám pomůže používat sipový účet při vašich hovorech." -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "Vytvořit účet vybráním uživatelského jména" +msgstr "Vytvořit účet na linphone.org" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "Účet již mám a chci jej použít" +msgstr "Účet na linphone.org již mám a chci jej použít" -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "Účet již mám a chci jej použít" +msgstr "SIP účet již mám a chci jej použít" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:91 +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 +msgid "Username*" +msgstr "Uživatelské jméno*" + +#: ../gtk/setupwizard.c:222 +msgid "Password*" +msgstr "Heslo*" + +#: ../gtk/setupwizard.c:225 +msgid "Domain*" +msgstr "Doména*" + +#: ../gtk/setupwizard.c:226 +msgid "Proxy" +msgstr "Proxy" + +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Zadejte uživatelské jméno na linphone.org" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Uživatelské jméno:" -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Heslo:" -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 -#, fuzzy -msgid "Username*" -msgstr "Uživatelské jméno" - -#: ../gtk/setupwizard.c:121 -#, fuzzy -msgid "Password*" -msgstr "Heslo" - -#: ../gtk/setupwizard.c:124 -msgid "Domain*" -msgstr "" - -#: ../gtk/setupwizard.c:125 -msgid "Proxy" -msgstr "" - -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Povinné položky" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Uživatelské jméno:" +msgstr "Uživatelské jméno: (*)" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Heslo:" +msgstr "Heslo: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "E-mail: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" +msgstr "Potvrďte heslo: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Děkujeme vám. Váš účet je nyní nastaven a připraven k použití." - -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" +"Prosím, ověřte svůj účet tak, že kliknete na odkaz, který jsme vám právě " +"zaslali e-mailem.\n" +"Pak se sem vraťte a stiskněte tlačítko Další." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Došlo k chybě (účet nebyl ověřen, uživatelské jméno již existuje nebo server " +"není dostupný).\n" +"Prosím, vraťte se a zkoste to znovu." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Děkujeme vám. Váš účet je nyní nastaven a připraven k použití." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Vítejte v průvodci nastavení účtu" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "Nastavit SIP účet" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -#, fuzzy -msgid "Error" -msgstr "Chyba." +msgid "Configure your account (step 1/1)" +msgstr "Nastavit účet (krok 1/1)" #: ../gtk/setupwizard.c:592 -#, fuzzy -msgid "Terminating" -msgstr "Ukončit hovor" +msgid "Enter your sip username (step 1/1)" +msgstr "Zadejte vaše sipové uživatelské jméno (krok 1/1)" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Zadejte údaje o účtu (krok 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Ověření (krok 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Chyba" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "Ukončuje se" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "Hovor č. %i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Přepojit hovor č. %i s %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "Nenalezeno" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Nepoužito" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Filtr ICE" +msgid "ICE not activated" +msgstr "ICE není zapnuto" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "ICE selhalo" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "Probíhá ICE" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Přesměrováno" +msgid "Going through one or more NATs" +msgstr "Prochází se jedním nebo více NATy" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "Přímé" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Skrze relay server" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "UPnP není zapnuto" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "Probíhá UPnP" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "UPnP není nedostupné" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "UPnP běží" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "UPnP selhalo" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Přímé nebo skrze server" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"příchozí: %f\n" +"odchozí: %f (kb/s)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 -msgid "Hang up" +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f sekund" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "Zavěsit" + +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "Volá se…" -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +#, fuzzy +msgid "00:00:00" msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "dobrá" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "průměrná" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "slabá" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "velmi slabá" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "příliš špatná" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "nedostupná" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" +msgstr "Zabezpečeno pomocí SRTP" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "Zabezpečeno pomocí ZRTP – [ověřovací klíč: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "Nastavit na neověřeno" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "Nastavit na ověřeno" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "Probíhá konference" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "Probíhá hovor" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "Odložený hovor" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i:%02i:%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Hovor skončil." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "Probíhá přepojení" -#: ../gtk/incall_view.c:734 -#, fuzzy +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "Přepojit" +msgstr "Přepojení dokončeno." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Přepojit" +msgstr "Přepojení selhalo." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "Obnovit" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "Odložit" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Nahrává se do\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Odloženo)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Prosím, zadejte své přihlašovací jméno pro %s:" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -msgid "Callee name" -msgstr "Jméno volaného" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Odeslat" - -#: ../gtk/main.ui.h:3 -#, fuzzy -msgid "End conference" -msgstr "Probíhá konference" - -# XXX: Do not translate, this is GTK identifier -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "Přepojit" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "Telefonuje se" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Délka" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "Hodnocení kvality hovoru" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "V_olby" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Zobrazovat sám sebe" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "Nápo_věda" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "Zobrazit ladicí okno" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "_Domovská stránka" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "Vyhledat akt_ualizace" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "Průvodce nastavením účtu" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "SIP adresa nebo telefonní číslo:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "Zahájit nový hovor" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Přidat" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Upravit" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Hledat" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Přidat kontakty z adresáře" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "Přidat kontakt" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "Klávesnice" - -#: ../gtk/main.ui.h:49 -msgid "Recent calls" -msgstr "Nedávné hovory" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Moje současná totožnost:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Uživatelské jméno" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Heslo" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Připojení k Internetu:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Přihlašovat mě automaticky" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Informace o přihlášení" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Vítejte!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "všech uživatelích" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "připojených uživatelích" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "Fiber Channel" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "Výchozí" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" +msgstr "Smazat" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "V_olby" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" msgstr "" +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Vždy spustit obraz" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Zobrazovat sám sebe" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "Nápo_věda" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Zobrazit ladicí okno" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Domovská stránka" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Vyhledat akt_ualizace" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Průvodce účtem" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIP adresa nebo telefonní číslo:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Zahájit nový hovor" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Kontakty" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Hledat" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Přidat kontakty z adresáře" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Přidat kontakt" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Nedávné hovory" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Moje současná totožnost:" + #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "O Linphonu" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "© Belledonne Communications, 2010\n" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -959,18 +1027,8 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" -"fr: Simon Morlat\n" -"en: Simon Morlat a Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Písař \n" -"hu: anonym\n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -994,7 +1052,7 @@ msgstr "Ladicí okno Linphonu" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "" +msgstr "Přejít na konec" #: ../gtk/password.ui.h:1 msgid "Linphone - Authentication required" @@ -1004,7 +1062,7 @@ msgstr "Linphone – Ověření totožnosti vyžadováno" msgid "Please enter the domain password" msgstr "Prosím, zadejte heslo pro doménu" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "Identifikátor uživatele" @@ -1045,259 +1103,246 @@ msgid "Looks like sip:" msgstr "Vypadá jako sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Směrování (volitelné):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registrační období (s):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Směrování (volitelné):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Zaregistrovat se" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Zveřejnit stav přítomnosti" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Nastavit SIP účet" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "implicitní zvuková karta" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "zvuková karta" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "implicitní kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Kodeky zvuku" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Kodeky obrazu" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "Nastavení" -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Nastavit MTU (největší přenositelná zpráva):" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Odesílat tóny DTMF jako SIP INFO zprávy" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Používat IPv6 místo IPv4" - -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Přenos" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "Druh šifrování médií" - -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "Obrazový RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "Zvukový RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "Síťové protokoly a porty" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Přímé připojení do Internetu" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Za NAT/firewallem (adresu brány zadejte níže)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Veřejná IP adresa:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Za NAT/firewallem (adresu určí STUN)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Za NAT/firewallem (adresu určí STUN)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "STUN server:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT a firewall" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Nastavení sítě" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Vyzvánění:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Zvláštní ALSA zařízení (volitelné):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Zařízení pro nahrávání:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Zařízení pro vyzvánění:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Zařízení pro přehrávání:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Zapnout potlačení ozvěny" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Zvuk" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Vstupní zařízení obrazu:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Upřednostňované rozlišení obrazu:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Obraz" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Nastavení multimédií" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "Tento oddíl určuje vaši SIP adresu, když se nepoužívá žádný účet" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "Vaše zobrazované jméno (např. Jan Novák):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Vaše uživatelské jméno:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "Vaše výsledná SIP adresa:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Implicitní totožnost" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" -msgstr "" +msgstr "Průvodce" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Přidat" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Upravit" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Odstranit" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Proxy účty" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Vymazat všechna hesla" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Soukromí" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Nastavení SIP účtů" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Povolit" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Vyzvánění:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Zakázat" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Zvláštní ALSA zařízení (volitelné):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Kodeky" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Zařízení pro nahrávání:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Zařízení pro vyzvánění:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Zařízení pro přehrávání:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Zapnout potlačení ozvěny" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Zvuk" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Vstupní zařízení obrazu:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 znamená „neomezeno“" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Obraz" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Omezení odchozí rychlosti (kb/s):" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Omezení příchozí rychlosti (kb/s):" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" -msgstr "Zapnout přizpůsobující řízení rychlosti" +msgstr "Zapnout přizpůsobující se řízení rychlosti" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1305,31 +1350,163 @@ msgstr "" "Přizpůsobující se řízení rychlosti je technika dynamického odhadu " "dostupného pásma během hovoru." -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Využití šířky pásma" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Nastavení multimédií" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Nastavit MTU (největší přenositelná zpráva):" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Odesílat tóny DTMF jako SIP INFO zprávy" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Přenos" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "Zvukový RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Stálý" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Obrazový RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Druh šifrování médií" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Šifrování médií je povinné" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tunel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "Položky DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Síťové protokoly a porty" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Přímé připojení do Internetu" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Za NAT/firewallem (adresu určí STUN)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "Za NAT/firewallem (adresu určí ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "Za NAT/firewallem (adresu určí UPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Veřejná IP adresa:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN server:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT a firewall" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Nastavení sítě" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Povolit" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Zakázat" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Kodeky" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Jazyk" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "Zobrazit podrobnější nastavení" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Úroveň" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Uživatelské rozhraní" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Hotovo" @@ -1345,220 +1522,336 @@ msgstr "Přidat na svůj seznam" msgid "Search somebody" msgstr "Hledat někoho" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "Prosím, čekejte" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Nastavení" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "Převzorkování zvuku" +msgstr "RTP proud zvuku" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "Obrazový RTP/UDP:" +msgstr "RTP proud obrazu" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "Nastavit hodnoty DSCP (šestnáctkově)" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Informace o hovoru" +msgstr "Statistické údaje o hovoru" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Kodeky zvuku" +msgstr "Kodek zvuku" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Kodeky obrazu" +msgstr "Kodek obrazu" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Přenosová rychlost zvuku na úrovni IP" #: ../gtk/call_statistics.ui.h:5 -#, fuzzy -msgid "Media connectivity" -msgstr "Druh šifrování médií" +msgid "Audio Media connectivity" +msgstr "Zvukové spojení" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Přenosová rychlost obrazu na úrovni IP" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "Obrazové spojení" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Odezva" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Informace o kontaktu" +msgstr "Statistické a ostatní údaje o hovoru" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Nastavit SIP účet" +msgstr "Nastavit VoIP tunel" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Stroj" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "Port" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Nastavit tunel" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Uživatelské jméno" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Heslo" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" +msgstr "Nastavit HTTP proxy (volitelné)" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "přerušen" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "dokončen" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "promeškán" +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s v %s\n" -"Od: %s\n" -"Pro: %s\n" -"Stav: %s\n" -"Délka: %i min %i s\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Odchozí hovor" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Odeslat" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Jméno volaného" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Ukončit konferenci" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Nahrát tento hovor do zvukového souboru" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Obraz" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Ztišit" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Přepojit" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "Telefonuje se" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Délka" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Hodnocení kvality hovoru" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Připojení k Internetu:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Přihlašovat mě automaticky" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Informace o přihlášení" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Připraven." -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Vyhledává se umístění čísla…" - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Toto číslo nelze vyhledat." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"Špatně zadaná SIP adresa. Adresa má mít tento formát " -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" -msgstr "Kontaktuji" +msgstr "Navazuje se spojení" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "Nelze volat" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Je nám líto, ale byl dosažen maximální počet současných hovorů." -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "vás volá" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr " a požaduje automatickou zvednutí." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "." - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "Upravují se parametry hovoru…" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Připojeno." -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" -"volbu. Linphone však potřebuje ke své práci modul emulace\n" -"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" -"'modprobe snd-pcm-oss', kterým modul zavede." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" -"volbu. Linphone však potřebuje ke své práci modul mixer emulace\n" -"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" -"'modprobe snd-mixer-oss', kterým modul zavede." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "Hledá se adresa pomocí STUN…" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "Shromažďují se místní kandidáti ICE…" #: ../coreapi/friend.c:33 msgid "Online" -msgstr "Připojeno" +msgstr "Připojen" #: ../coreapi/friend.c:36 msgid "Busy" @@ -1586,33 +1879,37 @@ msgstr "Nerušit" #: ../coreapi/friend.c:54 msgid "Moved" -msgstr "Přestěhoval se" +msgstr "Přestěhoval jsem se" #: ../coreapi/friend.c:57 msgid "Using another messaging service" -msgstr "Používá jinou službu přenosu zpráv" +msgstr "Používám jinou službu přenosu zpráv" #: ../coreapi/friend.c:60 msgid "Offline" -msgstr "Odpojeno" +msgstr "Odpojen" #: ../coreapi/friend.c:63 msgid "Pending" -msgstr "Čeká" +msgstr "Čekám" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Neznámá chyba" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -"Adresa SIP proxy, kterou jste zadali, není platná. Musí začínat na „sip:“ a " +"Adresa SIP proxy, kterou jste zadali, není platná. Musí začínat na „sip:“ a " "pak musí následovat jméno stroje." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1620,126 +1917,144 @@ msgstr "" "SIP identita, kterou jste zadali, není platná.\n" "Měla by mít tvar sip:uživatel@proxydoména, například sip:alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Vyhledává se umístění čísla…" + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Toto číslo nelze vyhledat." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "Nelze se přihlásit jako %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "Vyzvání na druhé straně." -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." msgstr "Vyzvání na druhé straně…" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "Časná média." -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "Hovor s %s je odložen." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "Hovor přijat kým: %s – odložen." -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "Hovor obnoven." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "Hovor přijat kým: %s." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "" +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "Není slučitelné. Zkontrolujte nastavení kodeků a zabezpečení…" -#: ../coreapi/callbacks.c:437 -#, fuzzy +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Neslučitelné parametry médií." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "Byli jsme obnoveni…" +msgstr "Byli jsme obnoveni." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "Byli jsme odloženi protistranou." -#: ../coreapi/callbacks.c:452 -#, fuzzy +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "Hovor byl aktualizován protistranou…" +msgstr "Hovor byl aktualizován protistranou." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Hovor ukončen." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Uživatel je zaneprázdněn." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Uživatel je dočasně nedostupný." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "Uživatel si nepřeje být rušen." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Volání odmítnuto." -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "Žádná odpověď." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "Chyba protokolu." - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "Přesměrováno" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "Volání se nezdařilo." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registrace na %s byla úspěšná." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Odregistrování z %s hotovo." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "odpověď nedorazila včas" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrace na %s selhala: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 #, c-format msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1747,878 +2062,37 @@ msgstr[0] "Máte %i zmeškaný hovor." msgstr[1] "Máte %i zmeškané hovory." msgstr[2] "Máte %i zmeškaných hovorů." -#~ msgid "Chat with %s" -#~ msgstr "Diskuze s %s" - -#~ msgid "Please choose a username:" -#~ msgstr "Prosím, vyberte si uživatelské jméno:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Zjišťuji, zda-li je „%s“ přípustné…" - -#~ msgid "Please wait..." -#~ msgstr "Prosím, čekejte…" - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "Je nám líto, ale toto jméno již existuje. Prosím, zvolte jiné." - -#~ msgid "Ok !" -#~ msgstr "V pořádku!" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Chyba při komunikaci. Prosím, zkuste to později." - -#~ msgid "Choosing a username" -#~ msgstr "Výběr uživatelského jména" - -#~ msgid "Verifying" -#~ msgstr "Ověřování" - -#~ msgid "Confirmation" -#~ msgstr "Potvrzení" - -#~ msgid "Creating your account" -#~ msgstr "Vytváření účtu" - -#~ msgid "Now ready !" -#~ msgstr "Připraveno!" - -#~ msgid "Contacts" -#~ msgstr "Kontakty" - -#~ msgid "Enable video" -#~ msgstr "Zapnout video" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "" -#~ "Zadejte uživatelské jméno, telefonní číslo nebo plnou sipovou adresu" - -#~ msgid "Lookup:" -#~ msgstr "Hledat:" - -#~ msgid "in" -#~ msgstr "ve" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Zaregistrovat se do\n" -#~ "virtuální sítě FONICS!" - -#~ msgid "We are being paused..." -#~ msgstr "Jsme odkládáni…" - -#~ msgid "No common codecs" -#~ msgstr "Žádný společný formát" - -#~ msgid "Authentication failure" -#~ msgstr "Selhání ověření totožnosti" - -#~ msgid "Register at startup" -#~ msgstr "Zaregistrovat při spuštění" - -#~ msgid "Windows" -#~ msgstr "Okna" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "Odložit všechny hovory\n" -#~ "a odpovědět" - -#~ msgid "Unmute" -#~ msgstr "Nahlas" - -#~ msgid "Contact list" -#~ msgstr "Seznam kontaktů" - -#~ msgid "Audio & video" -#~ msgstr "Zvuk a obraz" - -#~ msgid "Audio only" -#~ msgstr "Pouze zvuk" - -#~ msgid "Duration:" -#~ msgstr "Délka:" - -#~ msgid "_Call history" -#~ msgstr "_Historie volání" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "Ports" -#~ msgstr "Porty" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "Je nám líto, ale nejprve musíte hovor odložit nebo ukončit!" - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "Již probíhá hovor, nejprve jej odložte nebo ukončete." - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "Kodér a-law ITU-G.711" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "Dekodér a-law ITU-G.711" - -#~ msgid "Alsa sound source" -#~ msgstr "Zdroj zvuku ALSA" - -#~ msgid "Alsa sound output" -#~ msgstr "Zvukový výstup ALSA" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "Filtr zachytávání zvuku přes MacOS X službu zvukové fronty" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "Filtr přehrávání zvuku přes MacOS X službu zvukové fronty" - -#~ msgid "DTMF generator" -#~ msgstr "Generátor DTMF" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "Kodek plnopásmového GSM" - -#~ msgid "The GSM codec" -#~ msgstr "GSM kodek" - -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "Filtr zachytávání zvuku přes MacOS X ovladač Audio Unit" - -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "Filtr přehrávání zvuku přes MacOS X ovladač Core Audio" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Filtr pro vytváření konferencí" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Čtení syrových souborů a souborů WAV" - -#~ msgid "Wav file recorder" -#~ msgstr "Nahrávání do souborů WAV" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "Filtr, který směšuje několik vstupů do jednoho výstupu." - -#~ msgid "RTP output filter" -#~ msgstr "Filtr RTP výstupu" - -#~ msgid "RTP input filter" -#~ msgstr "Filtr RTP vstupu" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "Svobodný a úžasný kodek speex" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "Filtr, který měří a řídí hlasitost zvuku" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "Zdrojový filtr kompatibilní s Video4Linux proudující obrázky." - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "Filtr zachytávající obrázky z Video4Linux2 kamer" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "Filtr, který vydává nehybný obrázek." - -#~ msgid "A pixel format converter" -#~ msgstr "Převodník formátu pixelů" - -#~ msgid "A video size converter" -#~ msgstr "Převaděč velikosti videa" - -#~ msgid "a small video size converter" -#~ msgstr "Převaděč velikosti malých videí" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "Potlačení ozvěny prostřednictvím knihovny speex" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "Filtr, který čte vstup a kopíruje ho více výstupů." - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "Kodér videa do theory od xiph.org" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "" -#~ "Kodek pro video „theora“ od xiph.org, který má otevřený zdrojový kód a je " -#~ "prostý licenčních poplatků" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Dekodér theora videa od xiph.org" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "Kodér µ-law ITU-G.711" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "Dekodér µ-law ITU-G.711" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "Dekodér H.263 používající knihovnu ffmpeg" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "Dekodér MPEG4 používající knihovnu ffmpeg" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "Dekodér RTP/JPEG používající knihovnu ffmpeg" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "Dekodér MPEG používající knihovnu ffmpeg" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "Dekodér snow používající knihovnu ffmpeg" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "Kodér H.263 používající knihovnu ffmpeg." - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "" -#~ "Kodér H.263 videa používající knihovnu ffmpeg. Vyhovuje staré specifikaci " -#~ "RFC 2190." - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "Kodér MPEG4 videa používající knihovnu ffmpeg." - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "Kodér snow videa používající knihovnu ffmpeg." - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "Kodér RTP/MJPEG používající knihovnu ffmpeg." - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "" -#~ "Kodér H.263 videa používající knihovnu ffmpeg, vyhovuje staré specifikaci " -#~ "RFC 2190." - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "Kodek snow není zatížen poplatky a má otevřený zdrojový kód.\n" -#~ "Využívá průkopnické techniky, které jej činí jedním z nejslibnějších " -#~ "video kodeků. Je implementován v projektu ffmpeg.\n" -#~ "Avšak stále se vyvíjí, je trochu nestabilní a kompatibilita s ostatními " -#~ "verzemi není zaručena." - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "Kodér MJPEG používající knihovnu ffmpeg." - -#~ msgid "A SDL-based video display" -#~ msgstr "Zobrazování videa přes SDL" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "Zdrojový filtr kompatibilní s video4windows proudující obrázky." - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "" -#~ "Zdrojový filtr založený na videu pro windows (vwf.h) pro zachytávání " -#~ "obrázků." - -#~ msgid "" -#~ "A filter that trashes its input (useful for terminating some graphs)." -#~ msgstr "" -#~ "Filtr, který zahazuje svůj vstup (užitečné na zakončení některých grafů)." - -#~ msgid "Parametric sound equalizer." -#~ msgstr "Parametrický ekvalizér zvuku." - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "Snímač kamer postavený na directshow." - -#~ msgid "A video display based on windows DrawDib api" -#~ msgstr "Zobrazovaní videa přes API Windows DrawDib" - -#~ msgid "A filter that mixes down 16 bit sample audio streams" -#~ msgstr "Filtr, který smísí 16b vzorkované zvukové proudy" - -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "Filtr, který převádí mono na stereo a obráceně." - -#~ msgid "Inter ticker communication filter." -#~ msgstr "Komunikační filtr mezitiku." - -#~ msgid "A display filter sending the buffers to draw to the upper layer" -#~ msgstr "Zobrazovací filtr odesílající buffery na vykreslení do vyšší vrstvy" - -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "Filtr zachytávání zvuku přes MacOS X službu Audio Unit" - -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "Filtr přehrávání zvuku přes MacOS X službu Audio Unit" - -#~ msgid "A video display using X11+Xv" -#~ msgstr "Zobrazovaní videa pomocí X11+Xv" - -#~ msgid "Sound capture filter for Android" -#~ msgstr "Zvukový zachytávací filtr pro Android" - -#~ msgid "Sound playback filter for Android" -#~ msgstr "Zvukový přehrávací filtr pro Android" - -#~ msgid "A filter that captures Android video." -#~ msgstr "Filtr, který zachytává obraz za Androidu." - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Zdá se, že váš počítač je připojen do IPv6 sítě. Standardně linphone " -#~ "používá pouze IPv4. Prosím, změňte nastavení programu, pokud chcete " -#~ "používat IPv6." - -#~ msgid "Call answered - connected." -#~ msgstr "Hovoř přijat – spojen." - -#~ msgid "Incoming call from %s" -#~ msgstr "Příchozí hovor od %s" - -#~ msgid "Assistant" -#~ msgstr "Průvodce" - -#~ msgid "Show debug messages" -#~ msgstr "Zobrazit ladicí zprávy" - -#~ msgid "Start call" -#~ msgstr "Zahájit hovor" - -#~ msgid "_Modes" -#~ msgstr "Reži_my" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "Vytvořil Simon Morlat\n" - -#~ msgid "Accept" -#~ msgstr "Přijmout" - -#~ msgid "Incoming call from" -#~ msgstr "Příchozí hovor od" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone – Příchozí hovor" - -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "" -#~ "Kodeky zvuku\n" -#~ "Kodeky obrazu" - -#~ msgid "default soundcard\n" -#~ msgstr "implicitní zvuková karta\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "Vzdálený konec se asi odpojil, hovor bude ukončen." - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Promiňte, vedení více současných hovorů není podporováno!" - -#~ msgid "Digits" -#~ msgstr "Číslice" - -#~ msgid "Main view" -#~ msgstr "Hlavní zobrazení" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Žádná adresa NATu/firewallu nebyla zadána!" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Neplatná adresa NATu '%s': '%s" - -#~ msgid "Could not reach destination." -#~ msgstr "Cíl je nedostupný." - -#~ msgid "Request Cancelled." -#~ msgstr "Dotaz přerušen." - -#~ msgid "Bad request" -#~ msgstr "Chybný dotaz" - -#~ msgid "User cannot be found at given address." -#~ msgstr "Uživatele nelze na dané adrese zastihnout." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "Vzdálený uživatel nemá podporu pro žádný z navržených kodeků." - -#~ msgid "Timeout." -#~ msgstr "Vypršení časového limitu." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Vzdálený počítač byl nalezen, ale odmítl připojení." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Uživatel je nedostupný, ale navrhuje tyto alternativní\n" -#~ "setkání:" - -#~ msgid "Gone" -#~ msgstr "Pryč" - -#~ msgid "Waiting for Approval" -#~ msgstr "Čekám na schválení" - -#~ msgid "Be Right Back" -#~ msgstr "Na chvíli pryč" - -#~ msgid "On The Phone" -#~ msgstr "Na příjmu" - -#~ msgid "Out To Lunch" -#~ msgstr "Na obědě" - -#~ msgid "Closed" -#~ msgstr "Zavřeno" - -#~ msgid "Unknown" -#~ msgstr "Stav není znám" - -#~ msgid "SIP address" -#~ msgstr "SIP adresa" - -#~ msgid "Bresilian" -#~ msgstr "brazilská portugalština" - -#~ msgid "_View" -#~ msgstr "_Zobrazit" - -#~ msgid "A video for macosx compatible source filter to stream pictures." -#~ msgstr "Zdrojový filtr kompatibilní s MacOS X videem proudující obrázky." - -#~ msgid "" -#~ "Show All\n" -#~ "Show Online" -#~ msgstr "" -#~ "Zobrazovat vše\n" -#~ "Zobrazovat připojené" - -#~ msgid "Display filters" -#~ msgstr "Filtry pro zobrazení" - -#~ msgid "I'm not behing a firewall" -#~ msgstr "Nejsem za firewallem" - -#~ msgid "I'm behind a firewall, use supplied public IP address" -#~ msgstr "Jsem za firewallem, použij zadanou veřejnou IP adresu" - -#~ msgid "Use the supplied stun server above and do as best as possible" -#~ msgstr "Použij výše zadaný STUN server a snaž se, jak nejlépe umíš" - -#~ msgid "Miscelaneous" -#~ msgstr "Různé" - -#~ msgid "Go" -#~ msgstr "Soubor" - -#~ msgid "Shows calls" -#~ msgstr "Zobrazit volání" - -#~ msgid "Exit" -#~ msgstr "Ukončit" - -#~ msgid "..." -#~ msgstr "…" - -#~ msgid "Proxy to use:" -#~ msgstr "Proxy:" - -#~ msgid "" -#~ "Call or\n" -#~ "answer" -#~ msgstr "" -#~ "Volat nebo\n" -#~ "přijmout" - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Zavěsit nebo\n" -#~ "odmítnout" - -#~ msgid "Or chat !" -#~ msgstr "Nebo poslat zprávu!" - -#~ msgid "Show more..." -#~ msgstr "Zobrazit více…" - -#~ msgid "Playback level:" -#~ msgstr "Úroveň přehrávání:" - -#~ msgid "Recording level:" -#~ msgstr "Úroveň nahrávání:" - -#~ msgid "Ring level:" -#~ msgstr "Úroveň vyzvánění:" - -#~ msgid "Controls" -#~ msgstr "Ovládání" - -#~ msgid "Reachable" -#~ msgstr "Dosažitelný" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Mám práci, jsem zpět za " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "Druhá strana bude informována, že se vrátíte za X minut" - -#~ msgid "mn" -#~ msgstr "min" - -#~ msgid "Moved temporarily" -#~ msgstr "Dočasně mimo" - -#~ msgid "Alternative service" -#~ msgstr "Alternativní služba" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Přítomnost" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Zadejte čísla pro zaslání DTMF." - -#~ msgid "" -#~ " 3\n" -#~ "def" -#~ msgstr "" -#~ " 3\n" -#~ "def" - -#~ msgid "" -#~ " 2\n" -#~ "abc" -#~ msgstr "" -#~ " 2\n" -#~ "abc" - -#~ msgid "" -#~ " 4\n" -#~ "ghi" -#~ msgstr "" -#~ " 4\n" -#~ "ghi" - -#~ msgid "" -#~ " 5\n" -#~ "jkl" -#~ msgstr "" -#~ " 5\n" -#~ "jkl" - -#~ msgid "" -#~ " 6\n" -#~ "mno" -#~ msgstr "" -#~ " 6\n" -#~ "mno" - -#~ msgid "" -#~ " 7\n" -#~ "pqrs" -#~ msgstr "" -#~ " 7\n" -#~ "pqrs" - -#~ msgid "" -#~ " 8\n" -#~ "tuv" -#~ msgstr "" -#~ " 8\n" -#~ "tuv" - -#~ msgid "" -#~ " 9\n" -#~ "wxyz" -#~ msgstr "" -#~ " 9\n" -#~ "wxyz" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Přátelé online" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "© 2001\n" -#~ "Vyrobeno ve Staré Dobré Evropě" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone je program pro IP telefonii.\n" -#~ "Je kompatibilní s protokoly SIP a RTP." - -#~ msgid "http://www.linphone.org" -#~ msgstr "http://www.linphone.org/" - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Použít IPv6 síť (je-li dostupná)" - -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "" -#~ "Jestliže jste v síti podporující IPv6 protokol a chcete-li, aby jej " -#~ "linphone používal, zapněte tuto volbu." - -#~ msgid "Global" -#~ msgstr "Obecné" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Tato volba je určena pouze pro uživatele v intranetu za firewallem. Pokud " -#~ "to není váš případ, nevyplňujte." - -#~ msgid "No firewall" -#~ msgstr "Bez firewallu" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "Pro odhad veřejné adresy použít tento STUN server:" - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Veřejná adresa firewallu:" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "Volby průchodu NATem (experimentální)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Velikosti vyrovnávací fronty v milisekundách (potlačení rozptylu):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "RTP port pro zvuk:" - -#~ msgid "RTP properties" -#~ msgstr "RTP vlastnosti" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "Místo RTP rfc2833 použít pro DTMF přenos SIP INFO zprávu" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "Doporučeno je RTP-RFC2833." - -#~ msgid "Other" -#~ msgstr "Ostatní" - -#~ msgid "micro" -#~ msgstr "mikrofon" - -#~ msgid "Recording source:" -#~ msgstr "Zdroj nahrávání:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "Potlačit ozvěnu (projeví se na druhém konci)" - -#~ msgid "Choose file" -#~ msgstr "Vyberte soubor" - -#~ msgid "Listen" -#~ msgstr "Test" - -#~ msgid "Sound properties" -#~ msgstr "Vlastnosti zvuku" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Spustit uživatelského agenta SIP na portu:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Je doporučeno používat port 5060." - -#~ msgid "SIP port" -#~ msgstr "SIP port" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Identita" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Přidat proxy/registraci" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "Vyprázdnit všechny ověřovací informace (uživatelské jméno, heslo…)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Seznam audio kodeků podle preference:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Poznámka: Kodeky označené červeně nelze u vašeho typu připojení použít." - -#~ msgid "No information availlable" -#~ msgstr "Nejsou dostupné žádné informace" - -#~ msgid "Codec information" -#~ msgstr "Informace o kodeku" - -#~ msgid "Address Book" -#~ msgstr "Adresář" - -#~ msgid "Select" -#~ msgstr "Vybrat" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Uživatel je momentálně nedostupný, ale navrhuje tyto alternativní formy " -#~ "kontaktu:" - -#~ msgid "None." -#~ msgstr "Žádné." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Konfigurace proxy a registrace" - -#~ msgid "Send registration:" -#~ msgstr "Odeslat registraci:" - -#~ msgid "Name:" -#~ msgstr "Jméno:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Pravidlo přihlášení:" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Odeslat přihlášení (podle online stavu osoby)" - -#~ msgid "New incoming subscription" -#~ msgstr "Nové příchozí přihlášení" - -#~ msgid "You have received a new subscription..." -#~ msgstr "Obdrželi jste nové přihlášení…" - -#~ msgid "Refuse" -#~ msgstr "Odmítnout" - -#~ msgid "Authentication required for realm" -#~ msgstr "pro doménu je vyžadováno ověření" - -#~ msgid "userid:" -#~ msgstr "ID uživatele:" - -#~ msgid "realm:" -#~ msgstr "doména:" - -#~ msgid "Text:" -#~ msgstr "Text:" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "Volající žádá o rezervaci zdrojů. Souhlasíte?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "Volající nepoužívá rezervaci zdrojů. \t\t\t\t\tChcete přesto pokračovat?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "linphone – příchozí hovor z %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "Obdrželi jste přihlášení od %s. Znamená to, že si tato osoba přeje být " -#~ "informována o vašem stavu přítomnosti (online, zaneprázdněn, pryč…).\n" -#~ "Souhlasíte?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Pro doménu %s je vyžadováno ověření" - -#~ msgid "Wait" -#~ msgstr "Zdržet" - -#~ msgid "Deny" -#~ msgstr "Odmítnout" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "Špatně zadaná SIP adresa: SIP adresa má tvar sip:uživatel@doména" - -#~ msgid "Stun lookup done..." -#~ msgstr "STUN vyhledávání dokončeno…" - -#~ msgid "enter sip uri here" -#~ msgstr "Sem zadejte SIP URI" - -#~ msgid "User manual" -#~ msgstr "Uživatelská příručka" - -#~ msgid "Ring sound selection" -#~ msgstr "Výběr zvonění" - -#~ msgid "Communication ended." -#~ msgstr "Komunikace ukončena." - -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "Vnější IP adresa firewallu (v tečkové notaci):" - -#~ msgid "Index" -#~ msgstr "Rejstřík" - -#~ msgid "28k modem" -#~ msgstr "28k modem" - -#~ msgid "56k modem" -#~ msgstr "56k modem" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64k modem" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL nebo kabelový modem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet nebo podobný" - -#~ msgid "Connection type:" -#~ msgstr "Typ připojení:" - -#~ msgid "Server address" -#~ msgstr "Adresa serveru:" - -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone nemůže otevřít zvukové zařízení %s. Překontrolujte nastavení a " -#~ "funkčnost zvukové karty." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "Zde zadejte SIP adresu osoby, které si přejete volat." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Přijmout nebo\n" -#~ "odmítnout" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. Zkusit znovu po %i min." +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/de.po b/po/de.po index 6a0b322f7..9fd715fe7 100644 --- a/po/de.po +++ b/po/de.po @@ -1,73 +1,93 @@ -# SIP Telephony Application. -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. -# Simon Morlat , 2001. -# Gerhard Stengel , 2011, 2012. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# andreas, 2014 +# andreas, 2014 +# Ettore Atalan , 2015 +# Gerhard Stengel , 2011-2012 +# Simon Morlat , 2001 msgid "" msgstr "" -"Project-Id-Version: linphone 0.7.1\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2012-11-07 19:27+0100\n" -"Last-Translator: Gerhard Stengel \n" -"Language-Team: German \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: German (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/de/)\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8-bit\n" -"X-Generator: Lokalize 1.5\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "„%s“ anrufen" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Text zu „%s“ schicken" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "Letzte Anrufe (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "n/v" + +#: ../gtk/calllogs.c:318 msgid "Aborted" msgstr "Abgebrochen" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "Entgangen" +msgstr "Verpasst" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:324 msgid "Declined" msgstr "Abgewiesen" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i Minute" msgstr[1] "%i Minuten" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i Sekunde" msgstr[1] "%i Sekunden" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -"%s\t%s\tQualität: %s\n" -"%s\t%s %s\t" +"%s\tQualität: %s\n" +"%s\t%s\t" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "nicht verfügbar" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" -msgstr "" +msgid "%s\t%s" +msgstr "%s\t%s" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "Konferenz" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "Eigenes Telefon" @@ -76,33 +96,37 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "Version anzeigen und beenden." + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "Linphone mit ausgeschaltetem Video starten." -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "" "Nur im Systemabschnitt der Kontrollleiste starten, aber das Hauptfenster " "nicht zeigen." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "Im Moment anzurufende Adresse" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "Falls aktiviert, werden eingehende Anrufe automatisch beantwortet" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,86 +134,93 @@ msgstr "" "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. " "C:\\Programme\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Im Gespräch mit %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Konfigurationsdatei" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Starte den Audio-Assistent" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Selbsttest ausführen und mit 0 beenden, wenn erfolgreich" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s möchte Sie zu seiner Kontaktliste hinzufügen.\n" -"Möchten Sie ihm erlauben, Ihren Anwesenheitsstatus zu sehen, oder ihn zu " -"Ihrer Kontaktliste hinzufügen?\n" -"Wenn Sie mit Nein antworten, wird diese Person vorläufig blockiert." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"Geben Sie bitte Ihr Passwort für den Benutzernamen %s\n" -" auf der Domäne %s ein:" +"Bitte geben Sie Ihr Passwort für den Benutzernamen %s\n" +" für Bereich %s ein:" -#: ../gtk/main.c:1051 +#: ../gtk/main.c:1256 msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "Annehmen" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Abweisen" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 msgid "Call paused" msgstr "Anruf wird gehalten" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "von %s" +msgid "by %s" +msgstr "von %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s schlägt vor, eine Videoübertragung zu starten. Nehmen Sie an?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "Website-Verknüpfung" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - ein Internet-Video-Telefon" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "Ein Internet-Video-Telefon" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (Vorgabe)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "Vermittlung nach %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -197,179 +228,194 @@ msgstr "" "Auf diesem Rechner können keine Soundkarten gefunden werden.\n" "Sie können keine Audio-Anrufe tätigen oder entgegennehmen." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "Ein freies SIP-Video-Telefon" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "Hallo\n" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "Zum Adressbuch hinzufügen" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Anwesenheitsstatus" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Name" -#: ../gtk/friendlist.c:538 +#: ../gtk/friendlist.c:722 msgid "Call" msgstr "Anrufen" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Chat Raum" +msgstr "Chat" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Im %s-Verzeichnis suchen" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "Ungültiger SIP-Kontakt!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "„%s“ anrufen" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Text zu „%s“ schicken" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Kontakt „%s“ bearbeiten" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Lösche Gesprächshistorie von '%s'" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Rate (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min. Bitrate (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "IP Bit-Rate (kbit/s)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parameter" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Freigegeben" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Gesperrt" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Englisch" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Französisch" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Schwedisch" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italienisch" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Spanisch" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "Brasilianisches Portugiesisch" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polnisch" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Russisch" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "Japanisch" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Niederländisch" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Ungarisch" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Tschechisch" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "Chinesisch" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "Norwegisch" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" -msgstr "" +msgstr "Hebräisch" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Serbisch" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "Arabisch" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "Türkisch" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Linphone muss neu gestartet werden, damit die neue Spracheinstellung wirksam " "wird." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "Keinen" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" -msgstr "" +msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -411,95 +457,92 @@ msgid_plural "Found %i contacts" msgstr[0] "%i Kontakt gefunden" msgstr[1] "%i Kontakte gefunden" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" "Willkommen!\n" -"Dieser Assistent wird Ihnen dabei helfen, ein SIP-Konto für Ihre Anrufe zu " -"verwenden." +"Dieser Assistent hilft Ihnen dabei ein SIP-Konto einzurichten." -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "Ein Konto bei linphone.org erstellen." -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "" "Ich habe bereits ein Konto bei linphone.org und möchte es jetzt benutzen." -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" msgstr "Ich habe bereits ein SIP-Konto und möchte es jetzt benutzen." -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" -msgstr "Geben Sie Ihren Benutzernamen bei linphone.org ein." +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Ich möchte eine URI zur Fernkonfiguration angeben" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "Benutzername:" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "Geben Sie Ihre Zugangsdaten ein" -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "Passwort:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "Geben Sie Ihre Zugangsdaten ein." - -#: ../gtk/setupwizard.c:120 +#: ../gtk/setupwizard.c:221 msgid "Username*" msgstr "Benutzername*" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:222 msgid "Password*" msgstr "Passwort*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "Domäne*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "Proxy" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Geben Sie Ihren Benutzernamen bei linphone.org ein." + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Benutzername:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Passwort:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "(*) erforderliche Felder" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" msgstr "Benutzername: (*)" -#: ../gtk/setupwizard.c:300 +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" msgstr "Passwort: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "E-Mail: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "Bestätigen Sie Ihr Passwort: (*)" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" -"Fehler, Konto kann nicht bestätigt werden. Der Benutzername wird bereits\n" -"verwendet oder der Server ist unerreichbar.\n" -"Bitte gehen Sie zurück und versuchen Sie es noch einmal." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Halte mich über linphone Aktualisierungen auf dem laufenden" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" -"Danke. Ihr Konto ist nun fertig eingerichtet und kann verwendet werden." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "Ihr Konto wird erstellt, bitte warten." -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -509,77 +552,131 @@ msgstr "" "wir Ihnen soeben per E-Mail geschickt haben.\n" "Danach gehen Sie hierher zurück und drücken auf „Vor“." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "Es wird überprüft, ob Ihr Konto gültig ist, bitte warten." + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Fehler, Konto kann nicht bestätigt werden. Der Benutzername wird bereits\n" +"verwendet oder der Server ist unerreichbar.\n" +"Bitte gehen Sie zurück und versuchen Sie es noch einmal." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "" +"Danke. Ihr Konto ist nun fertig eingerichtet und kann verwendet werden." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "SIP-Konto-Einrichtungsassistent" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Willkommen zum Konto-Einrichtungsassistenten" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/setupwizard.c:565 +#: ../gtk/setupwizard.c:588 msgid "Configure your account (step 1/1)" msgstr "Konto einrichten (Schritt 1/1)" -#: ../gtk/setupwizard.c:570 +#: ../gtk/setupwizard.c:592 msgid "Enter your sip username (step 1/1)" msgstr "Geben Sie Ihren SIP-Benutzernamen ein (Schritt 1/1)" -#: ../gtk/setupwizard.c:574 +#: ../gtk/setupwizard.c:596 msgid "Enter account information (step 1/2)" msgstr "Geben Sie Ihre Zugangsdaten ein (Schritt 1/2)" -#: ../gtk/setupwizard.c:583 +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "Kontoerstellung läuft" + +#: ../gtk/setupwizard.c:605 msgid "Validation (step 2/2)" msgstr "Bestätigung (Schritt 2/2)" -#: ../gtk/setupwizard.c:588 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "Kontogültigkeitsprüfung läuft" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "Fehler" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "Fertigstellen" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "Anruf #%i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Vermittlung zum Anruf #%i mit %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "Nicht verwendet" -#: ../gtk/incall_view.c:219 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "ICE nicht aktiviert" -#: ../gtk/incall_view.c:221 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "ICE fehlgeschlagen" -#: ../gtk/incall_view.c:223 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "ICE läuft" -#: ../gtk/incall_view.c:225 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "Ein oder mehrere NATs werden durchquert" -#: ../gtk/incall_view.c:227 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "Direkt" -#: ../gtk/incall_view.c:229 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "Über einen Relay-Server" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP nicht aktiviert" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP läuft" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnp nicht verfügbar" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP läuft" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP fehlgeschlagen" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Direkt oder über Server" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" @@ -588,341 +685,342 @@ msgstr "" "Herunterladen: %f\n" "Hochladen: %f (kbit/s)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 -msgid "Hang up" -msgstr "" +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f bps" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f Sekunden" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "Auflegen" + +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "Verbindungsaufbau..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "gut" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "durchschnittlich" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "schlecht" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "sehr schlecht" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "zu schlecht" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "Gesichert durch SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "Gesichert durch DTLS" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "Auf „Ungeprüft“ setzen" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "Auf „Geprüft“ setzen" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "In Konferenz" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "Gehaltener Anruf" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Anruf beendet." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "Vermittlung läuft" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "Vermittlung abgeschlossen." -#: ../gtk/incall_view.c:737 +#: ../gtk/incall_view.c:871 msgid "Transfer failed." msgstr "Vermittlung fehlgeschlagen." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "Fortsetzen" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "Halten" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Recording into\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(pausiert)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Bitte geben Sie die Anmeldeinformationen für %s ein." +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "abrufen von %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Herunterladen der Fernkonfiguration von %s fehlgeschlagen" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Keine Stimme ermittelt" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "zu gering" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "gut" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "zu laut" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Haben Sie die drei Signaltöne gehört?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Toneinstellungen nicht gefunden" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Systemtonsteuerung kann nicht gestartet werden" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Willkommen!\n" +"Dieser Assistent hilft Ihnen die Audioeinstellungen für Linphone " +"einzurichten." + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Aufnahmegerät" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "aufgenommene Lautstärke" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Keine Stimme" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Systemtoneinstellungen" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Wiedergabegerät" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "spiele drei Pieptöne ab" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Drücken Sie den Aufnahmeknopf und sagen Sie etwas" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Hören Sie das Aufgenommene" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Aufnahme" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Wiedergabe" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Linphone jetzt starten" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Audio-Assistant" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Audio-Assistant" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Einrichtung MIkrofonverstärker" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Einrichtung Lautstärke" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "aufnehmen und abspielen" + #: ../gtk/main.ui.h:1 -msgid "Callee name" -msgstr "Name des Angerufenen" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Senden" - -#: ../gtk/main.ui.h:3 -#, fuzzy -msgid "End conference" -msgstr "In Konferenz" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "Vermittlung" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "Im Gespräch" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Dauer" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "Bewertung der Verbindungsqualität" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_Optionen" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "Video immer starten" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Selbstansicht ein" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "_Hilfe" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "Debug-Fenster anzeigen" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "Auf _Aktualisierungen überprüfen" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "Konto-Einrichtungsassistent" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "SIP-Adresse oder Telefonnummer:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "Einen neuen Anruf beginnen" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Hinzufügen" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Bearbeiten" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Suchen" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Kontakte aus einem Verzeichnis hinzufügen" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "Kontakt hinzufügen" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "Wähltastatur" - -#: ../gtk/main.ui.h:49 -msgid "Recent calls" -msgstr "Letzte Gespräche" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Aktuelle Identität:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Benutzername" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Passwort" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Internetverbindung:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Automatisch anmelden" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Anmeldeinformationen" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Willkommen !" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "Alle Teilnehmer" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "Angemeldete Teilnehmer" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "Glasfaserkabel" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "Vorgabe" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" -msgstr "" +msgstr "Löschen" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Optionen" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "Konfigurations URI angeben" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Video immer starten" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Selbstansicht ein" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Hilfe" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Debug-Fenster anzeigen" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Homepage" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Auf _Aktualisierungen überprüfen" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Konto-Einrichtungsassistent" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIP-Adresse oder Telefonnummer:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Einen neuen Anruf beginnen" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Kontakte" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Suchen" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Kontakte aus einem Verzeichnis hinzufügen" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Kontakt hinzufügen" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Letzte Gespräche" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Aktuelle Identität:" #: ../gtk/about.ui.h:1 -msgid "About linphone" +msgid "About Linphone" msgstr "Über Linphone" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -943,12 +1041,12 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" "it: Alberto Zanoni \n" "de: Jean-Jacques Sarton \n" -"\t Gerhard Stengel \n" "sv: Daniel Nylander \n" "es: Jesus Benitez \n" "ja: YAMAGUCHI YOSHIYA \n" @@ -956,6 +1054,7 @@ msgstr "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -989,7 +1088,7 @@ msgstr "Linphone - Authentifikation erforderlich" msgid "Please enter the domain password" msgstr "Bitte das Passwort der Domäne eingeben" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "Benutzer-ID" @@ -1030,260 +1129,248 @@ msgid "Looks like sip:" msgstr "Sieht aus wie sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (optional):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registrierungsdauer (sec):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Kontaktdetails (optional)" + #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "AVPF Standard RTCP Interval (sek):" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Route (optional):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Übertragung" + +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Registrieren" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Anwesenheitsstatus veröffentlichen" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Aktiviere AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "SIP-Konto einrichten" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "Anonym" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "Standard-Soundkarte" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "eine Soundkarte" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "Standard-Kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" -msgstr "" - -#: ../gtk/parameters.ui.h:5 -msgid "Audio codecs" -msgstr "Audio-Codecs" - -#: ../gtk/parameters.ui.h:6 -msgid "Video codecs" -msgstr "Video-Codecs" +msgstr "CIF" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" -msgstr "" +msgid "Audio codecs" +msgstr "Audiocodecs" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" -msgstr "" +msgid "Video codecs" +msgstr "Videocodecs" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" -msgstr "" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "SIP (UDP)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "SIP (TCP)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "SIP (TLS)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "Vorgabe" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "hohe-BpS" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "Benutzerdefiniert" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "Einstellungen" -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Maximum Transmission Unit setzen:" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "DTMFs als SIP-Info senden" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "IPv6 statt IPv4 verwenden" - -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Übertragung" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "Verschlüsselungstyp der Medien" - -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "Tunnel" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "DSCP-Felder" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "Fest" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "Netzwerkprotokoll und Ports" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Direkte Verbindung ins Internet" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Hinter NAT / Firewall (IP-Gateway darunter angeben)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Öffentliche IP-Adresse:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Hinter NAT / Firewall (STUN verwenden)" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Hinter NAT / Firewall (ICE verwenden)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "STUN-Server:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT und Firewall" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Netzwerkeinstellungen" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Klingelton:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Spezielles ALSA-Gerät (optional):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Aufnahmegerät:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Gerät für Klingelton:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Wiedergabegerät:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Echounterdrückung ein" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Video-Aufnahmegerät:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Bevorzugte Video-Auflösung:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Multimedia-Einstellungen" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "In diesem Bereich legen Sie Ihre SIP-Adresse fest, wenn Sie kein SIP-Konto " "verwenden." -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "Ihr angezeigter Name (z. B. Heinz Müller):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Ihr Benutzername:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "Sich ergebende SIP-Adresse:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Standard-Identität" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "Assistent" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Hinzufügen" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Bearbeiten" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Entfernen" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Proxy-Konten" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Alle Passwörter löschen" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Privatsphäre" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "Automatisch antworten, wenn ein Anruf eingeht" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "Verzögerung vor der Beantwortung (ms)" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "Automatische Antwort" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "SIP-Konten verwalten" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Freigeben" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Klingelton:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Sperren" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Spezielles ALSA-Gerät (optional):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Codecs" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Aufnahmegerät:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Gerät für Klingelton:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Wiedergabegerät:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Echounterdrückung ein" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Audio" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Video-Aufnahmegerät:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "Bevorzugte Videoauflösung:" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Methode zur Videoausgabe" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Kameravorschau anzeigen" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "Videovoreinstellung:" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "Bevorzugte Videobildfrequenz:" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 bedeutet „unbegrenzt“" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Upload-Bandbreite (kbit/sec):" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Download-Bandbreite (kbit/sec):" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "Adaptive Ratenregelung ein" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1291,31 +1378,163 @@ msgstr "" "Adaptive Ratenregelung ist eine Technik zur dynamischen Abschätzung der " "zur Verfügung stehenden Bandbreite während eines Anrufs." -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Bandbreiten-Einstellungen" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Multimedia-Einstellungen" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Maximum Transmission Unit setzen:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "DTMFs als SIP-Info senden" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "IPv6 erlauben" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Übertragung" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "SIP/UDP Port" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Zufällig" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "SIP/TCP Port" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "Audio RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Fest" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Video RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Verschlüsselungstyp der Medien" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Medienverschlüsselung erzwingen" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tunnel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "DSCP-Felder" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Netzwerkprotokoll und Ports" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Direkte Verbindung ins Internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Hinter NAT / Firewall (Gateway IP angeben)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Hinter NAT / Firewall (STUN verwenden)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "Hinter NAT / Firewall (ICE verwenden)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "Hinter NAT / Firewall (uPnP verwenden)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Öffentliche IP-Adresse:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN-Server:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT und Firewall" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Netzwerkeinstellungen" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Freigeben" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Sperren" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "Audiocodecs" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "Videocodecs" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Sprache" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "Fortgeschrittene Einstellungen anzeigen" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Detaillierung" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Benutzeroberfläche" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Server-Adresse" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Authentifizierungsmethode" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "LDAP-Kontoeinrichtung" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Fertig" @@ -1331,16 +1550,12 @@ msgstr "Zur Kontaktliste hinzufügen" msgid "Search somebody" msgstr "Kontaktsuche" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "Bitte warten" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" +msgid "DSCP settings" msgstr "DSCP-Einstellungen" #: ../gtk/dscp_settings.ui.h:2 @@ -1365,25 +1580,45 @@ msgstr "Anrufstatistik" #: ../gtk/call_statistics.ui.h:2 msgid "Audio codec" -msgstr "Audio-Codec" +msgstr "Audiocodec" #: ../gtk/call_statistics.ui.h:3 msgid "Video codec" -msgstr "Video-Codec" +msgstr "Videocodec" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "Genutzte IP-Bandbreite Audio" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" -msgstr "Medienanbindung" +msgid "Audio Media connectivity" +msgstr "Audio-Konnektivität" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" msgstr "Genutzte IP-Bandbreite Video" #: ../gtk/call_statistics.ui.h:7 +msgid "Video Media connectivity" +msgstr "Video-Konnektivität" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Umlaufzeit" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Videoauflösung empfangen" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Videoauflösung gesendet" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "RTP-Profil" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "Anrufstatistik und -informationen" @@ -1403,134 +1638,248 @@ msgstr "Port" msgid "Configure tunnel" msgstr "Tunnel einrichten" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Benutzername" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Passwort" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" -msgstr "HTTP-Proxy einrichten (optional)" +msgstr "Configure http proxy (optional)" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "abgebrochen" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "LDAP-Einstellungen" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "beendet" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "TLS-Verbindung verwenden" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "entgangen" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Aktuell nicht verfügbar" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "Verbindung" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "Bind-DN" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Authentifizierungsname" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Bereich" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "Basis-Objekt:" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "Filter (%s nach Name):" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "Name:" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "SIP-Adresse:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "Sucheigenschaft:" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "Suche" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "Zeitüberschreitung bei der Suche:" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "Max Ergebnisse:" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "folge Pseudonymen" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "Sonstiges" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "ANONYMOUS" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "SIMPLE" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "DIGEST-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "Eine URI zur FErnkonfiguration angeben" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s am %s\n" -"Von: %s\n" -"An: %s\n" -"Status: %s\n" -"Dauer: %i min %i sec\n" +"Diese Maske erlaubt Ihnen für das Laden der Konfiguration beim Programmstart " +"eine http- oder https-Adresse anzugeben.\n" +"Bitte geben Sie unten die Konfigurations-URI ein oder ändern diese. Nach dem " +"Bestätigen mit OK wird Linphone automatisch neustarten, um die neuen " +"Einstellungen zu übernehmen." -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Abgehender Anruf" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Einstellen..." -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" +"Bitte warten Sie während die Einstellungen vom Server abgerufen werden..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Senden" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Name des Angerufenen" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Konferenz beenden" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Speichere den Anruf in eine Audio-Datei" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Video" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Stumm" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Vermittlung" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "Im Gespräch" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Dauer" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Bewertung der Verbindungsqualität" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Internetverbindung:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Automatisch anmelden" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Anmeldeinformationen" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Willkommen!" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Bereit" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Telefonnummernziel wird gesucht..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Einstellen" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Diese Nummer kann nicht aufgelöst werden." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"SIP-Adresse kann nicht eingelesen werden. Eine SIP-Adresse hat folgenden " -"Aufbau " - -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Verbindungsaufbau" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "Anruf kann nicht getätigt werden." -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Die maximale Anzahl der gleichzeitigen Anrufe ist erreicht." -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "ruft Sie an" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr " und fragt nach automatischer Antwort." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "Die Anrufparameter werden verändert..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Verbunden." -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" -"Dies ist die beste Lösung; allerdings ist das von Linphone benötigte Modul\n" -"zur PCM-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" -"Systemverwalter den Befehl „modprobe snd-pcm-oss“ aus, um es zu laden." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" -"Dies ist die beste Lösung; allerdings ist das von Linphone benötigte Modul\n" -"zur Mixer-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" -"Systemverwalter den Befehl „modprobe snd-mixer-oss“ aus, um es zu laden." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "STUN-Ermittlung läuft..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "Lokale Kandidaten für ICE werden zusammengestellt..." @@ -1579,10 +1928,14 @@ msgid "Pending" msgstr "Ausstehend" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Unbekannter Fehler" +msgid "Vacation" +msgstr "Urlaub" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Unbekannter Status" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1590,7 +1943,7 @@ msgstr "" "Die von Ihnen eingegebene SIP-Proxy-Adresse ist ungültig, sie muss mit " "„sip:“ gefolgt vom Hostnamen beginnen." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1599,1086 +1952,187 @@ msgstr "" "Sie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:" "alice@beispiel.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Telefonnummernziel wird gesucht..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Diese Nummer kann nicht aufgelöst werden." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "Anmeldung als %s fehlgeschlagen" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "abrufen von %s" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "Klingeln bei der Gegenseite." -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." msgstr "Klingeln bei der Gegenseite..." -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." -msgstr "" +msgstr "nicht kompatibel, prüfe Codecs oder Sicherheitseinstellungen..." -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "Anruf mit %s wird gehalten." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "Der von %s entgegengenommene Anruf wird gehalten." -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "Anruf fortgesetzt." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "Anruf wird von %s entgegengenommen." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "Inkompatibel, überprüfen Sie die Codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "" +"Inkompatibel, überprüfen Sie die Codecs oder die Sicherheitseinstellungen..." -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Inkompatible Medienparameter." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "Anruf wird fortgesetzt." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "Anruf wird von der Gegenseite gehalten." -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "Anruf ist von der Gegenseite aktualisiert worden." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Anruf beendet." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Teilnehmer ist besetzt." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Teilnehmer zur Zeit nicht verfügbar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "Teilnehmer möchte nicht gestört werden." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Anruf abgewiesen" -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "Keine Antwort." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "Zeitüberschreitung bei der Anfrage" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "Protokollfehler" - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "Umgeleitet" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "Inkompatible Medienparameter." - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "Anruf fehlgeschlagen." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registrierung auf %s erfolgreich." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Abmeldung von %s ist erfolgt." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "Zeitüberschreitung bei der Antwort" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrierung auf %s fehlgeschlagen: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Service nicht verfügbar, versuche erneut" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 #, c-format msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "Anrufparameter wurden erfolgreich geändert." + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Sie haben %i Anruf in Abwesenheit." msgstr[1] "Sie haben %i Anrufe in Abwesenheit." -#~ msgid "Chat with %s" -#~ msgstr "Chat mit %s" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "Teilnehmer, Telefonnummer oder vollständige SIP-Adresse eingeben" - -#~ msgid "Lookup:" -#~ msgstr "Suchen:" - -#~ msgid "in" -#~ msgstr "in" - -#~ msgid "Contacts" -#~ msgstr "Kontakte" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Am virtuellen FONICS\n" -#~ "Netzwerk anmelden!" - -#~ msgid "Enable video" -#~ msgstr "Video ein" - -#~ msgid "edit" -#~ msgstr "Bearbeiten" - -#~ msgid "No common codecs" -#~ msgstr "Keine gemeinsamen Codecs" - -#~ msgid "Authentication failure" -#~ msgstr "Authentifikation fehlgeschlagen" - -#~ msgid "We are being paused..." -#~ msgstr "Anruf wird gehalten..." - -#~ msgid "Please choose a username:" -#~ msgstr "Bitte einen Benutzernamen auswählen:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Die Verfügbarkeit von „%s“ wird überprüft..." - -#~ msgid "Please wait..." -#~ msgstr "Bitte warten..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "" -#~ "Leider existiert dieser Benutzername bereits. Bitte versuchen sie es mit " -#~ "einem anderen." - -#~ msgid "Ok !" -#~ msgstr "OK!" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Kommunikationsproblem, bitte versuchen Sie es später noch einmal." - -#~ msgid "Choosing a username" -#~ msgstr "Benutzername wird ausgewählt" - -#~ msgid "Verifying" -#~ msgstr "Überprüfen" - -#~ msgid "Confirmation" -#~ msgstr "Bestätigung" - -#~ msgid "Creating your account" -#~ msgstr "Erstellen Ihres Kontos" - -#~ msgid "Now ready !" -#~ msgstr "Fertig!" - -#~ msgid "Register at startup" -#~ msgstr "Beim Starten registrieren" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "Alle Anrufe halten\n" -#~ "und annehmen" - -#~ msgid "Unmute" -#~ msgstr "Stumm aus" - -#~ msgid "Contact list" -#~ msgstr "Kontaktliste" - -#~ msgid "Audio & video" -#~ msgstr "Audio & Video" - -#~ msgid "Audio only" -#~ msgstr "Nur Audio" - -#~ msgid "Duration:" -#~ msgstr "Dauer:" - -#~ msgid "_Call history" -#~ msgstr "Anrufchronik" - -#~ msgid "Ports" -#~ msgstr "Ports" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "Sie müssen zuerst den aktuellen Anruf halten oder beenden!" - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "" -#~ "Es wird bereits ein Anruf verarbeitet. Halten oder beenden Sie ihn zuerst." - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw Encoder" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw Dekoder" - -#~ msgid "Alsa sound source" -#~ msgstr "ALSA-Sound-Quelle" - -#~ msgid "Alsa sound output" -#~ msgstr "ALSA-Sound-Ausgabe" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "Sound-Aufnahmefilter für den Audio-Warteschlangendienst auf MacOS X" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "" -#~ "Sound-Wiedergabefilter für den Audio-Warteschlangendienst auf MacOS X" - -#~ msgid "DTMF generator" -#~ msgstr "DTMF-Generator" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "Der Full-Rate-GSM-Codec" - -#~ msgid "The GSM codec" -#~ msgstr "Der GSM-Codec" - -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "Sound-Aufnahmefilter für den Audio-Warteschlangendienst auf MacOS X" - -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "" -#~ "Sound-Wiedergabefilter für den Audio-Warteschlangendienst auf MacOS X" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Ein Filter zur Durchführung von Konferenzen" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Lesen von Roh- und WAV-Dateien" - -#~ msgid "Wav file recorder" -#~ msgstr "Aufnahme von WAV-Dateien" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "Ein Filter, der mehrere Eingaben an eine Ausgabe sendet." - -#~ msgid "RTP output filter" -#~ msgstr "RTP-Ausgabefilter" - -#~ msgid "RTP input filter" -#~ msgstr "RTP-Eingabefilter" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "Der freie und herrliche Speex-Codec" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "Ein Filter zur Steuerung und Messung der Lautstärke" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "Ein mit Video4Linux kompatibler Quellfilter, um Bilder zu streamen." - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "" -#~ "Ein Filter zur Aufzeichnung von durch Video4Linux2 unterstützten Kameras." - -#~ msgid "A filter that outputs a static image." -#~ msgstr "Ein Filter zur Ausgabe eines Standbilds" - -#~ msgid "A pixel format converter" -#~ msgstr "Ein Konverter für Pixelformate" - -#~ msgid "A video size converter" -#~ msgstr "Ein Konverter für die Größe von Videos" - -#~ msgid "a small video size converter" -#~ msgstr "Ein Konverter für die Größe von kleinen Videos" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "Echo-Unterdrückung unter Verwendung der Speex-Bibliothek" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "" -#~ "Ein Filter, der aus einer Eingabe liest und auf viele Ausgaben kopiert." - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "Der Theora-Video-Encoder von xiph.org" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "" -#~ "Der quelloffene und lizenzkostenfreie „Theora“-Video-Codec von xiph.org" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Der Theora-Video-Dekoder von xiph.org" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw Encoder" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw Dekoder" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "Ein H263-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "Ein MPEG4-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "Ein RTP/JPEG-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "Ein MJPEG-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "Ein Snow-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "Ein H263-Video-Dekoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "" -#~ "Ein H263-Video-Dekoder, der die ffmpeg-Bibliothek verwendet. Er erfüllt " -#~ "die alte RFC2190-Spezifikation." - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "Ein MPEG4-Video-Encoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "Ein Snow-Video-Encoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "Ein RTP/MJPEG-Encoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "" -#~ "Ein H263-Video-Encoder, der die ffmpeg-Bibliothek verwendet, der die " -#~ "alter RFC2190-Spezifikation erfüllt." - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "Der Snow-Codec ist lizenzkostenfrei und quelloffen.\n" -#~ "Er nutzt innovative Techniken, die ihn zu einem der vielversprechendsten " -#~ "Video-Codecs machen. Er ist im Rahmen des ffmpeg-Projekts implementiert.\n" -#~ "Jedoch ist er noch in der Entwicklung, ziemlich instabil und die " -#~ "Kompatibilität mit anderen Versionen ist nicht gewährleistet." - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "Ein MJPEG-Encoder, der die ffmpeg-Bibliothek verwendet" - -#~ msgid "A SDL-based video display" -#~ msgstr "Eine SDL-basierte Video-Anzeige" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "" -#~ "Ein zu video4windows kompatibler Quellfilter, um Bilder zu streamen." - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "" -#~ "Ein auf Video für Windows (vfw.h) basierender Quellfilter, um Bilder " -#~ "aufzuzeichnen." - -#~ msgid "" -#~ "A filter that trashes its input (useful for terminating some graphs)." -#~ msgstr "Ein Filter, der seine Eingabe vernichtet" - -#~ msgid "Parametric sound equalizer." -#~ msgstr "Parametrischer Sound-Equalizer" - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "Ein auf Directshow basierender Webcam-Grabber" - -#~ msgid "A video display based on windows DrawDib api" -#~ msgstr "Eine Video-Anzeige basierend auf der Windows DrawDib-API" - -#~ msgid "A filter that mixes down 16 bit sample audio streams" -#~ msgstr "Ein Filter, der 16-Bit-Sample Audio-Streams abmischt." - -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "Ein Filter, der von Mono nach Stereo und umgekehrt konvertiert." - -#~ msgid "Inter ticker communication filter." -#~ msgstr "Filter für die Inter-Ticker-Kommunikation" - -#~ msgid "A display filter sending the buffers to draw to the upper layer" -#~ msgstr "" -#~ "Ein Anzeigefilter, der die Puffer sendet, um die oberste Schicht zu " -#~ "zeichnen" - -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "Sound-Aufnahmefilter für den Audio-Unit-Dienst auf MacOS X" - -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "Sound-Wiedergabefilter für den Audio-Unit-Dienst auf MacOS X" - -#~ msgid "A video display using X11+Xv" -#~ msgstr "Eine Video-Anzeige, die X11 und Xv verwendet" - -#~ msgid "Sound capture filter for Android" -#~ msgstr "Sound-Aufnahmefilter für Android" - -#~ msgid "Sound playback filter for Android" -#~ msgstr "Sound-Wiedergabefilter für Android" - -#~ msgid "A filter that captures Android video." -#~ msgstr "Ein Filter, der Android-Video aufzeichnet." - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Ihr Rechner scheint an einen IPv6 Netz angeschlossen zu sein. " -#~ "Linphoneverwendet normalerweise IPv4. Bitte Konfiguration anpassen wenn " -#~ "sie IPv6 verwenden wollen" - -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Eingehendes Gespr�h" - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "Codecs" - -#~ msgid "Accept" -#~ msgstr "Annehmen" - -#, fuzzy -#~ msgid "Incoming call from" -#~ msgstr "Eingehendes Gespr�h" - -#, fuzzy -#~ msgid "Linphone - Incoming call" -#~ msgstr "Eingehendes Gespr�h" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "Audio und Video Codecs" - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Mehrfachen gleichzeitigen Anrufen nicht unterstützt !" - -#~ msgid "Could not reach destination." -#~ msgstr "Konnte Ziel nicht erreichen" - -#~ msgid "Request Cancelled." -#~ msgstr "Anruf annulliert." - -#~ msgid "Bad request" -#~ msgstr "Fehlerhafte Anfrage" - -#~ msgid "User cannot be found at given address." -#~ msgstr "Teilnehmer ist unter der angegebene Adresse nicht erreichbar." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "Die Gegenstelle untersttzt die angebotenen Codecs nicht." - -#~ msgid "Timeout." -#~ msgstr "Zeitberschreitung." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Die Gegenstelle hat die Verbindung abgewiesen." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Teilnehmer nicht erreichbar. Bitte versuchen Sie es unter nachstehender " -#~ "Ressource:" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Keine Nat/Firewall Adresse vorgegeben !" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Ungültige NAT Adresse '%s' : '%s'" - -#~ msgid "Gone" -#~ msgstr "Gegangen" - -#~ msgid "Waiting for Approval" -#~ msgstr "Warte aud Bestätigung" - -#~ msgid "Be Right Back" -#~ msgstr "Bald wieder da" - -#~ msgid "On The Phone" -#~ msgstr "Am Höhrer" - -#~ msgid "Out To Lunch" -#~ msgstr "Beim Essen" - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adresse" - -#, fuzzy -#~ msgid "_View" -#~ msgstr "Video" - -#, fuzzy -#~ msgid "Display filters" -#~ msgstr "Angezeigter Name:" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "RTP-Eigenschaften" - -#, fuzzy -#~ msgid "Show logs" -#~ msgstr "Zeigt Gespräche" - -#, fuzzy -#~ msgid "_About" -#~ msgstr "Konto" - -#, fuzzy -#~ msgid "Proxy in use" -#~ msgstr "Benutze Proxy-Server:" - -#~ msgid "Sound" -#~ msgstr "Ton" - -#, fuzzy -#~ msgid "Proxy accounts" -#~ msgstr "Benutze Proxy-Server:" - -#~ msgid "Go" -#~ msgstr "Start" - -#~ msgid "Address book" -#~ msgstr "Adressbuch" - -#~ msgid "Exit" -#~ msgstr "Beenden" - -#~ msgid "Shows the address book" -#~ msgstr "Adressbuch" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Auflegen\n" -#~ "oder Abweisen" - -#~ msgid "Or chat !" -#~ msgstr "Oder Chat" - -#~ msgid "Show more..." -#~ msgstr "Mehr anzeigen" - -#~ msgid "Playback level:" -#~ msgstr "Abhörpegel" - -#~ msgid "Recording level:" -#~ msgstr "Aufnamepegel" - -#~ msgid "Ring level:" -#~ msgstr "Klingelpegel" - -#~ msgid "Controls" -#~ msgstr "Kontrolle" - -#~ msgid "Reachable" -#~ msgstr "Erreichbar" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Beschäftigt, wieder erreichbar in " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "" -#~ "Der Teilnehmer wird informiert, dass Sie in X Minuten wieder anwesend " -#~ "sind." - -#~ msgid "mn" -#~ msgstr "mn" - -#~ msgid "Moved temporarily" -#~ msgstr "Unterwegs" - -#~ msgid "Alternative service" -#~ msgstr "Andere Dienste" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Anwesenheit" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Zifferntasten drücken, um DTMF zu senden" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Meine online Freunde" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "C: 2001\n" -#~ "In Alt Europa erzeugt" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone ist ein web-phone.\n" -#~ "Es ist mit den SIP- und RTP-Protokollen kompatibel." - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "IPv6 Netzwerk (falls vorhanden) verwenden" - -# msgstr "Teilnehmer zur Zeit nicht ansprechbar." -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "" -#~ "Ankreuzen wenn Sie ein ipv6 Netz haben und wenn Sie es wünschen dass " -#~ "linphone es verwendet" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Diese Option gilt nur für Anwender in einem privaten Netzwerk oder wenn " -#~ "der Rechner durch einen Firewall geschützt ist. Andernfalls wird das Feld " -#~ "nicht ausgefüllt" - -#~ msgid "No firewall" -#~ msgstr "Kein Firewall" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "Dieses STUN Server verwenden um die Firewalladresse zu Ermitteln" - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Firewall Adresse von Hand angeben" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "NAT-Transversaloptionen (experimentell)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Anzahl der gepufferten Pakete (Jitterausgleich):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "Sound RTP Port:" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "Benutze SIP INFO Nachricht statt RTP rfc2833 für DTMF Übertragung" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 wird empfohlen" - -#~ msgid "Other" -#~ msgstr "Andere" - -#~ msgid "micro" -#~ msgstr "Mikrofon" - -#~ msgid "Recording source:" -#~ msgstr "Aufnahmequelle:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "" -#~ "Echounterdrückung einschalten (eliminiert das von Gesprächspartnet " -#~ "gehörter Echo)" - -#~ msgid "Listen" -#~ msgstr "Anhören" - -#~ msgid "Sound properties" -#~ msgstr "Audio Eigenschaften" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Sip \"user agent\" an Port:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Wir empfehlen, Port 5060 zu verwenden" - -#~ msgid "SIP port" -#~ msgstr "SIP-Port" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Identität" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Proxy/Registrator hinzufügen" - -#~ msgid "Remote services" -#~ msgstr "Dienste auf entferntem Server" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "" -#~ "Alle gespeicherten Authentifikationsinformationen löschen (Benutzername, " -#~ "Passwort,...)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Liste von Audio-CoDecs in der Reihenfolge ihrer Präferenz" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Notiz: Rot markierten Codecs können bei Ihrer Internetverbindungsart " -#~ "nicht verwendet werden." - -#~ msgid "No information availlable" -#~ msgstr "Informationen nicht verfügbar" - -#~ msgid "Codec information" -#~ msgstr "Codec Information" - -#~ msgid "Address Book" -#~ msgstr "Adressbuch" - -#~ msgid "Select" -#~ msgstr "Auswählen" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Teilnehmer nicht erreichbar. Bitte stattdessen nachstehende Ressource " -#~ "verwenden:" - -#~ msgid "None." -#~ msgstr "Nichts." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/Registrator Konfigurationsbox" - -#~ msgid "Send registration:" -#~ msgstr "Sende Registrierung:" - -#~ msgid "Name:" -#~ msgstr "Name:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Subskription Police" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Sende Subskription (zeige Onlinestatus der Person an)" - -#~ msgid "New incoming subscription" -#~ msgstr "Neu ankommende Subskription" - -#~ msgid "You have received a new subscription..." -#~ msgstr "Sie haben eine neue Subskription empfangen" - -#~ msgid "Refuse" -#~ msgstr "Ablehnen" - -#~ msgid "Authentication required for realm" -#~ msgstr "Authentifikation erforderlich für Bereich" - -#~ msgid "userid:" -#~ msgstr "Benutzer ID:" - -#~ msgid "realm:" -#~ msgstr "Bereich:" - -#~ msgid "Text:" -#~ msgstr "Text" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "Der Anrufer erbittet Resourcenreservierung. Sind Sie einverstanden?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "Der Anrufer benutzt keine Resourcenreservierung. \t\t\t\t\tWollen Sie " -#~ "dennoch fortfahren?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "Linphone- empfängt ein Anruf von %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "Sie haben eine Subskription von %s empfangen. Das heißt, dass diese " -#~ "Person ber Ihre Anwesenheitsinformation benachrichtigt werden will " -#~ "(erreichbar, beschäftig, abwesend...).\n" -#~ "Sind Sie einverstanden ?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Authentifikation erforderlich für Bereich %s" - -#~ msgid "Wait" -#~ msgstr "Warten" - -#~ msgid "Deny" -#~ msgstr "Abweisen" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "" -#~ "Fehlerhafte Sip-Adresse. Eine Sip-Adresse hat folgenden Aufbau " - -#~ msgid "Stun lookup done..." -#~ msgstr "Stun Ermittlung beendet..." - -#~ msgid "enter sip uri here" -#~ msgstr "Sip URI eingeben" - -#~ msgid "User manual" -#~ msgstr "Anwender-Handbuch" - -#~ msgid "Ring sound selection" -#~ msgstr "Klingelton ausw�len" - -#~ msgid "Communication ended." -#~ msgstr "Kommunikation beendet." - -#, fuzzy -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "IP-Adresse des Firewall (in Punktnotation)" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Server-Adresse:" - -#~ msgid "28k modem" -#~ msgstr "28K Modem" - -#~ msgid "56k modem" -#~ msgstr "56K Modem" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64K Modem (ISDN)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL oder Kabel-Modem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet oder äquivalent" - -#~ msgid "Connection type:" -#~ msgstr "Verbindungstyp:" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone kann das Soundgerät nicht öffnen. Prfen Sie nach, ob die " -#~ "Soundkarte vollst�dig konfiguriert und funktionsfähig ist." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "" -#~ "Geben Sie die Sip-Adresse des Anwenders, den Sie anrufen möchten, hier " -#~ "ein." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Auflegen oder\n" -#~ "Abweisen" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. In %i Minuten wieder versuchen." - -#~ msgid "Timeout..." -#~ msgstr "Zeitüberschreitung..." - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "" -#~ "Bitte ankreuzen, wenn Sie auf einem Sip-Server registriert werden wollen." - -#~ msgid "Address of record:" -#~ msgstr "Adresse des Eintrags:" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "" -#~ "Passwort für die Registrierung. Bei manchen Servern nicht erforderlich." - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "Verwenden Sie diesen Registrarserver als externen proxy." - -#~ msgid "sip address:" -#~ msgstr "SIP-Adresse:" - -#~ msgid "Modify" -#~ msgstr "Ändern" - -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "Sie verwenden zur Zeit den i810_audio Treiber.\n" -#~ "Diese Treiber ist fehlerhaft und funktioniert nicht mit Linphone\n" -#~ "Wir empfehlen, den Treiber entweder durch das ALSA-Treiber-Paket von " -#~ "ihrer Distribution\n" -#~ "zu ersetzen oder die gewnschten ALSA-Treiber von http://www.alsa-project." -#~ "org\n" -#~ "zu beziehen und zu installieren" - -#~ msgid "Unregistration successfull." -#~ msgstr "Abmeldung erfolgreich." - -#~ msgid "Select network interface to use:" -#~ msgstr "Netzwerkschnittstelle wählen:" - -#~ msgid "Network interface properties" -#~ msgstr "Eigenschaften der Netzwerkschnittstelle" - -#~ msgid "RTP" -#~ msgstr "RTP" - -#~ msgid "C: 2001" -#~ msgstr "April 2001" - -#~ msgid "Threads not supported by glib. Upgrade your glib.\n" -#~ msgstr "" -#~ "Threads werden von glib nicht unterstützt. Bitte aktualisieren Sie Ihre " -#~ "glib.\n" - -#~ msgid "Run linphone as a gnome-applet." -#~ msgstr "Linphone als gnome-Applet ausfhren." - -#~ msgid "Run linphone as a daemon (for use without gnome)." -#~ msgstr "Linphone als daemon ausführen (Verwendung ohne Gnome)." - -#~ msgid "" -#~ "Cannot find network previously used interface %s.\n" -#~ "If your computer is temporary connected to the internet, please connect " -#~ "and then run linphone.\n" -#~ "If you want to change your default network interface, go to the " -#~ "parameters 'box." -#~ msgstr "" -#~ "Linphone konnte die zuvor verwendete Netzwerkschnittstelle %s nicht " -#~ "finden.\n" -#~ "Wenn linphone nur temporär am Internet angeschlossen ist, stellen Sie " -#~ "eine Verbindung her und rufen Sie linphone erneut auf.\n" -#~ "Wenn Sie die vorgegebene Netzwerkschnittstelle ändern wollen, wählen Sie " -#~ "bitte \"Einstellungen\"." - -#~ msgid "" -#~ "Linphone cannot open the audio device.\n" -#~ "It may be caused by other programs using it.\n" -#~ "Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht öffnen.\n" -#~ "Dies kann durch andere Applikationen verursacht sein.\n" -#~ "Möchten sie diese Programme (esd oder artsd) beenden?" - -#~ msgid "Use it as a:" -#~ msgstr "Verwenden als:" - -#~ msgid "Outbound proxy" -#~ msgstr "Ausgehender Proxy-Server" - -#~ msgid "" -#~ "Toggle this button if the registrar must be used to proxy calls through a " -#~ "firewall." -#~ msgstr "" -#~ "Verwenden Sie diesen Knopf, falls der Registrar zum Tunneln durch einen " -#~ "Firewall verwendet werden muß" - -#~ msgid "kbit/s" -#~ msgstr "Kbits/s" - -#~ msgid "OSS" -#~ msgstr "OSS" - -#~ msgid "ALSA" -#~ msgstr "ALSA" - -#~ msgid "Automatically kill applications using soundcard when needed" -#~ msgstr "Applikationen die die Soundkarte verwenden, automatisch beenden." - -#~ msgid "" -#~ "Your computer is connected to several networks. Check in the global " -#~ "parameters if Linphone uses the one that you want." -#~ msgstr "" -#~ "Ihr Rechner ist an mehere Netze angeschlossen. Stellen Sie sicher, daß in " -#~ "den Globalen Parametern die richtige Schnittstelle selektiert ist." - -#~ msgid "" -#~ "Linphone failed to open the sound device. See the README file included in " -#~ "the distribution for details." -#~ msgstr "" -#~ "Linphone konnte die Soundschnittstelle nicht öffnen. Weitere " -#~ "Informationen finden Sie in der README-Datei (enthalten in der " -#~ "Distribution)." - -#~ msgid "Interface not found." -#~ msgstr "Schnittstelle nicht gefunden." - -#~ msgid "Warning" -#~ msgstr "Warnung" - -#~ msgid "" -#~ "Linphone cannot open the sound device. It may be caused by other programs " -#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht öffnen. Dies kann durch andere " -#~ "Applikationen verursacht sein. Möchten sie diese Programme (esd oder " -#~ "artsd) beenden?" - -#~ msgid "Linphone shutdowns..." -#~ msgstr "Linphone Ende..." - -#~ msgid "" -#~ "Please, wait a few seconds untils linphone unregisters your sip addess " -#~ "from registrar server..." -#~ msgstr "Bitte einige Sekunden warten, bis Sip-Adresse ausgetragen ist." - -#~ msgid "Bad formuled sip address." -#~ msgstr "SIP-Adresse fehlerhaft." - -#~ msgid "Couldn't create pixmap from file: %s" -#~ msgstr "Konnte Pixmap nicht aus Datei %s erzeugen." - -#~ msgid "" -#~ "Linphone did not detect any valid network interface. If you use a " -#~ "temporary internet connection, please connect and then run linphone again." -#~ msgstr "" -#~ "Linphone konnte keine Netzwerkschnittstelle finden. Wenn Sie nur eine " -#~ "temporäre Internetverbindung haben, bitte erneut eine Internetverbindung " -#~ "herstellen und linphone nochmals starten." - -#~ msgid "List of network interfaces on your system." -#~ msgstr "Vorhandene Netzwerkschnittstellen ihres Systems" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "abgebrochen" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "abgeschlossen" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "verpasst" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "unbekannt" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s um %s\n" +"Von: %s\n" +"An: %s\n" +"Status: %s\n" +"Dauer: %i Min. %i Sek.\n" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "Ausgehender Anruf" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "Kann %s nicht wiedergeben." diff --git a/po/es.po b/po/es.po index 999a16446..82a9efe16 100644 --- a/po/es.po +++ b/po/es.po @@ -1,367 +1,409 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Free Software Foundation, Inc. -# FIRST AUTHOR , YEAR. -# -#, fuzzy +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: Linphone 0.9.1\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" -"Last-Translator: Nelson Benitez \n" -"Language-Team: es \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Spanish (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/es/)\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "Llamar a %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Enviar mensaje a %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "n/a" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "Llamada cancelada." +msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:321 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "linea" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i minuto" +msgstr[1] "%i minutos" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i segundo" +msgstr[1] "%i segundos" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" -msgstr "" +msgstr "Conferencia" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" -msgstr "" +msgstr "Yo" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "" +"registra a stdout cierta información de depuración durante la ejecución." -#: ../gtk/main.c:96 -msgid "path to a file to write logs into." +#: ../gtk/main.c:139 +msgid "display version and exit." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:140 +msgid "path to a file to write logs into." +msgstr "ruta a un fichero donde escribir logs." + +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "" +msgstr "Iniciar sólo en la barra de tareas, no mostrar la interfaz principal." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "" +msgstr "dirección a la que llamar inmediatamente" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" +"Especifique un directorio de trabajo (debería ser la raíz de la instalación, " +"ej: c:\\Archivos de Programa\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" +#: ../gtk/main.c:145 +msgid "Configuration file" msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Llamada cancelada." +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 -#, fuzzy +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "Llamada cancelada." +msgstr "" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" -msgstr "" +msgstr "Llamada entrante" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" -msgstr "" +msgstr "Contestar" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "linea" - -#: ../gtk/main.c:1067 -#, fuzzy -msgid "Call paused" -msgstr "Llamada cancelada." - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" +msgstr "Enlace a la Web" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" +#: ../gtk/main.c:1568 +msgid "A video internet phone" msgstr "" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "" +msgstr "%s (Opción predeterminada)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" -msgstr "" +msgstr "Somos transferidos a %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" +"No se ha encontrado una tarjeta de sonido en este equipo.\n" +"No será posible realizar o recibir llamadas de audio." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" +msgstr "Un video-teléfono SIP gratuito" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" msgstr "" -#: ../gtk/friendlist.c:335 -#, fuzzy +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" -msgstr "Agenda" +msgstr "" -#: ../gtk/friendlist.c:509 -#, fuzzy +#: ../gtk/friendlist.c:692 msgid "Presence status" -msgstr "Estado" +msgstr "" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nombre" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Llamada cancelada." +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" -msgstr "" +msgstr "Buscar en el directorio %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" -msgstr "" +msgstr "¡Contacto SIP no válido!" -#: ../gtk/friendlist.c:775 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format msgid "Edit contact '%s'" -msgstr "(Ninguna informacion de contacto !)" +msgstr "" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" +msgstr "Eliminar contacto '%s'" + +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" -msgstr "" +msgstr "Añadir nuevo contacto desde el directorio %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" -msgstr "" +msgstr "Frecuencia (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Estado" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" -msgstr "Parametros" +msgstr "Parámetros" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Activado" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Desactivado" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" -msgstr "" +msgstr "Cuenta" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" -msgstr "" +msgstr "Inglés" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" -msgstr "" +msgstr "Francés" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" -msgstr "" +msgstr "Sueco" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" -msgstr "" +msgstr "Italiano" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" -msgstr "" +msgstr "Español" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" -msgstr "" +msgstr "Portugués de Brasil" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" -msgstr "" +msgstr "Polaco" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" -msgstr "" +msgstr "Alemán" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" -msgstr "" +msgstr "Ruso" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" -msgstr "" +msgstr "Japonés" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" -msgstr "" +msgstr "Holandés" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" -msgstr "" +msgstr "Húngaro" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" -msgstr "" +msgstr "Checo" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" -msgstr "" +msgstr "Chino" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" -msgstr "" +msgstr "Chino Tradicional" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" -msgstr "" +msgstr "Noruego" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." -msgstr "" +msgstr "Deberá reiniciar linphone para aplicar la nueva selección de lenguaje" -#: ../gtk/propertybox.c:912 -#, fuzzy +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "Ninguno." +msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" +msgstr "SRTP" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -376,566 +418,584 @@ msgstr "" #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" -msgstr "" +msgstr "Nombre, Apellidos" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "" +msgstr "Error al comunicar con el servidor." #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "Conexion" +msgstr "" #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "Conectado." +msgstr "" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." -msgstr "" +msgstr "Recibiendo datos..." #: ../gtk/buddylookup.c:180 #, c-format msgid "Found %i contact" msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Se encontró %i contacto" +msgstr[1] "Se encontraron %i contactos" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "Manual de Usuario" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "Tu Contraseña:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "Manual de Usuario" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "Tu Contraseña:" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Manual de Usuario" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Tu Contraseña:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Gracias. Su cuenta está configurada y lista para su utilización." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" -msgstr "" +msgstr "Bienvenido al asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" -msgstr "" +msgstr "Asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:565 +#: ../gtk/setupwizard.c:588 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:570 +#: ../gtk/setupwizard.c:592 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:574 +#: ../gtk/setupwizard.c:596 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:583 +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:588 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format -msgid "Call #%i" -msgstr "Llamada cancelada." - -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format -msgid "Transfer to call #%i with %s" +msgid "Call #%i" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:155 +#, c-format +msgid "Transfer to call #%i with %s" +msgstr "Transferir a llamada #%i con %s" + +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:219 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Llamada cancelada." - #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -msgid "Direct" +msgid "Going through one or more NATs" msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Contactando " - -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" + +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Contactando " +msgstr "" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "" +msgstr "buena" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "" +msgstr "media" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "" +msgstr "mala" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "" +msgstr "muy mala" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "" +msgstr "demasiado mala" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "" +msgstr "no disponible" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" +msgstr "Cifrada con SRTP" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "Cifrada con ZRTP - [token de autenticación: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "Set sin verificar" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "Set verificado" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" -msgstr "" +msgstr "En conferencia" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Contactando " - -#: ../gtk/incall_view.c:669 -#, fuzzy -msgid "Paused call" -msgstr "Contactando " - -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:699 -#, fuzzy -msgid "Call ended." -msgstr "Llamada cancelada." +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "" + +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Llamada cancelada." +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "" +msgstr "Reanudar" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" +msgstr "Pausar" + +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" +msgstr "Por favor, introduzca los datos de inicio de sesión para %s" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" msgstr "" #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Llamada cancelada." +msgid "All users" +msgstr "Todos los usuarios" #: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "Sonido" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "Contactando " - -#: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "Informacion" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "Activado" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone esta terminando..." - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "La direccion SIP del servidor de registro." - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Añadir" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Informacion de codec" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "(Ninguna informacion de contacto !)" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "Contactando " - -#: ../gtk/main.ui.h:50 -#, fuzzy -msgid "My current identity:" -msgstr "Identidad" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Manual de Usuario" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Tu Contraseña:" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "Informacion de codec" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "Contactando " - -#: ../gtk/main.ui.h:57 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:58 -#, fuzzy msgid "Online users" -msgstr "linea" +msgstr "" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" +msgstr "Canal de Fibra" + +#: ../gtk/main.ui.h:5 +msgid "Default" msgstr "" -#: ../gtk/main.ui.h:61 -#, fuzzy -msgid "Default" -msgstr "Identidad" - -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Opciones" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Ayuda" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Pagina_de_Inicio" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Buscar_Actualizaciones" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Iniciar nueva llamada" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Buscar" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "" + #: ../gtk/about.ui.h:1 -#, fuzzy -msgid "About linphone" -msgstr "linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "" +"Un vídeo-teléfono a través de Internet que usa el protocolo estándar SIP " +"(rfc3261)" #: ../gtk/about.ui.h:5 msgid "" @@ -950,426 +1010,508 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "Direccion" +msgstr "" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" -msgstr "" +msgstr "Mostrar el estado de presencia de este contacto" #: ../gtk/contact.ui.h:4 msgid "Allow this contact to see my presence status" -msgstr "" +msgstr "Permitir que este contacto vea mi estado de presencia" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "Informacion de codec" +msgstr "" #: ../gtk/log.ui.h:1 -#, fuzzy msgid "Linphone debug window" -msgstr "Linphone esta terminando..." +msgstr "" #: ../gtk/log.ui.h:2 msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Informacion de codec" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" -msgstr "" +msgstr "Por favor introduzca la contraseña del dominio" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "UserID" #: ../gtk/call_logs.ui.h:1 msgid "Call history" -msgstr "" +msgstr "Registro de llamadas" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" -msgstr "" +msgstr "Borrar todos" #: ../gtk/call_logs.ui.h:3 msgid "Call back" -msgstr "" +msgstr "Devolver llamada" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" -msgstr "" +msgstr "Linphone - Configurar una cuenta SIP" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "Identidad" +msgstr "" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" -msgstr "" +msgstr "Del tipo sip:@" #: ../gtk/sip_account.ui.h:4 msgid "sip:" -msgstr "SIP:" +msgstr "sip:" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "Direccion SIP" +msgstr "" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" -msgstr "" +msgstr "Del tipo sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" +msgid "Registration duration (sec):" msgstr "" #: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Se ha registrado con exito." +msgid "Contact params (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "Informacion de codec" +msgid "Route (optional):" +msgstr "Ruta (opcional):" #: ../gtk/sip_account.ui.h:11 -msgid "Configure a SIP account" +msgid "Transport" msgstr "" +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Registrarse" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 +msgid "Configure a SIP account" +msgstr "Configurar una cuenta SIP" + #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" -msgstr "" +msgid "default soundcard" +msgstr "tarjeta de sonido predeterminada" #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "Propiedades del codec de Audio" +msgid "a sound card" +msgstr "una tarjeta de sonido" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "Propiedades del codec de Audio" +msgid "default camera" +msgstr "cámara predeterminada" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" +msgid "Audio codecs" msgstr "" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" +msgid "Video codecs" msgstr "" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" -msgstr "" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "" +msgid "SIP (UDP)" +msgstr "SIP (UDP)" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "" +msgid "SIP (TCP)" +msgstr "SIP (TCP)" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "" +msgid "SIP (TLS)" +msgstr "SIP (TLS)" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "Contactando " +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "Configuración" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" +msgid "This section defines your SIP address when not using a SIP account" +msgstr "Esta sección define su dirección SIP cuando no utiliza una cuenta SIP" #: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" +msgid "Your display name (eg: John Doe):" +msgstr "Su nombre a mostrar (x ej: Pepito Pérez):" #: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" +msgid "Your username:" msgstr "" #: ../gtk/parameters.ui.h:21 -msgid "Fixed" +msgid "Your resulting SIP address:" msgstr "" #: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" +msgid "Default identity" msgstr "" #: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "Direccion SIP" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "Servidor de Redireccionamiento" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "Red" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "Fuente de grabacion:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "Usar dispositivo de sonido:" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "Usar dispositivo de sonido:" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Usar dispositivo de sonido:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "Usar dispositivo de sonido:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Your display name (eg: John Doe):" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -#, fuzzy -msgid "Your username:" -msgstr "Manual de Usuario" - -#: ../gtk/parameters.ui.h:45 -#, fuzzy -msgid "Your resulting SIP address:" -msgstr "Tu direccion SIP:" - -#: ../gtk/parameters.ui.h:46 -#, fuzzy -msgid "Default identity" -msgstr "Identidad" - -#: ../gtk/parameters.ui.h:47 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Añadir" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Editar" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" -msgstr "Borrar" +msgstr "Eliminar" + +#: ../gtk/parameters.ui.h:27 +msgid "Proxy accounts" +msgstr "" + +#: ../gtk/parameters.ui.h:28 +msgid "Erase all passwords" +msgstr "Borrar todas las contraseñas" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Manage SIP Accounts" +msgstr "Gestionar cuentas SIP" + +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "" + +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Dispositivo especial ALSA (opcional):" + +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "" + +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Activar cancelación de eco" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 +msgid "0 stands for \"unlimited\"" +msgstr "0 significa \"ilimitado\"" + +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "" + +#: ../gtk/parameters.ui.h:49 +msgid "Upload speed limit in Kbit/sec:" +msgstr "Velocidad límite de subida en Kbit/seg" + +#: ../gtk/parameters.ui.h:50 +msgid "Download speed limit in Kbit/sec:" +msgstr "Velocidad límite de descarga en Kbit/seg:" #: ../gtk/parameters.ui.h:51 -#, fuzzy -msgid "Proxy accounts" -msgstr "Contactando " +msgid "Enable adaptive rate control" +msgstr "Activar control de frecuencia adaptativo" #: ../gtk/parameters.ui.h:52 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:53 -#, fuzzy -msgid "Privacy" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:54 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Activado" - -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Desactivado" - -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:58 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -msgid "Upload speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:60 -msgid "Download speed limit in Kbit/sec:" -msgstr "" - -#: ../gtk/parameters.ui.h:61 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:62 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" +"Control de frecuencia adaptativo es una técnica que estima dinámicamente " +"el ancho de banda disponible durante la llamada." + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "Control de ancho de banda" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Configuración multimedia" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Fijar Unidad de Transmisión Máxima:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Enviar DTMFs como información SIP" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" #: ../gtk/parameters.ui.h:63 -msgid "Bandwidth control" -msgstr "" +msgid "Audio RTP/UDP:" +msgstr "Audio RTP/UDP:" #: ../gtk/parameters.ui.h:64 -#, fuzzy -msgid "Codecs" -msgstr "Codecs" - -#: ../gtk/parameters.ui.h:65 -#, fuzzy -msgid "Language" -msgstr "Contactando " - -#: ../gtk/parameters.ui.h:66 -msgid "Show advanced settings" +msgid "Fixed" msgstr "" +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Vídeo RTP/UDP" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Tipo de cifrado de medios" + #: ../gtk/parameters.ui.h:67 -#, fuzzy -msgid "Level" -msgstr "Contactando " +msgid "Media encryption is mandatory" +msgstr "" #: ../gtk/parameters.ui.h:68 -#, fuzzy -msgid "User interface" -msgstr "Manual de Usuario" +msgid "Tunnel" +msgstr "" #: ../gtk/parameters.ui.h:69 -#, fuzzy +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Protocolo de red y puertos" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Conexión directa a Internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Tras un NAT/Firewall (utilizar STUN para resolver)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Activar" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Desactivar" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "Mostrar opciones avanzadas" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "Ninguno." +msgstr "" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "Informacion de codec" +msgstr "" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" -msgstr "" +msgstr "Añadir a mi lista" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "Contactando " - -#: ../gtk/waiting.ui.h:1 -#, fuzzy -msgid "Linphone" -msgstr "linphone" +msgstr "" #: ../gtk/waiting.ui.h:2 msgid "Please wait" -msgstr "" +msgstr "Espere por favor" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Red" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1392,21 +1534,19 @@ msgid "Call statistics" msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Propiedades del codec de Audio" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Propiedades del codec de Audio" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1414,9 +1554,28 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Informacion de codec" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" @@ -1434,23 +1593,475 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Transferir" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Calidad de la llamada" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Conexión a Internet" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Iniciar sesión automáticamente" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 +msgid "Ready" +msgstr "" + +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "" + +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 +msgid "Contacting" +msgstr "" + +#: ../coreapi/linphonecore.c:2805 +msgid "Could not call" +msgstr "" + +#: ../coreapi/linphonecore.c:2956 +msgid "Sorry, we have reached the maximum number of simultaneous calls" +msgstr "Disculpe, se ha alcanzado el máximo número de llamadas simultáneas" + +#: ../coreapi/linphonecore.c:3114 +msgid "is contacting you" +msgstr "" + +#: ../coreapi/linphonecore.c:3115 +msgid " and asked autoanswer." +msgstr "y ha solicitado auto respuesta." + +#: ../coreapi/linphonecore.c:3241 +msgid "Modifying call parameters..." +msgstr "Modificando parámetros de llamada…" + +#: ../coreapi/linphonecore.c:3625 +msgid "Connected." +msgstr "Conectado." + +#: ../coreapi/linphonecore.c:3650 +msgid "Call aborted" +msgstr "" + +#: ../coreapi/linphonecore.c:3847 +msgid "Could not pause the call" +msgstr "No se pudo pausar la llamada" + +#: ../coreapi/linphonecore.c:3850 +msgid "Pausing the current call..." +msgstr "Pausando la llamada actual..." + +#: ../coreapi/misc.c:436 +msgid "Stun lookup in progress..." +msgstr "Búsqueda STUN en proceso…" + +#: ../coreapi/misc.c:617 +msgid "ICE local candidates gathering in progress..." +msgstr "" + +#: ../coreapi/friend.c:33 +msgid "Online" +msgstr "" + +#: ../coreapi/friend.c:36 +msgid "Busy" +msgstr "Ocupado" + +#: ../coreapi/friend.c:39 +msgid "Be right back" +msgstr "Vuelvo enseguida" + +#: ../coreapi/friend.c:42 +msgid "Away" +msgstr "Ausente" + +#: ../coreapi/friend.c:45 +msgid "On the phone" +msgstr "" + +#: ../coreapi/friend.c:48 +msgid "Out to lunch" +msgstr "A comer" + +#: ../coreapi/friend.c:51 +msgid "Do not disturb" +msgstr "No molestar" + +#: ../coreapi/friend.c:54 +msgid "Moved" +msgstr "" + +#: ../coreapi/friend.c:57 +msgid "Using another messaging service" +msgstr "Utilizando otro servicio de mensajería" + +#: ../coreapi/friend.c:60 +msgid "Offline" +msgstr "" + +#: ../coreapi/friend.c:63 +msgid "Pending" +msgstr "Pendiente" + +#: ../coreapi/friend.c:66 +msgid "Vacation" +msgstr "" + +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 +msgid "" +"The sip proxy address you entered is invalid, it must start with \"sip:\" " +"followed by a hostname." +msgstr "" +"La dirección del Proxy SIP que ha introducido no es válida, debe empezar con " +"\"sip:\" seguido del hostname." + +#: ../coreapi/proxy.c:301 +msgid "" +"The sip identity you entered is invalid.\n" +"It should look like sip:username@proxydomain, such as sip:alice@example.net" +msgstr "" +"La identidad SIP que ha introducido no es válida.\n" +"Debe ser del tipo sip:username@proxydomain, como por ejemplo sip:" +"alice@example.net" + +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Buscando el número de teléfono del destinatario…" + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "No se ha podido resolver este número." + +#: ../coreapi/proxy.c:1407 +#, c-format +msgid "Could not login as %s" +msgstr "" + +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "" + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "" + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "Medios iniciales." + +#: ../coreapi/callbacks.c:548 +#, c-format +msgid "Call with %s is paused." +msgstr "La llamada con %s está puesta en pausa." + +#: ../coreapi/callbacks.c:561 +#, c-format +msgid "Call answered by %s - on hold." +msgstr "Llamada respondida por %s - en espera." + +#: ../coreapi/callbacks.c:571 +msgid "Call resumed." +msgstr "" + +#: ../coreapi/callbacks.c:575 +#, c-format +msgid "Call answered by %s." +msgstr "" + +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "" + +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "" + +#. we are being paused +#: ../coreapi/callbacks.c:642 +msgid "We are paused by other party." +msgstr "" + +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 +msgid "Call is updated by remote." +msgstr "" + +#: ../coreapi/callbacks.c:797 +msgid "Call terminated." +msgstr "" + +#: ../coreapi/callbacks.c:825 +msgid "User is busy." +msgstr "El usuario está ocupado." + +#: ../coreapi/callbacks.c:826 +msgid "User is temporarily unavailable." +msgstr "El usuario no está disponible temporalmente." + +#. char *retrymsg=_("%s. Retry after %i minute(s)."); +#: ../coreapi/callbacks.c:828 +msgid "User does not want to be disturbed." +msgstr "El usuario no quiere que le molesten." + +#: ../coreapi/callbacks.c:829 +msgid "Call declined." +msgstr "Llamada rechazada." + +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" + +#: ../coreapi/callbacks.c:875 +msgid "Redirected" +msgstr "Redigirida" + +#: ../coreapi/callbacks.c:930 +msgid "Call failed." +msgstr "" + +#: ../coreapi/callbacks.c:1008 +#, c-format +msgid "Registration on %s successful." +msgstr "" + +#: ../coreapi/callbacks.c:1009 +#, c-format +msgid "Unregistration on %s done." +msgstr "" + +#: ../coreapi/callbacks.c:1027 +msgid "no response timeout" +msgstr "timeout sin respuesta" + +#: ../coreapi/callbacks.c:1030 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "" + +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format +msgid "You have missed %i call." +msgid_plural "You have missed %i calls." +msgstr[0] "Tiene %i llamada perdida." +msgstr[1] "Tiene %i llamadas perdidas." + +#: ../coreapi/call_log.c:209 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:235 +#: ../coreapi/call_log.c:212 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/call_log.c:215 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:243 +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 #, c-format msgid "" "%s at %s\n" @@ -1460,805 +2071,11 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/call_log.c:221 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1226 -#, fuzzy -msgid "Ready" -msgstr "Preparado." - -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "" - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/linphonecore.c:2121 -#, fuzzy -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Direccion SIP mal escrita. Una direccion SIP es " - -#: ../coreapi/linphonecore.c:2312 -#, fuzzy -msgid "Contacting" -msgstr "Contactando " - -#: ../coreapi/linphonecore.c:2319 -#, fuzzy -msgid "Could not call" -msgstr "No se pudo encontrar el archivo pixmap: %s" - -#: ../coreapi/linphonecore.c:2429 -msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" - -#: ../coreapi/linphonecore.c:2573 -#, fuzzy -msgid "is contacting you" -msgstr "le esta llamando." - -#: ../coreapi/linphonecore.c:2574 -msgid " and asked autoanswer." -msgstr "" - -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 -msgid "Modifying call parameters..." -msgstr "" - -#: ../coreapi/linphonecore.c:2908 -msgid "Connected." -msgstr "Conectado." - -#: ../coreapi/linphonecore.c:2931 -#, fuzzy -msgid "Call aborted" -msgstr "Llamada cancelada." - -#: ../coreapi/linphonecore.c:3102 -msgid "Could not pause the call" -msgstr "" - -#: ../coreapi/linphonecore.c:3107 -msgid "Pausing the current call..." -msgstr "" - -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Tu ordenador parece estar usando los controladores de ALSA.\n" -"Esa es la mejor eleccion. Sin embargo el modulo de emulacion pcm de OSS\n" -"no se encuentra y linphone lo necesita. Por favor ejecute\n" -"'modprobe snd-pcm-oss' como root para cargarlo." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Tu ordenador parece estar usando los controladores de ALSA.\n" -"Esa es la mejor eleccion. Sin embargo el modulo de emulacion mixer de OSS\n" -"no se encuentra y linphone lo necesita. Por favor ejecute\n" -" 'modprobe snd-mixer-oss' como root para cargarlo." - -#: ../coreapi/misc.c:496 -msgid "Stun lookup in progress..." -msgstr "" - -#: ../coreapi/misc.c:630 -msgid "ICE local candidates gathering in progress..." -msgstr "" - -#: ../coreapi/friend.c:33 -#, fuzzy -msgid "Online" -msgstr "linea" - -#: ../coreapi/friend.c:36 -msgid "Busy" -msgstr "" - -#: ../coreapi/friend.c:39 -msgid "Be right back" -msgstr "" - -#: ../coreapi/friend.c:42 -msgid "Away" -msgstr "Ausente" - -#: ../coreapi/friend.c:45 -#, fuzzy -msgid "On the phone" -msgstr "linphone" - -#: ../coreapi/friend.c:48 -msgid "Out to lunch" -msgstr "" - -#: ../coreapi/friend.c:51 -msgid "Do not disturb" -msgstr "No molestar" - -#: ../coreapi/friend.c:54 -#, fuzzy -msgid "Moved" -msgstr "Codecs" - -#: ../coreapi/friend.c:57 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:60 -#, fuzzy -msgid "Offline" -msgstr "linea" - -#: ../coreapi/friend.c:63 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "" - -#: ../coreapi/proxy.c:204 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:210 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format -msgid "Could not login as %s" -msgstr "No se pudo encontrar el archivo pixmap: %s" - -#: ../coreapi/callbacks.c:276 -#, fuzzy -msgid "Remote ringing." -msgstr "Registrando..." - -#: ../coreapi/callbacks.c:296 -#, fuzzy -msgid "Remote ringing..." -msgstr "Registrando..." - -#: ../coreapi/callbacks.c:307 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:352 +#: ../gtk/videowindow.c:66 #, c-format -msgid "Call with %s is paused." +msgid "Cannot play %s." msgstr "" - -#: ../coreapi/callbacks.c:365 -#, c-format -msgid "Call answered by %s - on hold." -msgstr "" - -#: ../coreapi/callbacks.c:376 -#, fuzzy -msgid "Call resumed." -msgstr "Llamada cancelada." - -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format -msgid "Call answered by %s." -msgstr "" -"Llamar o\n" -"Responder" - -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "" - -#: ../coreapi/callbacks.c:437 -msgid "We have been resumed." -msgstr "" - -#: ../coreapi/callbacks.c:446 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:452 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:521 -#, fuzzy -msgid "Call terminated." -msgstr "Llamada cancelada." - -#: ../coreapi/callbacks.c:528 -msgid "User is busy." -msgstr "El usuario esta ocupado." - -#: ../coreapi/callbacks.c:529 -msgid "User is temporarily unavailable." -msgstr "El usuario le dice que volvera enseguida." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 -msgid "User does not want to be disturbed." -msgstr "El usuario no quiere que lo molesten." - -#: ../coreapi/callbacks.c:532 -msgid "Call declined." -msgstr "Llamada cancelada." - -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "" - -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 -#, fuzzy -msgid "Call failed." -msgstr "Llamada cancelada." - -#: ../coreapi/callbacks.c:701 -#, fuzzy, c-format -msgid "Registration on %s successful." -msgstr "Se ha registrado con exito." - -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format -msgid "Unregistration on %s done." -msgstr "Se ha registrado con exito." - -#: ../coreapi/callbacks.c:722 -msgid "no response timeout" -msgstr "" - -#: ../coreapi/callbacks.c:725 -#, fuzzy, c-format -msgid "Registration on %s failed: %s" -msgstr "Se ha registrado con exito." - -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Informacion de codec" - -#: ../coreapi/linphonecall.c:2124 -#, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informacion" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Contactando " - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Activado" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Informacion de codec" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "Contactando " - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Propiedades del codec de Audio" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "Propiedades del codec de Audio" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "Informacion" - -#, fuzzy -#~ msgid "_Linphone" -#~ msgstr "linphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Conectado." - -#, fuzzy -#~ msgid "gtk-ok" -#~ msgstr "Borrar" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Conectado." - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "Contactando " - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "Codecs" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "Propiedades del codec de Audio" - -#, fuzzy -#~ msgid "Request Cancelled." -#~ msgstr "Llamada cancelada." - -#~ msgid "User cannot be found at given address." -#~ msgstr "No se encontro ningun usuario en la direccion indicada." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "El usuario remoto no soporta ninguno de los codecs propuestos." - -#~ msgid "Timeout." -#~ msgstr "Tiempo agotado." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Se encontro host remoto pero rechazo la conexion." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Usuario no disponible en este momento pero le invita\n" -#~ "a contactarle usando el siguiente recurso alternativo:" - -#, fuzzy -#~ msgid "Gone" -#~ msgstr "Ninguno." - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Direccion" - -#, fuzzy -#~ msgid "Display filters" -#~ msgstr "Nombre a mostrar:" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "Propiedades de RTP" - -#, fuzzy -#~ msgid "Proxy in use" -#~ msgstr "Servidor Proxy" - -#~ msgid "Sound" -#~ msgstr "Sonido" - -#, fuzzy -#~ msgid "Proxy accounts" -#~ msgstr "Servidor Proxy" - -#~ msgid "Address book" -#~ msgstr "Agenda" - -#, fuzzy -#~ msgid "Shows the address book" -#~ msgstr "Muestra la Agenda" - -#~ msgid "Show more..." -#~ msgstr "Mostrar mas..." - -#~ msgid "Playback level:" -#~ msgstr "Nivel de reproduccion:" - -#~ msgid "Recording level:" -#~ msgstr "Nivel de Grabacion:" - -#, fuzzy -#~ msgid "Ring level:" -#~ msgstr "Nivel de Grabacion:" - -#~ msgid "Reachable" -#~ msgstr "Disponible" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Ocupado, estare de vuelta en " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "" -#~ "Se le comunicara a la otra persona que estaras de vuelta en X minutos" - -#~ msgid "mn" -#~ msgstr "min" - -#~ msgid "Moved temporarily" -#~ msgstr "Vengo enseguida" - -#~ msgid "Alternative service" -#~ msgstr "Servicio alternativo" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Estado" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Pulsa los digitos para mandar DTMFs." - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone es un telefono para Internet.\n" -#~ "Es compatible con los protocolos SIP y RTP." - -#, fuzzy -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "El usuario le dice que volvera enseguida." - -#, fuzzy -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Esta opcion es solo para usuarios en una red privada, detras de un " -#~ "cortafuegos. Siese no es tu caso, deja esto vacio." - -#, fuzzy -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "Opciones para NAT transversal (experimental)" - -#, fuzzy -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Numero de milisegundos en el buffer(compensacion jitter):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "Puerto RTP usado para audio:" - -#~ msgid "micro" -#~ msgstr "microfono" - -#~ msgid "Recording source:" -#~ msgstr "Fuente de grabacion:" - -#~ msgid "Sound properties" -#~ msgstr "Propiedades de sonido" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Ejecutar SIP user agent en el puerto:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Se recomienda encarecidamente usar el puerto 5060." - -#~ msgid "SIP port" -#~ msgstr "Puerto SIP" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Identidad" - -#, fuzzy -#~ msgid "Add proxy/registrar" -#~ msgstr "Usar el registro SIP" - -#~ msgid "Remote services" -#~ msgstr "Servicios Remotos:" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Lista de codecs de audio, en orden de preferencia:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Nota: Los codecs en ROJO no son adecuados para tu conexion a internet." - -#, fuzzy -#~ msgid "No information availlable" -#~ msgstr "Informacion no disponible" - -#, fuzzy -#~ msgid "Codec information" -#~ msgstr "Informacion de codec" - -#~ msgid "Address Book" -#~ msgstr "Agenda" - -#~ msgid "Select" -#~ msgstr "Seleccionar" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Usuario no disponible en este momento pero le invita a contactarle usando " -#~ "el siguiente recurso alternativo:" - -#~ msgid "None." -#~ msgstr "Ninguno." - -#, fuzzy -#~ msgid "Name:" -#~ msgstr "Nombre" - -#, fuzzy -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "" -#~ "Direccion SIP mal escrita. Una direccion SIP es " - -#~ msgid "Communication ended." -#~ msgstr "Comunicacion finalizada." - -#, fuzzy -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "Direccion IP del cortafuegos (en notacion con puntos):" - -#~ msgid "Index" -#~ msgstr "Indice" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Direccion del Servidor:" - -#~ msgid "28k modem" -#~ msgstr "modem 28k" - -#~ msgid "56k modem" -#~ msgstr "modem 56k" - -#~ msgid "64k modem (numeris)" -#~ msgstr "modem 64k (numeris)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL o Cable" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet o equivalente" - -#~ msgid "Connection type:" -#~ msgstr "Tipo de conexion:" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone no pudo abrir el dispositivo de audio. Asegurese que su tarjeta " -#~ "de sonido esta completamente configurada y operativa." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "Escribe aqui la direccion SIP de la persona que quieres llamar." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Descolgar o\n" -#~ "Rechazar" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. Reintentar tras %i minutos." - -#, fuzzy -#~ msgid "Timeout..." -#~ msgstr "Tiempo agotado." - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "Marcar opcion si desea registrarse en un servidor remoto." - -#~ msgid "Address of record:" -#~ msgstr "Nombre de registro:" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "" -#~ "La contraseña usada para registrarse. En algunos servidores no es " -#~ "necesaria" - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "Usar el servidor de registro como outbound proxy." - -#~ msgid "sip address:" -#~ msgstr "Direccion SIP:" - -#~ msgid "Modify" -#~ msgstr "Modificar" - -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "Estas usando actualmente el controlador i810_audio.\n" -#~ "Ese controlador tiene errores y por tanto no funciona con Linphone.\n" -#~ "Le recomendamos que lo sustituya por su controlador equivalente de ALSA,\n" -#~ "ya sea mediante paquetes de su distribucion, o descargando\n" -#~ "controladores ALSA de http://www.alsa-project.org." - -#~ msgid "Unregistration successfull." -#~ msgstr "Cancelacion del registro completada." - -#~ msgid "C: 2001" -#~ msgstr "Abril 2001" - -#~ msgid "Select network interface to use:" -#~ msgstr "Selecciona la interfaz de red para usar:" - -#~ msgid "Network interface properties" -#~ msgstr "Propiedades de Interfaz de Red:" - -#~ msgid "RTP" -#~ msgstr "RTP" - -#~ msgid "Threads not supported by glib. Upgrade your glib.\n" -#~ msgstr "Threads no soportados por glib. Actualize su glib.\n" - -#~ msgid "Run linphone as a gnome-applet." -#~ msgstr "Lanzar linphone como un gnome-applet." - -#~ msgid "Run linphone as a daemon (for use without gnome)." -#~ msgstr "Ejecutar linphone como demonio (para uso sin gnome)." - -#~ msgid "" -#~ "Cannot find network previously used interface %s.\n" -#~ "If your computer is temporary connected to the internet, please connect " -#~ "and then run linphone.\n" -#~ "If you want to change your default network interface, go to the " -#~ "parameters 'box." -#~ msgstr "" -#~ "No se puede encontrar la interfaz de red usada previamente %s.\n" -#~ "Si tu ordenador esta conectado temporalmente a Internet, por favor " -#~ "conecta y entonces ejecuta linphone.\n" -#~ "Si quieres cambiar tu interfaz de red predeterminada, ve a la opcion " -#~ "Parametros." - -#, fuzzy -#~ msgid "" -#~ "Linphone cannot open the audio device.\n" -#~ "It may be caused by other programs using it.\n" -#~ "Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone no puede abrir el dispositivo de audio.\n" -#~ " Puede deberse a que otros programas lo esten usando.\n" -#~ "¿ Quiere que Linphone cierre esos programas (esd o artsd) ?" - -#~ msgid "Use it as a:" -#~ msgstr "Usarlo como un:" - -#~ msgid "Outbound proxy" -#~ msgstr "Outbound proxy" - -#~ msgid "" -#~ "Togle this button if the registrar must be used to proxy calls through a " -#~ "firewall." -#~ msgstr "" -#~ "Marcar esta opcion si el servidor de registro debe ser usado para " -#~ "llamadas a proxy a traves de un cortafuegos." - -#~ msgid "OSS" -#~ msgstr "OSS" - -#~ msgid "ALSA" -#~ msgstr "ALSA" - -#~ msgid "Automatically kill applications using soundcard when needed" -#~ msgstr "" -#~ "Cerrar aplicaciones que usen la tarjeta de sonido cuando se necesite." - -#~ msgid "" -#~ "Your computer is connected to several networks. Check in the global " -#~ "parameters if Linphone uses the one that you want." -#~ msgstr "" -#~ "Tu ordenador esta conectado a varias redes. Revisa en los Parametros " -#~ "globales si Linphone usa la que necesitas." - -#~ msgid "" -#~ "Linphone failed to open the sound device. See the README file included in " -#~ "the distribution for details." -#~ msgstr "" -#~ "Linphone fallo al abrir el dispositivo de sonido. Vea el archivo README " -#~ "incluido en la distribucion para mas detalles." - -#~ msgid "Interface not found." -#~ msgstr "Interfaz no encontrada." - -#~ msgid "Warning" -#~ msgstr "Atencion" - -#~ msgid "" -#~ "Linphone cannot open the sound device. It may be caused by other programs " -#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone no puede abrir el dispositivo de sonido. Puede deberse a que " -#~ "otros programaslo esten usando. ¿ Quiere que Linphone cierre esos " -#~ "programas (esd o artsd) ?" - -#~ msgid "Linphone shutdowns..." -#~ msgstr "Linphone esta terminando..." - -#~ msgid "" -#~ "Please, wait a few seconds untils linphone unregisters your sip addess " -#~ "from registrar server..." -#~ msgstr "" -#~ "Por favor, espere unos segundos hasta que Linphone cancele el registro de " -#~ "su direccion SIP en el servidor de registros..." - -#~ msgid "Bad formuled sip address." -#~ msgstr "Direccion SIP mal escrita." - -#~ msgid "Couldn't create pixmap from file: %s" -#~ msgstr "No se pudo crear pixmap desde el archivo: %s" - -#~ msgid "" -#~ "Linphone did not detect any valid network interface. If you use a " -#~ "temporary internet connection, please connect and then run linphone again." -#~ msgstr "" -#~ "Linphone no detecto ninguna interfaz de red valida. Si usas una conexion " -#~ "temporal a Internet, por favor conecta y vuelve a ejecutar Linphone." - -#~ msgid "List of network interfaces on your system." -#~ msgstr "Lista de interfaces de red en tu sistema." - -#~ msgid "" -#~ "RTP est le mode de transport de la voix. Modifier ces paramètres pour " -#~ "tenter d'améliorer la qualité de la communication si celle-ci est " -#~ "dégradée." -#~ msgstr "" -#~ "RTP es el modelo de transporte de la voz. Modifica estos parametros para " -#~ "intentar mejorar la calidad de la comunicacion, si es que.es mala." - -#~ msgid "Use rtp port:" -#~ msgstr "Puerto RTP:" - -#~ msgid "" -#~ "Les codecs ou vocodeurs sont les algorithmes utilisés pour compresser la " -#~ "voix." -#~ msgstr "" -#~ "Los codecs o codificadores/decodificadores son los algoritmos usados para " -#~ "comprimir la voz." - -#~ msgid "" -#~ "Vous pouvez ajuster avec cet onglet des paramètre liés à votre carte son." -#~ msgstr "Puede modificar estos parametros a su gusto." diff --git a/po/fr.po b/po/fr.po index 8c955f75c..f15677f13 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,192 +1,228 @@ # SOME DESCRIPTIVE TITLE. -# Copyright (C) 2001 Free Software Foundation, Inc. -# Simon Morlat , 2001. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Belledonne Communications , 2015 +# Gautier Pelloux-Prayer , 2014 +# Gautier Pelloux-Prayer , 2014 +# Gautier Pelloux-Prayer , 2014-2015 +# Simon Morlat , 2001 msgid "" msgstr "" -"Project-Id-Version: Linphone 0.9.1\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-05 12:41+0100\n" -"PO-Revision-Date: 2002-12-06 17:33+0100\n" -"Last-Translator: Simon Morlat \n" -"Language-Team: french \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-08-23 09:28+0000\n" +"Last-Translator: Gautier Pelloux-Prayer \n" +"Language-Team: French (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/fr/)\n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: ../gtk/calllogs.c:82 -msgid "Aborted" -msgstr "Abandonné" - -#: ../gtk/calllogs.c:85 -msgid "Missed" -msgstr "Manqué" - -#: ../gtk/calllogs.c:88 -msgid "Declined" -msgstr "Refusé" - -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 #, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" +msgid "Call %s" +msgstr "Appeler %s" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 #, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgid "Send text to %s" +msgstr "Chatter avec %s" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:233 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" -msgstr "" +msgid "Recent calls (%i)" +msgstr "Appels récents (%i)" -#: ../gtk/calllogs.c:102 +#: ../gtk/calllogs.c:315 msgid "n/a" msgstr "inconnu" -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "Abandonné" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "Manqué" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "Refusé" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "%i minute" +msgstr[1] "%i minutes" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "%i seconde" +msgstr[1] "%i secondes" + +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" +"%s\tQualité: %s\n" +"%s\t%s\t" -#: ../gtk/conference.c:33 -#: ../gtk/main.ui.h:13 +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "Conférence" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "Moi" -#: ../gtk/support.c:49 -#: ../gtk/support.c:73 -#: ../gtk/support.c:102 +#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Icone non trouvée: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "affiche des informations de debogage" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "Afficher la version et quitter." + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "" +msgstr "chemin vers le fichier de logs." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Démarrer linphone avec la vidéo désactivée." -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "Démarre iconifié, sans interface principale." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "addresse à appeler maintenant" +msgstr "adresse à appeler maintenant" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "si positionné, répond automatiquement aux appels entrants" +#: ../gtk/main.c:144 +msgid "" +"Specifiy a working directory (should be the base of the installation, eg: c:" +"\\Program Files\\Linphone)" +msgstr "" +"Spécifie un répertoire de travail (qui devrait être le répertoire " +"d'installation, par exemple c:\\Program Files\\Linphone)" -#: ../gtk/main.c:131 -msgid "Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)" -msgstr "Spécifie un répertoire de travail (qui devrait être le répertoire d'installation, par exemple c:\\Program Files\\Linphone)" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Ficher de configuration" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Appel avec %s" +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Démarre l'assistant audio" -#: ../gtk/main.c:871 +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Exécuter le test local et retourner 0 en cas de succès" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" "%s souhaite vous ajouter à sa liste de contact.\n" -"Souhaitez vous l'autoriser à voir votre information de présence et l'ajouter à votre liste également ?\n" -"Si vous répondez non, cette personne sera mise temporairement sur liste noire." +"Souhaitez vous l'ajouter à votre liste également et l'autoriser à voir votre " +"information de présence ?\n" +"Si vous répondez non, cette personne sera mise temporairement sur liste " +"noire." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Entrez le mot de passe pour %s\n" " sur le domaine %s:" -#: ../gtk/main.c:1051 +#: ../gtk/main.c:1256 msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1054 -#: ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1057 -#: ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1059 -#: ../gtk/incall_view.c:451 -#: ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1061 -#: ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Refuser" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 msgid "Call paused" msgstr "Appel en pause" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "" +msgid "by %s" +msgstr "b>par %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s propose de démarrer la vidéo. Acceptez-vous ?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "Lien site web" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - un téléphone video pour l'internet" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "Appels vidéo via internet" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1714 -#: ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -194,179 +230,194 @@ msgstr "" "Aucune carte son n'a été détectée sur cet ordinateur.\n" "Vous ne pourrez pas effectuer d'appels audio." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "Un visiophone libre" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "Bonjour\n" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "Ajouter au carnet d'adresse" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:526 -#: ../gtk/propertybox.c:362 -#: ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" -#: ../gtk/friendlist.c:538 +#: ../gtk/friendlist.c:722 msgid "Call" msgstr "Appeler" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "" +msgstr "Chat" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Rechercher dans l'annuaire de %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "Contact sip invalide !" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "Appeler %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Chatter avec %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Editer le contact '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Supprimer le contact '%s'" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Supprimer l'historique de chat de '%s'" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Ajouter un contact depuis l'annuaire %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Fréquence (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Etat" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Débit min. (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "Débit IP (kbit/s)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Paramètres" -#: ../gtk/propertybox.c:430 -#: ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Activé" -#: ../gtk/propertybox.c:432 -#: ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Désactivé" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Compte" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Anglais" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Suédois" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italien" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Espagnol" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "Portugais brésilien" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polonais" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Allemand" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Russe" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Néérlandais" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Hongrois" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Tchèque" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "Chinois traditionnel" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "Norvégien" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "Hébreu" -#: ../gtk/propertybox.c:842 -msgid "You need to restart linphone for the new language selection to take effect." -msgstr "La nouvelle selection de langue prendra effet au prochain démarrage de linphone." +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Serbe" -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "Arabe" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "Turc" + +#: ../gtk/propertybox.c:1245 +msgid "" +"You need to restart linphone for the new language selection to take effect." +msgstr "" +"La nouvelle selection de langue prendra effet au prochain démarrage de " +"linphone." + +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "" +msgstr "Aucun" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" -msgstr "" +msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -374,10 +425,13 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" +"Une version plus récente est disponible sur %s.\n" +"Voulez vous ouvrir le navigateur afin de pouvoir télécharger la dernière " +"version ?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "" +msgstr "Vous utilisez la dernière version." #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" @@ -385,7 +439,7 @@ msgstr "Prénom, Nom" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "" +msgstr "Erreur de communication avec le serveur." #: ../gtk/buddylookup.c:164 msgid "Connecting..." @@ -406,521 +460,568 @@ msgid_plural "Found %i contacts" msgstr[0] "%i contact trouvé." msgstr[1] "%i contacts trouvés." -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" +"Bienvenue !\n" +"Cet assistant va vous aider à utiliser un compte SIP pour vos appels." -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Créer un compte sur linphone.org" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "" +msgstr "J'ai déjà un compte linphone.org et je souhaite l'utiliser" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "" +msgstr "J'ai déjà un compte Sip et je souhaite l'utiliser" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" -msgstr "" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Je veux spécifier une URI de configuration" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "Nom d'utilisateur:" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "Entrez vos paramètres de compte" -#: ../gtk/setupwizard.c:93 -#: ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "Mot de passe:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 +#: ../gtk/setupwizard.c:221 msgid "Username*" msgstr "Nom d'utilisateur*" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:222 msgid "Password*" msgstr "Mot de passe*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" -msgstr "" +msgstr "Domaine*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" -msgstr "" +msgstr "Proxy" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Entrez votre identifiant linphone.org" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Nom d'utilisateur:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Mot de passe:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Champs requis" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" msgstr "Nom d'utilisateur: (*)" -#: ../gtk/setupwizard.c:300 +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" msgstr "Mot de passe: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "Email : (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Confirmez votre mot de passe: (*)" -#: ../gtk/setupwizard.c:368 +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Me tenir informé des mises à jour de Linphone " + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "Votre compte est en cours de création. Veuillez patienter." + +#: ../gtk/setupwizard.c:494 +msgid "" +"Please validate your account by clicking on the link we just sent you by " +"email.\n" +"Then come back here and press Next button." +msgstr "" +"Merci de valider votre compte en cliquant sur le lien que nous avons envoyé " +"par email.\n" +"Puis appuyez sur suivant." + +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "Vérification que le compte a été validé. Veuillez patienter." + +#: ../gtk/setupwizard.c:512 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" +"Erreur, le compte n'est pas validé, l'identifiant est déjà utilisé ou le " +"serveur n'est pas accessible.\n" +"Merci d'essayer à nouveau." -#: ../gtk/setupwizard.c:379 +#: ../gtk/setupwizard.c:521 msgid "Thank you. Your account is now configured and ready for use." -msgstr "" +msgstr "Merci. Votre compte est maintenant configuré et prêt à être utilisé." -#: ../gtk/setupwizard.c:387 -msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" -"Then come back here and press Next button." -msgstr "" +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "Assistant de configuration de compte." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:559 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "Configuer un compte SIP" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "Bienvenue dans l'assistant de configuration de compte." #: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" +msgid "Account setup assistant" +msgstr "Assistant de configuration de compte." #: ../gtk/setupwizard.c:588 +msgid "Configure your account (step 1/1)" +msgstr "Configurez votre compte (étape 1/1)" + +#: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "Entrez votre identifiant sip (étape 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Entrez les informations concernant votre compte (étape 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "Création du compte en cours" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Validation (étape 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "Vérification de la validité du compte en cours" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "Erreur" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "" +msgstr "En cours d’arrêt." -#: ../gtk/incall_view.c:69 -#: ../gtk/incall_view.c:90 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "Appel #%i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Transférer vers l'appel #%i avec %s" -#: ../gtk/incall_view.c:209 -#: ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "Non trouvé" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Non utilisé" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "L'appel a échoué." +msgid "ICE not activated" +msgstr "ICE non activé" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "Erreur ICE" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "Négociation ICE en cours" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Redirection" +msgid "Going through one or more NATs" +msgstr "Via un ou plusieurs NATs" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "En direct" -#: ../gtk/incall_view.c:238 -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Via un serveur relais" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP non activé" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP en cours" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnP est indisponible" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP en cours d’exécution" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP a échoué." + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Directe ou via un serveur" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"débit descendant : %f\n" +"débit ascendant : %f (kbits/s)" -#: ../gtk/incall_view.c:341 -#: ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f fps" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f secondes" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" -msgstr "" +msgstr "Raccrocher" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:433 -#: ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "bon" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "moyen" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "faible" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "très faible" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:490 -#: ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "indisponible" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "Sécurisé par SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "Sécurisé par DTLS" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Sécurisé par ZRTP- [jeton: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:617 -#: ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "Marquer comme vérifié" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "En conférence" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "Appel en cours" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "Appel en attente" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Appel terminé." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "Transfert en cours" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "Transfert terminé" -#: ../gtk/incall_view.c:737 +#: ../gtk/incall_view.c:871 msgid "Transfer failed." msgstr "Transfert échoué" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:788 -#: ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "Pause" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Enregistrement dans\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(en attente)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Entrez vos identifiants pour %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "chargement depuis %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Le chargement de la configuration depuis %s a échoué." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Voix non détectée" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Trop bas" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "Bien" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Trop bruyant" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Avez-vous entendu trois bips ?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Préférences son non trouvé" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Impossible de démarrer le contrôleur système du son" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Bienvenue !\n" +"Cet assistant va vous aider à régler les paramètres audio de votre " +"ordinateur pour une utilisation optimale avec Linphone." + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Périphérique de capture" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "Volume enregistré" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Silencieux" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Préférences son système" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Périphérique d'écoute" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Joue trois bips" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Appuyer sur le bouton enregistrer et dites quelques mots" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Ecoutez votre voix enregistrée" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Enregistrer" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Jouer" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Démarrons Linphone maintenant" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Assistant audio" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Assistant audio" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Calibration du gain du microphone" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Calibration du volume du haut parleur" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Enregistrer et joue" + #: ../gtk/main.ui.h:1 -msgid "Callee name" -msgstr "Nom du correspondant" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Envoyer" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "Fin de conférence" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "Vidéo" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "Transfert" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "Appel en cours" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Durée" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "Qualité de l'appel" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Se voir" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "_Aide" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "Fenêtre de débogage" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "_Site web" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "Adresse SIP ou numéro" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "Démarrer un nouvel appel" - -#: ../gtk/main.ui.h:27 -#: ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Ajouter" - -#: ../gtk/main.ui.h:28 -#: ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Editer" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "" - -#: ../gtk/main.ui.h:33 -#: ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Rechercher" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Ajouter un contact depuis l'annuaire" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "Ajouter un contact." - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "Clavier" - -#: ../gtk/main.ui.h:49 -msgid "Recent calls" -msgstr "Appels récents" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Mon identité sip:" - -#: ../gtk/main.ui.h:51 -#: ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Nom d'utilisateur" - -#: ../gtk/main.ui.h:52 -#: ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Mot de passe" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Me connecter automatiquement" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Information de login" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Bienvenue !" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "Tous" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "En ligne" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" -msgstr "" +msgstr "Fibre optique" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "Par défaut" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" -msgstr "" +msgstr "Supprimer" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Options" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "URI de configuration" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Toujours activer la vidéo" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Se voir" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Aide" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Fenêtre de débogage" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Site web" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "_Mises à jour" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Assistant de compte" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "Adresse SIP ou numéro" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Démarrer un nouvel appel" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Contacts" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Rechercher" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Ajouter un contact depuis l'annuaire" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Ajouter un contact." + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Appels récents" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Mon identité SIP :" #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "A propos de linphone" +msgid "About Linphone" +msgstr "À propos de Linphone" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -939,7 +1040,20 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -963,19 +1077,19 @@ msgstr "Fenêtre de débogage de linphone" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "" +msgstr "Défiler jusqu'à la fin" #: ../gtk/password.ui.h:1 msgid "Linphone - Authentication required" -msgstr "Linphone - Autentification demandée" +msgstr "Linphone - Authentification demandée" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "Entrez votre mot de passe pour le domaine" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "ID utilisateur" #: ../gtk/call_logs.ui.h:1 msgid "Call history" @@ -995,7 +1109,7 @@ msgstr "Linphone - Configurer un compte SIP" #: ../gtk/sip_account.ui.h:2 msgid "Your SIP identity:" -msgstr "Votre identité SIP:" +msgstr "Votre identité SIP :" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" @@ -1003,300 +1117,424 @@ msgstr "De la forme sip:@" #: ../gtk/sip_account.ui.h:4 msgid "sip:" -msgstr "" +msgstr "sip:" #: ../gtk/sip_account.ui.h:5 msgid "SIP Proxy address:" -msgstr "Addresse du proxy SIP:" +msgstr "Adresse du proxy SIP:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" msgstr "De la forme sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (optionnel):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Période d'enregistrement (secondes):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Paramètres de contact (optionnel):" + #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "Intervalle standard RTCP AVPF (sec) :" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Route (optionnel):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Transport" + +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "S'enregistrer" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publier la présence" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Activer AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" -msgstr "Configuer un compte SIP" +msgstr "Configurer un compte SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "anonyme" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "Carte son par défaut" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "une carte son" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "camera par défaut" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" -msgstr "" +msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Codecs audio" -#: ../gtk/parameters.ui.h:6 -msgid "Video codecs" -msgstr "Codecs video" - -#: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" -msgstr "" - #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" -msgstr "" +msgid "Video codecs" +msgstr "Codecs vidéo" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" -msgstr "" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "SIP (UDP)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "SIP (TCP)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "SIP (TLS)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "Par défaut" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "Fréquence d'images élevée" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "Personnalisé" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "Réglages" -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Spécifier la Maximum Transmission Unit" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Envoyer les digits en tant que SIP INFO" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Utiliser l'IPv6 au lieu d'IPv4" - -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Transport" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "Type d'encryption media" - -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" +msgid "This section defines your SIP address when not using a SIP account" msgstr "" +"Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de " +"compte SIP" #: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "Protocoles réseaux et ports" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Connexion directe à l'Internet" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Derrière un pare-feu (spécifier la passerelle ci dessous)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Adresse IP publique:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Derrière un pare-feu (utiliser STUN)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Derrière un pare-feu (utiliser STUN)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "Serveur STUN:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "Paramètres liés au pare-feu" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Paramètres réseau" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Sonnerie:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Périphérique de capture:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Périphérique de sonnerie:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Périphérique d'écoute:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Activer l'annulation d'écho" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Son" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Périphérique d'entrée video" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Résolution video préférée:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Paramètres multimedia" - -#: ../gtk/parameters.ui.h:42 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Cette rubrique permet de définir son addresse SIP lorsqu'on ne possède pas de compte SIP" - -#: ../gtk/parameters.ui.h:43 msgid "Your display name (eg: John Doe):" msgstr "Votre nom d'affichage (ex: John Doe)" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Votre nom d'utilisateur:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "Votre addresse SIP:" +msgstr "Votre adresse SIP:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Identité par défaut" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" -msgstr "" +msgstr "Assistant" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Ajouter" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Editer" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Enlever" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Comptes SIP via des proxy" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Effacer tous les mots de passe" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Sécurité" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "Répondre automatiquement aux appels entrants" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "Temps d'attente avant réponse (ms)" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "Décrochage automatique" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Gérer mes comptes SIP" -#: ../gtk/parameters.ui.h:55 -#: ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Activer" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Sonnerie:" -#: ../gtk/parameters.ui.h:56 -#: ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Désactiver" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Appareil ALSA spécifique (optionnel) :" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Codecs" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Périphérique de capture:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Périphérique de sonnerie:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Périphérique d'écoute:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Activer l'annulation d'écho" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Son" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Périphérique d'entrée vidéo" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "Résolution vidéo préférée :" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Type de rendu video:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Afficher la vidéo" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "Profile vidéo:" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "Fréquence d'images préférée" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "Indiquez 0 pour ne pas mettre de limite" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Limite de débit montant en kbits/sec:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Limite de débit descendant en kbits/sec:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "Activer le control de débit adaptatif." -#: ../gtk/parameters.ui.h:62 -msgid "Adaptive rate control is a technique to dynamically guess the available bandwidth during a call." -msgstr "Le control de débit adaptatif est une technique pour adapter la qualité de l'audio et de la video en fonction de la bande passante disponible, durant l'appel." +#: ../gtk/parameters.ui.h:52 +msgid "" +"Adaptive rate control is a technique to dynamically guess the available " +"bandwidth during a call." +msgstr "" +"Le control de débit adaptatif est une technique pour adapter la qualité " +"de l'audio et de la video en fonction de la bande passante disponible, " +"durant l'appel." -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Gestion de la bande passante" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Paramètres multimedia" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Spécifier la Maximum Transmission Unit" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Envoyer les digits en tant que SIP INFO" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "Utiliser IPv6" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Transport" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "Port SIP / UDP" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Aléatoire" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "Port SIP / TCP" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "Audio RTP / UDP :" + #: ../gtk/parameters.ui.h:64 -msgid "Codecs" -msgstr "" +msgid "Fixed" +msgstr "Fixe" #: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Vidéo RTP / UDP :" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Type d'encryption media" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Le chiffrement media est obligatoire" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tunnel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "Champs DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Protocoles réseaux et ports" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Connexion directe à l'Internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Derrière un pare-feu (spécifier la passerelle ci dessous)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Derrière un pare-feu (utiliser STUN)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "Derrière un pare-feu (utiliser ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "Derrière un pare-feu (utiliser uPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Adresse IP publique:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Serveur STUN:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "Paramètres liés au pare-feu" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Paramètres réseau" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Activer" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Désactiver" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "Codecs audio" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "Codecs vidéo" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "Codecs" + +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Langue" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "Montrer les réglages avancés" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Niveau" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Interface utilisateur" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Adresse du serveur:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Méthode d'authentification:" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "Configuration LDAP" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Fermer" @@ -1312,210 +1550,339 @@ msgstr "Ajouter à ma liste" msgid "Search somebody" msgstr "Rechercher une personne" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "En attente" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Réglages" +msgid "DSCP settings" +msgstr "Réglages DSCP" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" -msgstr "" +msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 msgid "Audio RTP stream" -msgstr "" +msgstr "Flux RTP audio" #: ../gtk/dscp_settings.ui.h:4 msgid "Video RTP stream" -msgstr "" +msgstr "Flux RTP vidéo" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "Indiquez les valeurs DSCP (en hexacdécimal)" #: ../gtk/call_statistics.ui.h:1 msgid "Call statistics" -msgstr "" +msgstr "Statistiques de l'appel" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Codecs audio" +msgstr "Codec audio" #: ../gtk/call_statistics.ui.h:3 msgid "Video codec" -msgstr "Codecs vidéo" +msgstr "Codec vidéo" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Bande passante audio" #: ../gtk/call_statistics.ui.h:5 -#, fuzzy -msgid "Media connectivity" -msgstr "Type d'encryption media" +msgid "Audio Media connectivity" +msgstr "Connectivité audio" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Bande passante video" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "Connectivité video" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Temps d'aller retour" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Taille de video reçue" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Taille de video envoyée" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "Profil RTP" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Information sur le contact" +msgstr "Statistiques de l'appel et informations" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Configuer un compte SIP" +msgstr "Configuer le mode tunnel" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Hôte" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "Port" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Configuration du tunnel" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Nom d'utilisateur" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Mot de passe" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "Configuration d'un proxy http (optionel)" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "abandonné" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "Paramètres LDAP" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "terminé" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "Utiliser TLS" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "manqué" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Non disponible" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "Connexion" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "Assigner ND" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Nom d'authentification" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Realm" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "Object de base :" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "Filtre (nom avec %s) : " + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "Attribut nom :" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "Attribut pour l'addresse SIP:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "Attributs à chercher:" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "Rechercher" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "Temps de recherche maximum:" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "Nombre de résultats maximum:" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "Suivre les alias" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "Divers" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "ANONYME" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "SIMPLE" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "DIGEST-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "Spécifier une URI de configuration" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s le %s\n" -"De: %s\n" -"A destination de: %s\n" -"Etat: %s\n" -"Durée: %i mn %i sec\n" +"Cette boite de dialogue vous permet de spécifier une addresse http ou https " +"où la configuration doit être téléchargée au démarrage.\n" +"Veuillez entrer l'URI http(s) ci dessous. Après avoir validé, Linphone va " +"redémarrer automatiquement pour charger et prendre en compte la nouvelle " +"configuration." -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Appel sortant" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Configuration en cours" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" +"Veuillez patenter un instant pendant le chargement de la configuration " +"distante..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Envoyer" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Nom du correspondant" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Fin de conférence" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Enregistrement de l'appel dans un fichier audio." + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Vidéo" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Couper le micro" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Transfert" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "Appel en cours" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Durée" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Qualité de l'appel" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Connexion internet:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Me connecter automatiquement" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Information de login" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Bienvenue !" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Prêt." -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Recherche de la destination du numéro de téléphone..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Configuration en cours" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "La destination n'a pu être trouvée." - -#: ../coreapi/linphonecore.c:2121 -msgid "Could not parse given sip address. A sip url usually looks like sip:user@domain" -msgstr "Adresse SIP mal formulée. Une address sip ressemble à " - -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Appel de" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "Echec de l'appel" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Désolé, le nombre maximum d'appels simultanés est atteint." -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "vous appelle" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "et sollicite un décrochage automatique." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "Modifications des paramètres d'appels..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "En ligne." -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Votre ordinateur semble utiliser les pilotes sons ALSA.\n" -"C'est en g��al le meilleur choix, cependant un module\n" -"d'emulation oss est manquant et linphone en a besoin.\n" -"Veuillez s'il vous plait executer la commande\n" -"'modprobe snd-pcm-oss' en tant que root afin de le charger." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Votre ordinateur semble utiliser les pilotes sons ALSA. C'est en g��al le\n" -"meilleur choix, cependant un module d'emulation est manquant et linphone en\n" -"a besoin. Veuillez s'il vous plait executer la commande\n" -"'modprobe snd-mixer-oss' en tant que root afin de le charger." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "Découverte STUN en cours" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "Collection des candidats locaux ICE en cours..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1551,7 +1918,7 @@ msgstr "Parti" #: ../coreapi/friend.c:57 msgid "Using another messaging service" -msgstr "" +msgstr "Utilisation d'un autre service de messagerie" #: ../coreapi/friend.c:60 msgid "Offline" @@ -1562,218 +1929,210 @@ msgid "Pending" msgstr "En attente" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Bug inconnu" +msgid "Vacation" +msgstr "En congé" -#: ../coreapi/proxy.c:204 -msgid "The sip proxy address you entered is invalid, it must start with \"sip:\" followed by a hostname." -msgstr "L'addresse SIP du proxy est invalide. Elle doit commencer par \"sip:\" suivie par un nom de domaine." +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Status inconnu" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:295 +msgid "" +"The sip proxy address you entered is invalid, it must start with \"sip:\" " +"followed by a hostname." +msgstr "" +"L'adresse SIP du proxy est invalide. Elle doit commencer par \"sip:\" suivie " +"par un nom de domaine." + +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" "L'identité SIP que vous avez fourni est invalide.\n" -"Elle doit être de la forme sip:username@domain, comme par example sip:alice@example.net" +"Elle doit être de la forme sip:utilisateur@domaine, comme par exemple sip:" +"alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Recherche de la destination du numéro de téléphone..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "La destination n'a pu être trouvée." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "Echec de la connexion en tant que %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "chargement depuis %s" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "Sonnerie distante." -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." msgstr "Sonnerie distante..." -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." -msgstr "Prise d'appel anticipée" +msgstr "Prise d'appel anticipée." -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "%s est maintenant en attente." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "Appel répondu par %s - en attente" -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "Appel répondu par %s." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "" +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "Incompatible, vérfiez les codecs ou les paramètres de sécurité..." -#: ../coreapi/callbacks.c:437 -#, fuzzy +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Paramètres media incompatibles." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "Reprise..." +msgstr "Appel repris." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "L'appel a été mis en attente." -#: ../coreapi/callbacks.c:452 -#, fuzzy +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "L'appel a été repris par le correspondant." +msgstr "L'appel est modifié par la partie distante." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Appel terminé." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Occupé..." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "L'usager est temporairement indisponible." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "L'usager ne souhaite pas être dérangé" -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Appel décliné." -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "Pas de réponse." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "Délai d'attente de la requête dépassé." -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "Erreur de protocole" - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "Redirection" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "L'appel a échoué." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Enregistrement sur %s effectué." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Désenregistrement sur %s effectué." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "Pas de réponse" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Echec de l'enregistrement sur %s: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Service indisponible, nouvelle tentative" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 #, c-format msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "Les paramètres d'appel ont été modifiés avec succès." + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Vous avez manqué %i appel" msgstr[1] "Vous avez manqué %i appels" -#~ msgid "Chat with %s" -#~ msgstr "Chat avec %s" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "interrompu" -#~ msgid "Choosing a username" -#~ msgstr "Choix du nom d'utilisateur" +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "terminé" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Information sur le contact" +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "manqué" -#~ msgid "Contacts" -#~ msgstr "Contacts" +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "inconnu" -#~ msgid "Enable video" -#~ msgstr "Activer la video" +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s à %s\n" +"De : %s\n" +"Vers : %s\n" +"Status : %s\n" +"Durée : %i min %i sec\n" -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "" -#~ "Entrez un nom d'utilisateur, un numéro de téléphone, ou une addresse SIP" +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "Appel sortant" -#~ msgid "Lookup:" -#~ msgstr "Rechercher:" - -#~ msgid "in" -#~ msgstr "dans" - -#~ msgid "We are being paused..." -#~ msgstr "Mise en attente..." - -#~ msgid "No common codecs" -#~ msgstr "Pas de codecs commun" - -#~ msgid "Authentication failure" -#~ msgstr "Echec d'authentification" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "Pauser les appels en cours\n" -#~ "et répondre" - -#~ msgid "Contact list" -#~ msgstr "Liste de contacts" - -#~ msgid "Audio & video" -#~ msgstr "Audio et video" - -#~ msgid "Audio only" -#~ msgstr "Audio seul" - -#~ msgid "Duration:" -#~ msgstr "Durée:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Historique des appels" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "Register at startup" -#~ msgstr "S'enregistrer au démarrage" - -#~ msgid "Ports" -#~ msgstr "Ports utilisés" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "Désolé, vous devez d'abord mettre en attente l'appel en cours." - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "" -#~ "Il y a déjà un appel en cours, veuillez d'abord le mettre en attente ou " -#~ "le raccrocher." +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "Impossibde de jouer %s." diff --git a/po/he.po b/po/he.po index bba94e8ca..540d02ee6 100644 --- a/po/he.po +++ b/po/he.po @@ -1,81 +1,93 @@ -# Hebrew translations for linphone -# Copyright (C) Belledonne Communications,2010 -# This file is distributed under the same license as the linphone package. -# Eli Zaretskii , 2012. -# Isratine Citizen , 2012. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# Eli Zaretskii , 2012 +# Gautier Pelloux-Prayer , 2015 +# GenghisKhan , 2014 +# GenghisKhan , 2014 +# GenghisKhan , 2012-2013 msgid "" msgstr "" -"Project-Id-Version: Linphone 3.5.2\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2012-12-27 10:14+0200\n" -"Last-Translator: Isratine Citizen \n" -"Language-Team: Rahut \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Hebrew (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/he/)\n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.5.4\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "התקשר אל %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "שלח טקסט אל %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "שיחות אחרונות (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "לא זמין (n/a)" + +#: ../gtk/calllogs.c:318 msgid "Aborted" msgstr "ננטשה" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" msgstr "הוחמצה" -# דחיה -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "לדחות" +msgstr "נדחתה" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "דקה %i" msgstr[1] "%i דקות" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "שניה %i" msgstr[1] "%i שניות" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -"%s\t%s\tאיכות: %s\n" -"%s\t%s %s\t" +"%s\tאיכות: %s\n" +"%s\t%s\t" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "לא זמין (n/a)" - -#: ../gtk/calllogs.c:105 -#, fuzzy, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" msgstr "" -"%s\t%s\tאיכות: %s\n" -"%s\t%s %s\t" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "ועידה" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "אני" @@ -84,321 +96,318 @@ msgstr "אני" msgid "Couldn't find pixmap file: %s" msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" -# cli -#: ../gtk/main.c:89 -#, fuzzy +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." -msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמן ביצוע." +msgstr "" -# cli -#: ../gtk/main.c:96 -#, fuzzy +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." +msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -# cli -#: ../gtk/main.c:110 -#, fuzzy +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "התחל במגש המערכת בלבד, אל תציג את הממשק הראשי." +msgstr "" -# cli -#: ../gtk/main.c:117 -#, fuzzy +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "כתובת להתקשרות ברגע זה" +msgstr "" -# cli -#: ../gtk/main.c:124 -#, fuzzy -msgid "if set automatically answer incoming calls" -msgstr "באם אפשרות זו נקבעת ענה אוטומטית לקריאות נכנסות" - -# cli -#: ../gtk/main.c:131 -#, fuzzy +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -"ציין מדור העבודה (אמור להיות מבוסס על ההתקנה, למשל: c:\\Program Files" -"\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "התקשרות באמצעות %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -# הקשר שלהם -# אם התשובה -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"‫%s מעוניין להוסיפך אל רשימת אנשי הקשר שלו.\n" -"האם ברצונך להרשות להם לראות את מצב נוכחותך או להוסיפם אל רשימת אנשי הקשר " -"שלך ?\n" -"היה ותשובתך תהיה לא, אדם זה יהיה מסומן באופן זמני ברשימה השחורה." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"נא להזין את סיסמתך עבור שם משתמש %s\n" -" בתחום %s:" +"אנא הזן סיסמה עבור משתמש %s\n" +"במתחם %s:" -# שיחה -#: ../gtk/main.c:1051 +#: ../gtk/main.c:1256 msgid "Call error" msgstr "שגיאת קריאה" -# Conversation ended -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "שיחה הסתיימה" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "לענות" -# דחיה -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "לדחות" -# Conversation paused -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 msgid "Call paused" msgstr "שיחה הושהתה" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "מאת %s" +msgid "by %s" +msgstr "על ידי %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "‏%s רוצה להתחיל וידאו. האם אתה מסכים ?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "קישור אתר רשת" -# ‫Linphone - וידאופון במרשתת -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "‫Linphone - וידאופון אינטרנטי" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "‫%s (משתמטת)" +msgstr "‫%s (ברירת מחדל)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "אנחנו מועברים אל %s" -# קריאות שמע -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" -"לא תהיה ביכולתך לשלוח או לקבל שיחות שמע." +"לא תהיה ביכולתך לשלוח או לקבל שיחות אודיו." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "וידאופון SIP חופשי" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "הוסף אל ספר כתובות" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "מצב נוכחות" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "שם" -#: ../gtk/friendlist.c:538 +#: ../gtk/friendlist.c:722 msgid "Call" msgstr "קריאה" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "" +msgstr "שיחה" -# a name or a number -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "חיפוש במדור %s" -# איש־קשר -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "כתובת sip לא תקפה !" -# צור קשר עם -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "התקשר אל %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "שלח טקסט אל %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "ערוך איש קשר '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "מחק היסטוריית שיחה של '%s'" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "הוסף איש קשר חדש מן מדור %s" -# קצב תדר תדירות מהירות -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "שיעור (הרץ)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "מצב" -# שיעור סיביות מינימלי -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "קצב נתונים מינימלי (קי״ב/שנ׳)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "פרמטרים" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "מופעל" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "לא מופעל" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "חשבון" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "English" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Español" -# português do Brasil -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "português brasileiro" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polski" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Nederlands" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Česky" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "中文" -# 繁体字 -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "繁體字" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "norsk" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" +msgstr "עברית" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "српски srpski" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" msgstr "" -# selected הנבחרת -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "ללא" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -411,7 +420,6 @@ msgstr "" "גרסא מאוחרת יותר זמינה מן %s.\n" "האם ברצונך לפתוח דפדפן בכדי להורידה ?" -# בידך #: ../gtk/update.c:91 msgid "You are running the lastest version." msgstr "ברשותך הגרסא האחרונה של לינפון." @@ -443,97 +451,89 @@ msgid_plural "Found %i contacts" msgstr[0] "נמצא איש קשר %i" msgstr[1] "נמצאו %i אנשי קשר" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"ברוך בואך !\n" -"אשף זה יסייע לך לעשות שימוש בחשבון SIP עבור שיחותייך." -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "צור חשבון אצל linphone.org" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "כבר קיים חשבון linphone.org ברשותי וברצוני לעשות בו שימוש" -# כבר קיים ברשותי חשבון sip -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" msgstr "כבר קיים חשבון sip ברשותי וברצוני לעשות בו שימוש" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" -msgstr "הזן את שם משתמשך אצל linphone.org" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "שם משתמש:" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "סיסמה:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "הזן את מידע חשבונך" - -#: ../gtk/setupwizard.c:120 +#: ../gtk/setupwizard.c:221 msgid "Username*" msgstr "שם משתמש*" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:222 msgid "Password*" msgstr "סיסמה*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "מתחם*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "פרוקסי" -# נדרשים -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "הזן את שם משתמשך אצל linphone.org" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "שם משתמש:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "סיסמה:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "(*) שדות חובה" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" msgstr "שם משתמש: (*)" -#: ../gtk/setupwizard.c:300 +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" msgstr "סיסמה: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "דוא״ל: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "אימות סיסמתך: (*)" -# אינו בר־השגה -# לשוב אחורה -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -"שגיאה, חשבון לא אומת, שם משתמש כבר בשימוש או שרת לא ניתן להשגה.\n" -"נא לחזור ולנסות שוב." -# תודה רבה -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "תודה לך. חשבונך מוגדר ומוכן לשימוש כעת." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" -# לאחר מכן -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -542,442 +542,471 @@ msgstr "" "נא לאמת את חשבונך באמצעות הקלקה על הקישור ששלחנו לך עתה באמצעות דוא״ל.\n" "אחרי כן נא לחזור לכאן וללחוץ על הלחצן 'קדימה'." -# Wizard אשף -# סייע -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"שגיאה, חשבון לא אומת, שם משתמש כבר בשימוש או שרת לא ניתן להשגה.\n" +"נא לחזור ולנסות שוב." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "תודה לך. חשבונך מוגדר ומוכן לשימוש כעת." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "ברוך בואך אל אשף הגדרת החשבון" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "אשף הגדרת חשבון" -# שלב -#: ../gtk/setupwizard.c:565 +#: ../gtk/setupwizard.c:588 msgid "Configure your account (step 1/1)" msgstr "הגדרת חשבונך (צעד 1/1)" -#: ../gtk/setupwizard.c:570 +#: ../gtk/setupwizard.c:592 msgid "Enter your sip username (step 1/1)" msgstr "הזנת שם משתמש sip (צעד 1/1)" -#: ../gtk/setupwizard.c:574 +#: ../gtk/setupwizard.c:596 msgid "Enter account information (step 1/2)" msgstr "הזנת מידע חשבון (צעד 1/2)" -# תקפות -#: ../gtk/setupwizard.c:583 +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 msgid "Validation (step 2/2)" msgstr "אימות (צעד 2/2)" -#: ../gtk/setupwizard.c:588 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "שגיאה" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "מסיים כעת" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "שיחה מס׳ %i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "העברה אל שיחה מס׳ %i עם %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "לא נמצא" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "לא בשימוש" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "קריאה נכשלה." +msgid "ICE not activated" +msgstr "‏ICE לא מופעלת" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "‏ICE נכשלה" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "‏ICE מצויה כעת בעיצומה" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "מכוון מחדש" +msgid "Going through one or more NATs" +msgstr "עובר דרך NAT אחד או יותר" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "ישיר" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "דרך שרת ממסר" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "‏uPnP לא מופעלת" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "‏uPnP מצויה כעת בעיצומה" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "‏uPnp לא זמינה" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "‏uPnP מורצת כעת" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "‏uPnP נכשלה" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "ישיר או דרך שרת" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"הורדה: %f\n" +"העלאה: %f (קי״ב/שנ׳)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 -msgid "Hang up" +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f שניות" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "נתק" + +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "מתקשר כעת..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +#, fuzzy +msgid "00:00:00" msgstr "‭00::00::00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "טובה" -# רגילה -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "ממוצעת" -# weak חלשה חלושה רפויה רופפת -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "דלה" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "דלה מאוד" -# רעה -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "גרועה מדי" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "לא זמינה" -# באמצעות -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "מאובטחת על ידי SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" -# set or unset verification state of ZRTP SAS. -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "הגדר כלא מאומתת" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "הגדר כמאומתת" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "בשיחת ועידה" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "שיחה מושהית" -# שעות %02i דקות %02i שניות %02i -# Force LTR time format (hours::minutes::seconds) with LRO chatacter (U+202D) -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "‭%02i::%02i::%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "שיחה הסתיימה." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "העברה מצויה כעת בעיצומה" -#: ../gtk/incall_view.c:734 -#, fuzzy +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "העברה" +msgstr "העברה הסתיימה." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "העברה" +msgstr "העברה נכשלה." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "חזרה" +msgstr "חזור" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" -msgstr "השהיה" +msgstr "השהה" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"מקליט אל תוך\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(מושהה)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "נא להזין מידע התחברות עבור %s" -# מתקשר Caller -# זה ש: נתקשר או מתוקשר או הותקשר? +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "נמוך מדי" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "טוב" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "חזק מדי" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "התקן לכידה" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "אין קול" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "התקן השמעה" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "נגן שלושה צפצופים" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "הבא נתחיל את Linphone עכשיו" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -msgid "Callee name" -msgstr "שם המקבל" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "שיגור" - -#: ../gtk/main.ui.h:3 -#, fuzzy -msgid "End conference" -msgstr "בשיחת ועידה" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "תוויות" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "העברה" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "בשיחה כעת" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "משך זמן" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "אומדן איכות שיחה" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_אפשרויות" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "אפשר ראות-עצמית" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "_עזרה" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "הצג חלון ניפוי שגיאות" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "_עמוד הבית" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "בדיקת _עדכונים" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "אשף חשבון" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "כתובת SIP או מספר טלפון" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "התחלת שיחה חדשה" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "הוסף" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "ערוך" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9 (סעפ)" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8 (צק)" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7 (רשת)" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6 (זחט)" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5 (יכל)" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4 (מנ)" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3 (אבג)" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2 (דהו)" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "חיפוש" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "הוסף אנשי קשר מן מדור" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "הוספת איש קשר" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "לוח מקשים" - -# קריאות אחרונות -#: ../gtk/main.ui.h:49 -msgid "Recent calls" -msgstr "שיחות אחרונות" - -# הזהות הנוכחית שלי -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "זהותי הנוכחית:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "שם משתמש" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "סיסמה" - -# מרשתת -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "חיבור אינטרנט:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "חבר אותי אוטומטית" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "מידע התחברות" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "ברוך בואך !" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "כל המשתמשים" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "משתמשים מקוונים" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "‫ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "ערוץ סיב" -# משתמט -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "ברירת מחדל" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" +msgstr "מחק" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_אפשרויות" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" msgstr "" -#: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "אודות לינפון" +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "התחל תמיד וידאו" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "אפשר ראות-עצמית" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_עזרה" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "הצג חלון ניפוי שגיאות" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_עמוד הבית" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "בדיקת _עדכונים" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "אשף חשבון" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "כתובת SIP או מספר טלפון" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "התחל שיחה חדשה" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "אנשי קשר" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "חיפוש" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "הוסף אנשי קשר מן מדור" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "הוסף איש קשר" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "שיחות אחרונות" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "זהותי הנוכחית:" + +#: ../gtk/about.ui.h:1 +msgid "About Linphone" +msgstr "" -# Should be updated to 2012 2013 -# כל הזכויות שמורות (C) ‫Belledonne Communications, ‫2010\n #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "‫(C) ‫Belledonne Communications,‫2010\n" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -996,6 +1025,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -1026,16 +1056,14 @@ msgstr "גלול אוטומטית לסוף" msgid "Linphone - Authentication required" msgstr "‫Linphone - נדרש אימות" -# תחום #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "נא להזין את סיסמת המתחם" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "זהות משתמש (‫UID)" +msgstr "מזהה משתמש" -# קריאות #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "היסטוריית שיחות" @@ -1044,7 +1072,6 @@ msgstr "היסטוריית שיחות" msgid "Clear all" msgstr "טיהור מוחלט" -# קריאה חוזרת #: ../gtk/call_logs.ui.h:3 msgid "Call back" msgstr "חיוג חוזר" @@ -1074,273 +1101,246 @@ msgid "Looks like sip:" msgstr "נראה כמו ‪sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "ניתוב (רשות):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "משך רישום (בשניות):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "ניתוב (רשות):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "טרנספורט" + +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "רישום" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "פרסם מידע נוכחות" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "אפשר AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "הגדרת חשבון ‫SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "כרטיס קול משתמט" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "כרטיס קול" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "מצלמה משתמטת" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" -msgstr "קודקים של שמע" +msgstr "קודקים של אודיו" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "קודקים של וידאו" -#: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" -msgstr "" - -#: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" -msgstr "" - #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" +msgid "C" msgstr "" #: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "‏SIP ‏(UDP)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "‏SIP ‏(TCP)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "‏SIP ‏(TLS)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "הגדרות" -# שידור -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "הגדר יחידת תמסורת מרבית:" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "שלח טזמ״תים (DTMFs) כמידע SIP" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "השתמש בפרוטוקול IPv6 במקום בפרוטוקול IPv4" - -# מוביל -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "טרנספורט" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "סוג הצפנת מדיה" - -# מנהרה -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "וידאו RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "שמע RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "פרוטוקולי רשת עבודה ופורטים" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "חיבור ישיר אל האינטרנט" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "מאחורי NAT \\ חומת־אש (ציון כתובת שער (Gateway IP) למטה)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "כתובת IP פומבית:" - -# שימוש ב־STUN -# utilize -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "מאחורי NAT \\ חומת־אש (ניצול STUN)" - -# שימוש ב־STUN -# utilize -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "מאחורי NAT \\ חומת־אש (ניצול STUN)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "שרת STUN:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "‫NAT וחומת אש" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "הגדרות רשת עבודה" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "צליל צלצול:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "התקן ALSA מיוחד (רשות):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "התקן לכידה:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "התקן צלצול:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "התקן פס קול:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "אפשר ביטול הד" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "שמע" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "התקן קלט וידאו:" - -# רצויה -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "רזולוציית וידאו מועדפת:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "וידאו" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "הגדרות מולטימדיה" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "חלק זה מגדיר את כתובת ה־SIP כאשר אינך עושה שימוש בחשבון SIP" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "שם התצוגה שלך (למשל: יורם יהודה):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "שם המשתמש שלך:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "כתובת SIP נובעת:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "זהות משתמטת" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "אשף" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "הוסף" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "ערוך" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "הסר" -# חשבונות מתווכים -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "חשבונות Proxy" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "מחק סיסמאות" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "פרטיות" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "ניהול חשבונות ‫SIP" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "אפשר" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "צליל צלצול:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "נטרל" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "התקן ALSA מיוחד (רשות):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "קודקים" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "התקן לכידה:" -# ללא הגבלה -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "התקן צלצול:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "התקן פס קול:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "אפשר ביטול הד" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "אודיו" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "התקן קלט וידאו:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 מסמל \"בלי הגבלה\"" -# האם KiB means kibibyte? -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "וידאו" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "מגבלת מהירות העלאה בקי״ב/שנ׳:" -# האם KiB means kibibyte? -# קי״ב (1024) אל מול ק״ב (1000) -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "מגבלת מהירות הורדה בקי״ב/שנ׳:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "אפשר בקרת קצב מסתגלת" -# שיטה ניחוש -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1348,33 +1348,163 @@ msgstr "" "בקרת קצב מסתגלת הינה טכניקה להשערה דינמית של רוחב הפס הזמין במהלך שיחה." -# פס רוחב -# טווח תדרים -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "בקרת רוחב פס" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "הגדרות מולטימדיה" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "הגדר יחידת תמסורת מרבית:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "שלח טזמ״תים (DTMFs) כמידע SIP" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "טרנספורט" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "אודיו RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "מקובע" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "וידאו RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "סוג הצפנת מדיה" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "הצפנת מדיה הינה מנדטורית" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "מינהור" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "שדות DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "פרוטוקולי רשת תקשורת ופורטים" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "חיבור ישיר אל האינטרנט" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "מאחורי NAT / חומת אש (בעזרת STUN לפתירה)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "מאחורי NAT / חומת אש (בעזרת ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "מאחורי NAT / חומת אש (בעזרת uPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "כתובת IP פומבית:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "שרת STUN:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "‫NAT וחומת אש" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "הגדרות רשת תקשורת" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "אפשר" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "נטרל" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "קודקים" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "שפה" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "הצג הגדרות מתקדמות" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "רמה" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "ממשק משתמש" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "סיום" @@ -1386,226 +1516,336 @@ msgstr "חיפוש אנשי קשר בתוך מדור" msgid "Add to my list" msgstr "הוסף אל הרשימה שלי" -# חיפוש מאן דהו #: ../gtk/buddylookup.ui.h:3 msgid "Search somebody" msgstr "חיפוש אחר מישהו" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "נא להמתין" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "הגדרות" +msgid "DSCP settings" +msgstr "אפשרויות DSCP" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "שמע RTP/UDP:" +msgstr "זרם RTP אודיו" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "וידאו RTP/UDP:" +msgstr "זרם RTP וידאו" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "קבע ערכי DSCP (בהקסדצימלי)" #: ../gtk/call_statistics.ui.h:1 msgid "Call statistics" -msgstr "" +msgstr "סטטיסטיקות שיחה" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "קודקים של שמע" +msgstr "קודק של אודיו" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "קודקים של וידאו" +msgstr "קודק של וידאו" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "ניצול רוחב פס IP אודיו" #: ../gtk/call_statistics.ui.h:5 -#, fuzzy -msgid "Media connectivity" -msgstr "סוג הצפנת מדיה" +msgid "Audio Media connectivity" +msgstr "קישוריות מדיום אודיו" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "ניצול רוחב פס IP וידאו" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "קישוריות מדיום וידאו" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "זמן הלוך ושוב" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "מידע איש קשר" +msgstr "סטטיסטיקות ומידע שיחה" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "הגדרת חשבון ‫SIP" +msgstr "הגדר תיעול VoIP" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "מארח" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "פורט" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "הגדר מינהור" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "שם משתמש" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "סיסמה" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" +msgstr "הגדר http proxy (רשות)" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "ננטשה" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "הסתיימה" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "הוחמצה" +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" -# needs to be tested -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "חיפוש" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "שונות" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s אצל %s\n" -"מאת: %s\n" -"אל: %s\n" -"מצב: %s\n" -"משך: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "קריאה יוצאת" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "שלח" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "שם מקבל" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "סיים ועידה" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "הקלט את שיחה זו אל קובץ אודיו" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "וידאו" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "השתק" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "העבר" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "בשיחה כעת" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "משך זמן" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "אומדן איכות שיחה" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "חיבור אינטרנט:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "חבר אותי אוטומטית" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "מידע התחברות" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "מוכן" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "מחפש כעת עבור יעד מספר טלפון..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "לא ניתן לפתור את מספר זה." - -# לרוב -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"לא ניתן היה לפענח את הכתובת שניתנה. כתובת sip בדרך כלל נראית כך: sip:" -"user@domain" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "מתקשר כעת" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "לא ניתן להתקשר" -# מספר השיחות המקבילות המרבי -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "הגענו אל המספר המרבי של שיחות מקבילות, עמך הסליחה" -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "מתקשר/ת אליך" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr " ומבקש/ת מענה אוטומטי." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -# פרמטרי קריאה -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "מתאים כעת פרמטרים של שיחה..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "מקושר." -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "קריאה בוטלה" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "לא ניתן להשהות את השיחה" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "משהה כעת שיחה נוכחית..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" -"זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של pcm oss\n" -"נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" -"‫'modprobe snd-pcm-oss' כמשתמש שורש (משתמש על) כדי להטעינו." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" -"זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של mixer oss\n" -"נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" -"‫'modprobe snd-mixer-oss' כמשתמש שורש (משתמש על) כדי להטעינו." - -# במהלך (או) באמצע חיפוש... -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "בדיקת STUN מצויה כעת בעיצומה..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "צבירת מועמדים מקומיים של ICE מצויה כעת בעיצומה..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1615,7 +1855,6 @@ msgstr "מקוון" msgid "Busy" msgstr "עסוק" -# מיד אשוב #: ../coreapi/friend.c:39 msgid "Be right back" msgstr "כבר אשוב" @@ -1636,14 +1875,10 @@ msgstr "בארוחת צהריים" msgid "Do not disturb" msgstr "נא לא להפריע" -# Is it: change residence? -# What is the difference with Away? -# fr Parti #: ../coreapi/friend.c:54 msgid "Moved" msgstr "עברתי דירה" -# additional נוסף #: ../coreapi/friend.c:57 msgid "Using another messaging service" msgstr "אני עושה כעת שימוש בשירות מסרים אחר" @@ -1657,18 +1892,21 @@ msgid "Pending" msgstr "בהמתנה" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "תקלה לא ידועה" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -"כתובת sip proxy שהוזנה הינה שגויה, זו צריכה להתחיל עם‭\"sip:\" ‬ לאחר שם מארח." +"כתובת sip proxy שהזנת הינה שגויה, זו צריכה להתחיל עם‭\"sip:\" ‬ לאחר שם מארח." -# כמו למשל -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1676,261 +1914,181 @@ msgstr "" "זהות sip שהוזנה הינה שגויה.\n" "זו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" -# בשם כ־ -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "מחפש כעת עבור יעד מספר טלפון..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "לא ניתן לפתור את מספר זה." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "לא ניתן להתחבר בזהות %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "צלצול מרוחק." -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." msgstr "צלצול מרוחק..." -# A SIP state -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "מדיה מוקדמת." -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "שיחה עם %s מושהית." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "קריאה נענתה על ידי %s - בהמתנה." -# renewed -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "קריאה חודשה." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "קריאה נענתה על ידי %s." -# לא תואם -# אי תאימות -# אי התאמה -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "חוסר תאימות, נא לבדוק קודקים..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "חוסר תאימות, בדוק קודקים או הגדרות אבטחה..." -#: ../coreapi/callbacks.c:437 -#, fuzzy +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "פרמטריי מדיה חסרי תואמים." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "חזרנו..." +msgstr "חזרנו." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "אנו מושהים על ידי צד אחר." -# באופן מרוחק -#: ../coreapi/callbacks.c:452 -#, fuzzy +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "שיחה עודכנה מרחוק..." +msgstr "שיחה עודכנה מרחוק." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "קריאה הסתיימה." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "משתמש עסוק כעת." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "משתמש לא זמין זמנית." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "משתמש לא מעוניין שיפריעו לו." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "קריאה סורבה." -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "אין תגובה." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "שגיאת פרוטוקול." - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "מכוון מחדש" -# לא תואם -# אי תאימות -# אי התאמה -#: ../coreapi/callbacks.c:600 -#, fuzzy -msgid "Incompatible media parameters." -msgstr "חוסר תאימות, נא לבדוק קודקים..." - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "קריאה נכשלה." -# הרשמה אצל %s הושלמה בהצלחה. -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "רישום אצל %s הושלם בהצלחה." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "אי רישום אצל %s סוים." -# Pas de réponse -# no response in defined time -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "אין היענות תוך זמן מוגדר" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "רישום אצל %s נכשל: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 #, c-format msgid "Authentication token is %s" msgstr "אות האימות הינה %s" -# האם כדאי לחקות את הטלפונים הניידים? שיחות של נענו -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "החמצת שיחה %i." msgstr[1] "החמצת %i שיחות." -# שוחחו -#~ msgid "Chat with %s" -#~ msgstr "שיחה עם %s" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" -#~ msgid "Contacts" -#~ msgstr "אנשי קשר" +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" -#~ msgid "Enable video" -#~ msgstr "הפעל וידאו" +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" -# הזנת -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "נא להזין שם משתמש, מספר טלפון, או כתובת sip מלאה" +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" -# עיון -#~ msgid "Lookup:" -#~ msgstr "חיפוש:" +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" -# במסגרת -#~ msgid "in" -#~ msgstr "בקרב" +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "רישום אל FONICS\n" -#~ "רשת עבודה וירטואלית !" - -#~ msgid "edit" -#~ msgstr "עריכה" - -#~ msgid "We are being paused..." -#~ msgstr "אנחנו כעת מושהים..." - -#~ msgid "No common codecs" -#~ msgstr "אין קודקים משותפים" - -#~ msgid "Authentication failure" -#~ msgstr "כשל באימות" - -#~ msgid "Please choose a username:" -#~ msgstr "נא לבחור שם משתמש:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "בודק כעת אם '%s' זמין..." - -#~ msgid "Please wait..." -#~ msgstr "נא להמתין..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "צר לי, שם משתמש זה כבר קיים. נא לנסות אחד חדש." - -#, fuzzy -#~ msgid "Ok !" -#~ msgstr "חיובי !" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "בעיית תקשורת, נא לנסות שוב מאוחר יותר." - -#~ msgid "Choosing a username" -#~ msgstr "בחירת שם משתמש" - -# וידוא -#, fuzzy -#~ msgid "Verifying" -#~ msgstr "מאמת כעת" - -# וידוא -#~ msgid "Confirmation" -#~ msgstr "אימות" - -#~ msgid "Creating your account" -#~ msgstr "חשבונך נוצר כעת" - -#~ msgid "Now ready !" -#~ msgstr "מוכן כעת !" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "Pauser les appels en cours\n" -#~ "et répondre" - -#~ msgid "Contact list" -#~ msgstr "Liste de contacts" - -#~ msgid "Audio & video" -#~ msgstr "Audio et video" - -#~ msgid "Audio only" -#~ msgstr "Audio seul" - -#~ msgid "Duration:" -#~ msgstr "Durée:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Historique des appels" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "Register at startup" -#~ msgstr "S'enregistrer au démarrage" - -#~ msgid "Ports" -#~ msgstr "Ports utilisés" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "Désolé, vous devez d'abord mettre en attente l'appel en cours." - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "" -#~ "Il y a déjà un appel en cours, veuillez d'abord le mettre en attente ou " -#~ "le raccrocher." +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/hu.po b/po/hu.po index 0367b7d16..dc1155db5 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,366 +1,410 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Free Software Foundation, Inc. -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2007-12-14 11:12+0100\n" -"Last-Translator: \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Hungarian (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/hu/)\n" +"Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "%s hívása" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Szöveg küldése a következőnek: %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "-" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "megszakítva" +msgstr "Megszakítva" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "elhibázva" +msgstr "Nem fogadott" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "line" +msgstr "Elutasítva" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" -msgstr "" +msgstr "Konferencia" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" -msgstr "" +msgstr "én" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." +msgstr "Futás közben némi hibakeresési információ az stdout-ra naplózása." + +#: ../gtk/main.c:139 +msgid "display version and exit." msgstr "" -#: ../gtk/main.c:96 +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "" +msgstr "fájl elérési útja, melybe a naplók kerülnek." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Linphone indítása, videó kikpacsolva. " -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "" +msgstr "Csak a tálcaikon indítása, ne mutassa a fő ablakot." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "" +msgstr "Cím azonnali híváshoz" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" +"Adjon meg egy munkakönyvtárat (ennek az installációs könyvtárnak kéne " +"lennie, pl. C:\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, fuzzy, c-format -msgid "Call with %s" -msgstr "Chat-elés %s -el" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Linphone - Híváselőzmények" +msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" -msgstr "" +msgstr "Hívás fogadása" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "line" +msgstr "Elutasítás" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "megszakítva" +msgstr "Hívás várakoztatva" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "" +msgid "by %s" +msgstr "a következő által: %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s szerené elidítani a videót. Elfogadja?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" +msgstr "Internetes oldal" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "" - -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "" +msgstr "%s (Alapértelmezett)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" -msgstr "" +msgstr "Át vagyunk irányítva ide: %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" +"Hangkártya nincs érzékelve ezen a számítógépen.\n" +"Nem fog tudni hang hívásokat küldeni vagy fogadni." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" -#: ../gtk/friendlist.c:335 -#, fuzzy -msgid "Add to addressbook" -msgstr "Címjegyzék" +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "Hozzáadás címjegyzékhez" + +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Jelenlét státusz" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Név" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Hivás előzmények" +msgstr "Hivás" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Chat szoba" +msgstr "Csevegés" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" -msgstr "" +msgstr "Keresés ebben a könyvtárban: %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" -msgstr "" +msgstr "Érvénytelen sip partner !" -#: ../gtk/friendlist.c:775 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Hivás előzmények" - -#: ../gtk/friendlist.c:776 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format msgid "Edit contact '%s'" -msgstr "Kapcsolatinformációk szerkesztése" +msgstr "Kapcsolatinformációk szerkesztése: '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" +msgstr "'%s' partner törlése" + +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" -msgstr "" +msgstr "Új partner hozzáadása ebből a könyvtárból: %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Érték (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Állapot" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Paraméterek" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Engedélyezve" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Tiltva" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Hozzáférés" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" -msgstr "" +msgstr "angol" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" -msgstr "" +msgstr "francia" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" -msgstr "" +msgstr "svéd" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" -msgstr "" +msgstr "olasz" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" -msgstr "" +msgstr "spanyol" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" -msgstr "" +msgstr "brazil-portugál" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" -msgstr "" +msgstr "lengyel" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" -msgstr "" +msgstr "német" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" -msgstr "" +msgstr "orosz" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" -msgstr "" +msgstr "japán" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" -msgstr "" +msgstr "holland" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" -msgstr "" +msgstr "magyar" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" -msgstr "" +msgstr "cseh" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" -msgstr "" +msgstr "egyszerúsített kínai" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" -msgstr "" +msgstr "tradícionális kínai" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" -msgstr "" +msgstr "norvég" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" +msgstr "héber" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" +"Újra kell indítania a linphone-t, hogy az új nyelv kiválasztása érvényre " +"jusson. " -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "Nincs" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" +msgstr "SRTP" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -368,32 +412,32 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" +"Elérhető egy újabb verzió a következőn: %s.\n" +"Szeretné, hogy a letöltéshez egy új böngésző ablak nyíljon?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "" +msgstr "Ön a legfrissebb verziót használja." #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" -msgstr "" +msgstr "Utónév, Családnév" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "" +msgstr "Hiba a kiszolgálóval történő kommunikáció során." #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "Kapcsolódás" +msgstr "Kapcsolódás..." #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "Kapcsolódva." +msgstr "Kapcsolódva" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." -msgstr "" +msgstr "Adatok fogadása..." #: ../gtk/buddylookup.c:180 #, c-format @@ -402,541 +446,569 @@ msgid_plural "Found %i contacts" msgstr[0] "" msgstr[1] "" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Fiók létrehozása a linphone.org -on" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "" +msgstr "Már rendelkezem linphone.org fiókkal, azt szeretném használni" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" +msgstr "Már rendelkezem sip fiókkal, azt szeretném használni" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "felhasználónév:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "jelszó:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "felhasználónév:" +msgstr "Felhasználónév*" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "jelszó:" +msgstr "Jelszó*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" -msgstr "" +msgstr "Tartomány" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" -msgstr "" +msgstr "Proxy" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Adja meg linphone.org felhasználónevét" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Felhasználónév:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Jelszó:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Mező kitöltése szükséges" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "felhasználónév:" +msgstr "Felhasználónév: (*)" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "jelszó:" +msgstr "Jelszó: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "E-mail: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" +msgstr "Jelszó megerősítése: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" +"Kérjük, érvényesítse fiókját az általunk elektronikus levélben küldött " +"hivatkozásra kattintva.\n" +"Azután térjen vissza ide és kattintson a Következő gombra." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Hiba, a fiók nincs érvényesítve. Valaki már használja ezt a felhasználónevet " +"vagy a kiszolgáló nem elérhető.\n" +"Kérjük, lépjen vissza és próbálja újra." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Köszönjük! Az Ön fiókját beállítottuk és használatra kész." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:559 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:565 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "A fiók beállítása varázsló üdvözli Önt" #: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" +msgid "Account setup assistant" +msgstr "Fiók beállítása varázsló" #: ../gtk/setupwizard.c:588 -msgid "Error" -msgstr "" +msgid "Configure your account (step 1/1)" +msgstr "Az Ön fiókjának beállítása (1/1 lépés)" #: ../gtk/setupwizard.c:592 -msgid "Terminating" +msgid "Enter your sip username (step 1/1)" +msgstr "Adja meg sip felhasználónevét (1/2 lépés)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Adja meg a fiókinformációt (1/2 lépés)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format -msgid "Call #%i" -msgstr "Hivás előzmények" +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Érvényesítés (2/2 lépés)" -#: ../gtk/incall_view.c:150 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Hiba" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "Befejezés" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "Hívás #%i" + +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" -msgstr "" +msgstr "Átirányítás #%i híváshoz ezzel: %s " -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Nem használt" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Hívás elutasítva" +msgid "ICE not activated" +msgstr "ICE nincs aktiválva" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "ICE nem sikerült" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "ICE folyamatban" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Átirányítva idw %s..." +msgid "Going through one or more NATs" +msgstr "Átmegy egy vagy több NAT-on" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "Közvetlen" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Közvetítő kiszolgálón keresztül" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP nincs aktiválva" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP folyamatban" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnP nem elérhető" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP fut" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP nem sikerült" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "közvetlen vagy kiszolgálón keresztül" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"letöltés: %f\n" +"feltöltés: %f (kbit/mp)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f másodperc" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" -msgstr "" +msgstr "Befejezés" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Kapcsolatilista" +msgstr "Hívás folyamatban..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Beérkező hívás" +msgstr "Beérkező hívás" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "" +msgstr "jó" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "" +msgstr "közepes" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "" +msgstr "gyenge" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "" +msgstr "nagyon gyenge" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "" +msgstr "rossz" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "" +msgstr "nem elérhető" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" +msgstr "SRTP-vel titkosítva" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "Beállítás ellenőrizetlenként" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "Beállítás ellenőrzöttként" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" -msgstr "" +msgstr "Konferencián" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Kapcsolatilista" +msgstr "vonalban" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "Kapcsolatilista" +msgstr "Várakoztatott hívás" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 -#, fuzzy +#: ../gtk/incall_view.c:834 msgid "Call ended." -msgstr "Hívás vége" +msgstr "Hívás vége." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "Átvitel folyamatban" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "" +msgstr "Átvitel befejezve." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Hívás elutasítva" +msgstr "Az átvitel sikertelen." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "" +msgstr "Visszatérés" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" -msgstr "" +msgstr "Várakoztatás" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Felvétel a következőbe\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Várakoztatva)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" +msgstr "Kérem, adja meg a bejelentkezési információt %s -hoz" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" msgstr "" #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Hívás vége" +msgid "All users" +msgstr "Minden felhasználó" #: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "Hang" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "Beérkező hívás" - -#: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "Információk" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "Video engedélyezés" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "_Help" -msgstr "Help" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Gépeld ide a sip címet vagy a telefonszámot" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Szerkesztés" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Kapcsolatiinformáció" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "Kapcsolatinformációk szerkesztése" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "Beérkező hívás" - -#: ../gtk/main.ui.h:50 -#, fuzzy -msgid "My current identity:" -msgstr "SIP azonosító:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "felhasználónév:" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "jelszó:" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -#, fuzzy -msgid "Automatically log me in" -msgstr "Automatikus valós hostnév megállapítása" - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "Kapcsolatiinformáció" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "Kapcsolatilista" - -#: ../gtk/main.ui.h:57 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:58 -#, fuzzy msgid "Online users" msgstr "Elérhető" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" -msgstr "" +msgstr "Fiber csatorna" -#: ../gtk/main.ui.h:61 -#, fuzzy +#: ../gtk/main.ui.h:5 msgid "Default" -msgstr "SIP azonosító:" +msgstr "Alapértelmezett" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" +msgstr "Törlés" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Beállítások" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" msgstr "" +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Videó indítása mindig" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Saját nézet" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Segítség" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Hibakeresési ablak mutatása" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Honlap" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Frissítések keresése" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Fiók varázsló" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "Adja meg a SIP címet vagy a telefonszámot:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Új hívás kezdeményezése" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Partnerek" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Keresés" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Partnerek hozzáadása könyvtárból" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Partner hozzáadása" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Legutóbbi hívások" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Jelenlegi identitásom:" + #: ../gtk/about.ui.h:1 -#, fuzzy -msgid "About linphone" -msgstr "linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "" +"Internetes videó telefon, mely a szabványos SIP (rfc3261) protokolt " +"használja." #: ../gtk/about.ui.h:5 msgid "" @@ -951,428 +1023,508 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "Sip cím:" +msgstr "SIP cím" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" -msgstr "" +msgstr "A partner jelenlétének mutatása" #: ../gtk/contact.ui.h:4 msgid "Allow this contact to see my presence status" -msgstr "" +msgstr "Megengedem ennek a partnernek, hogy lássa a jelenlétemet" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "Kapcsolatiinformáció" +msgstr "Partner információ" #: ../gtk/log.ui.h:1 msgid "Linphone debug window" -msgstr "" +msgstr "Linphone Hibakereső Ablak" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "" +msgstr "Görgetés a végéhez" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Hitelesítést kértek" +msgstr "Linphone - Hitelesítés szükséges" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" -msgstr "" +msgstr "Kérem adja meg a tartomány jelszavát" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "Felhasználó azonosító" #: ../gtk/call_logs.ui.h:1 -#, fuzzy msgid "Call history" -msgstr "Linphone - Híváselőzmények" +msgstr "Híváselőzmények" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" -msgstr "" +msgstr "Mind törlése" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "Hivás előzmények" +msgstr "Visszahívás" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" -msgstr "" +msgstr "Linphone - SIP fiók beállítása" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "SIP azonosító:" +msgstr "Az Ön SIP azonosítója:" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" -msgstr "" +msgstr "Így néz ki: sip:@" #: ../gtk/sip_account.ui.h:4 msgid "sip:" msgstr "sip:" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "SIP Proxy:" +msgstr "SIP Proxy cím:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" -msgstr "" +msgstr "Így néz ki: sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Út (nem kötelező):" +msgid "Registration duration (sec):" +msgstr "Regisztrálási Időköz (mp):" #: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Regisztrálási Időköz:" +msgid "Contact params (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "Jelenléti információ közlése:" +msgid "Route (optional):" +msgstr "Út (nem kötelező):" #: ../gtk/sip_account.ui.h:11 -msgid "Configure a SIP account" +msgid "Transport" msgstr "" +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Regisztráció" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "Jelenléti információ közlése" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 +msgid "Configure a SIP account" +msgstr "SIP fiók beállítása" + #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" -msgstr "" +msgid "default soundcard" +msgstr "alapértelmezett hangkártya" #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "Audio kodekek" +msgid "a sound card" +msgstr "egy hangkártya" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "Audio kodekek" +msgid "default camera" +msgstr "alapértelmezett kamera" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" -msgstr "" +msgid "Audio codecs" +msgstr "Audió kódekek" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" -msgstr "" +msgid "Video codecs" +msgstr "Videó kódekek" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" -msgstr "" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "" +msgid "SIP (UDP)" +msgstr "SIP (UDP)" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "" +msgid "SIP (TCP)" +msgstr "SIP (TCP)" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "" +msgid "SIP (TLS)" +msgstr "SIP (TLS)" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "Kapcsolatilista" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "Beállítások" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" +msgid "This section defines your SIP address when not using a SIP account" +msgstr "Ez a rész határozza meg az Ön SIP címét, amikor nem használ SIP fiókot" #: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" +msgid "Your display name (eg: John Doe):" +msgstr "Az Ön megjelenített neve (pl. Kis József):" #: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" +msgid "Your username:" +msgstr "Az Ön felhasználóneve:" #: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" +msgid "Your resulting SIP address:" +msgstr "Az Ön így keletkezett SIP címe:" #: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" +msgid "Default identity" +msgstr "Alapértelmezett identitás" #: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" +msgid "Wizard" +msgstr "Varázsló" #: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" +msgid "Add" +msgstr "Hozzáadás" #: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "Sip cím:" +msgid "Edit" +msgstr "Szerkesztés" #: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "Hang eszköz" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Kapcsolatilista" - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "Hálózat" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "Csengőhang:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "Felvevő hang eszköz:" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "Csengőhang forrás:" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Lejátszó hang eszköz:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "Kapcsolatilista" - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "Hang eszköz" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "Kapcsolatilista" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "" - -#: ../gtk/parameters.ui.h:43 -msgid "Your display name (eg: John Doe):" -msgstr "" - -#: ../gtk/parameters.ui.h:44 -#, fuzzy -msgid "Your username:" -msgstr "felhasználónév:" - -#: ../gtk/parameters.ui.h:45 -#, fuzzy -msgid "Your resulting SIP address:" -msgstr "Saját sip cím:" - -#: ../gtk/parameters.ui.h:46 -#, fuzzy -msgid "Default identity" -msgstr "SIP azonosító:" - -#: ../gtk/parameters.ui.h:47 -msgid "Wizard" -msgstr "" - -#: ../gtk/parameters.ui.h:50 msgid "Remove" msgstr "Eltávolítás" -#: ../gtk/parameters.ui.h:51 -#, fuzzy +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "Kapcsolatilista" +msgstr "Proxy fiókok" + +#: ../gtk/parameters.ui.h:28 +msgid "Erase all passwords" +msgstr "Minden kulcsszó törlése" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "Titoktartás" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Manage SIP Accounts" +msgstr "SIP fiókok beállítása" + +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Csengőhang:" + +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Különleges ALSA eszköz (nem kötelező):" + +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Felvevő hang eszköz:" + +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Csengőhang eszköz:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Lejátszó hang eszköz:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Visszhang-elnyomás engedélyezése" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Audió" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Videó bemeneti eszköz:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 +msgid "0 stands for \"unlimited\"" +msgstr "A 0 jelentése \"végtelen\"" + +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Videó" + +#: ../gtk/parameters.ui.h:49 +msgid "Upload speed limit in Kbit/sec:" +msgstr "Feltöltési sebesség korlát (kbit/mp):" + +#: ../gtk/parameters.ui.h:50 +msgid "Download speed limit in Kbit/sec:" +msgstr "Letöltési sebesség korlát (kbit/mp):" + +#: ../gtk/parameters.ui.h:51 +msgid "Enable adaptive rate control" +msgstr "Alkalmazkodó mérték-szabályozás engedélyezése" #: ../gtk/parameters.ui.h:52 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:53 -#, fuzzy -msgid "Privacy" -msgstr "Kapcsolatilista" - -#: ../gtk/parameters.ui.h:54 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Engedélyezés" - -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Tiltás" - -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "Kapcsolatilista" - -#: ../gtk/parameters.ui.h:58 -msgid "0 stands for \"unlimited\"" -msgstr "" - -#: ../gtk/parameters.ui.h:59 -#, fuzzy -msgid "Upload speed limit in Kbit/sec:" -msgstr "Feltöltési sávszélesség (kbit/sec):" - -#: ../gtk/parameters.ui.h:60 -#, fuzzy -msgid "Download speed limit in Kbit/sec:" -msgstr "Letöltési sávszélesség (kbit/sec):" - -#: ../gtk/parameters.ui.h:61 -msgid "Enable adaptive rate control" -msgstr "" - -#: ../gtk/parameters.ui.h:62 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" +"Az alkalmazkodó mérték-szabályozás egy módszer, mely erőteljesen próbálja " +"megállapítani a rendelkezésre álló sávszélességet hívás alatt." + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "Sávszélesség szabályozása" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Multimédia beállítások" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Maximum Továbbítási Egység beállítása:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "DTMF küldése SIP infóként" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Átvitel" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" #: ../gtk/parameters.ui.h:63 -msgid "Bandwidth control" -msgstr "" +msgid "Audio RTP/UDP:" +msgstr "Audió RTP/UDP:" #: ../gtk/parameters.ui.h:64 -#, fuzzy -msgid "Codecs" -msgstr "Kodekek" +msgid "Fixed" +msgstr "Javítva" #: ../gtk/parameters.ui.h:65 -#, fuzzy -msgid "Language" -msgstr "Kapcsolatilista" +msgid "Video RTP/UDP:" +msgstr "Videó RTP/UDP:" #: ../gtk/parameters.ui.h:66 -msgid "Show advanced settings" -msgstr "" +msgid "Media encryption type" +msgstr "Média titkosítás típusa" #: ../gtk/parameters.ui.h:67 -#, fuzzy -msgid "Level" -msgstr "Kapcsolatilista" +msgid "Media encryption is mandatory" +msgstr "Média titkosítás kötelező" #: ../gtk/parameters.ui.h:68 -#, fuzzy -msgid "User interface" -msgstr "felhasználónév:" +msgid "Tunnel" +msgstr "Alagút" #: ../gtk/parameters.ui.h:69 -#, fuzzy +msgid "DSCP fields" +msgstr "DSCP mezők" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Hálózati protokoll és port" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Közvetlen Internet kapcsolat" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "NAT / tűzfal mögött (STUN használata a feloldáshoz)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "NAT / tűzfal mögött (ICE használata)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "NAT / tűzfal mögött (uPnP használata)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Publikus IP cím:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN kiszolgáló:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT és tűzfal" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Hálózati beállítások" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Engedélyezés" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Tiltás" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "Kódekek" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "Nyelv" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "Haladó beállítások megjelenítése" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "Szint" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "Felhasználói környezet" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "Elveszítve" +msgstr "Kész" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "Kapcsolatiinformáció" +msgstr "Partnerek keresése könyvtárban" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" -msgstr "" +msgstr "Hozzáadása a listámhoz" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "Kapcsolatilista" - -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" +msgstr "Keres valakit" #: ../gtk/waiting.ui.h:2 msgid "Please wait" -msgstr "" +msgstr "Kérem várjon" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Hálózat" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1380,198 +1532,318 @@ msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 msgid "Audio RTP stream" -msgstr "" +msgstr "Audió RTP folyam" #: ../gtk/dscp_settings.ui.h:4 msgid "Video RTP stream" -msgstr "" +msgstr "Videó RTP folyam" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "DSCP értékek beállítása (hexadecimális)" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Hivás előzmények" +msgstr "Hívási statisztika" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Audio kodekek" +msgstr "Audió kódek" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Audio kodekek" +msgstr "Videó kódek" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Audió IP sávszélesség használat" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" -msgstr "" +msgid "Audio Media connectivity" +msgstr "Audió média kapcsolat" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Videó IP sávszélesség használat" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "Videó média kapcsolat" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Körbeérés ideje" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Kapcsolatiinformáció" +msgstr "Hívási statisztika és információ" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" -msgstr "" +msgstr "VoIP alagút beállítása" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Hoszt" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "Port" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Alagút beállítása" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Felhasználónév" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Jelszó" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" +msgstr "http proxy beállítása (nem kötelező)" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "megszakítva" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "befejezve" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "elhibázva" +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s nél %s\n" -"Tól: %s\n" -"Ig: %s\n" -"Állapot: %s\n" -"Időtartam: %i perc %i másodperc\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Kimenő hívás" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Küld" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Hívott neve" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Konferencia vége" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Beszélgetés felvétele hangfájlba" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Videó" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Elnémítás" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Átvitel" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "vonalban" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Időtartam" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Hívásminőség" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Internet kapcsolat:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Jelentkeztessen be automatikusan" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Bejelentkezési információ" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Kész" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Telefonszám-cél keresése..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Nem sikkerült értelmezni a számot." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"Az adott szám nem értelmezhető. Egy sip cím általában így néz ki: user@domain" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Kapcsolódás" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "nem sikerült hívni" +msgstr "Nem sikerült hívni" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" +msgstr "Elnézést, elértük a egyidejű hívások maximális számát" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "kapcsolatba lép veled." +msgstr "kapcsolatba lépett veled." -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." -msgstr "" +msgstr "és automatikus választ kért." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." -msgstr "" +msgstr "A hívási jellemzők módosítása..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Kapcsolódva." -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "megszakítva" +msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3102 -#, fuzzy +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "nem sikerült hívni" +msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3107 -#, fuzzy +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "nem sikerült hívni" +msgstr "Jelenlegi hívás várakoztatásának aktiválása..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" -"Ez a legjobb választás. Mindazonáltal a pcm* OSS emuláció modulra\n" -" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" -"'modprobe snd-pcm-oss' parancsot rendszergazdaként." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" -"Ez a legjobb választás. Mindazonáltal a mixer OSS emuláció modulra\n" -" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" -"'modprobe snd-pcm-oss' parancsot rendszergazdaként." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "Stun keresés folyamatban..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "ICE helyi jelentkezők begyűjtése folyamatban..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1582,21 +1854,18 @@ msgid "Busy" msgstr "Foglalt" #: ../coreapi/friend.c:39 -#, fuzzy msgid "Be right back" -msgstr "Legyen igazad" +msgstr "Mindjárt visszajön" #: ../coreapi/friend.c:42 msgid "Away" msgstr "Nem elérhető" #: ../coreapi/friend.c:45 -#, fuzzy msgid "On the phone" -msgstr "Telefonál" +msgstr "Vonalban" #: ../coreapi/friend.c:48 -#, fuzzy msgid "Out to lunch" msgstr "Ebédelni ment" @@ -1605,693 +1874,222 @@ msgid "Do not disturb" msgstr "Ne zavarj" #: ../coreapi/friend.c:54 -#, fuzzy msgid "Moved" -msgstr "Kodekek" +msgstr "Elment" #: ../coreapi/friend.c:57 msgid "Using another messaging service" -msgstr "" +msgstr "Másik üzenő szolgáltatás használata" #: ../coreapi/friend.c:60 -#, fuzzy msgid "Offline" -msgstr "Elérhető" +msgstr "Nem elérhető" #: ../coreapi/friend.c:63 msgid "Pending" -msgstr "" +msgstr "Függőben" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" +msgid "Vacation" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" +"Az Ön által megadott SIP proxy cím érvénytelen. \"sip:\"-tal kell kezdődnie, " +"ezt egy hosztnév követi." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" +"Az Ön által megadott SIP identitás érvénytelen.\n" +"Így kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:" +"aladar@pelda.hu" -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Telefonszám-cél keresése..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Nem sikkerült értelmezni a számot." + +#: ../coreapi/proxy.c:1407 +#, c-format msgid "Could not login as %s" -msgstr "Nemtalálható a pixmap fájl: %s" +msgstr "Nem sikerült belépni ezzel: %s" -#: ../coreapi/callbacks.c:276 -#, fuzzy +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." -msgstr "Távoli szolgáltatások" +msgstr "Távoli csengés." -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Távoli szolgáltatások" +msgstr "Távoli csengés..." -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "Korai médiák." -#: ../coreapi/callbacks.c:352 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:548 +#, c-format msgid "Call with %s is paused." -msgstr "Chat-elés %s -el" +msgstr "A hívás a következővel: %s várakoztatva" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." -msgstr "" +msgstr "%s fogadta a hívást - várakoztatva." -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Hívás vége" +msgstr "Hívás visszatért" -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:575 +#, c-format msgid "Call answered by %s." -msgstr "" -"Hívás vagy\n" -"Válasz" +msgstr "%s válaszolt a hívásra." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" +"Nem kompatibilis, ellenőrizze a kódek- vagy a biztonsági beállításokat..." -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Nem kompatibilis médiajellemzők." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "" +msgstr "Visszatértünk." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "Megállítva a másik fél által." -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "" +msgstr "A hívás távolról frissítve." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "A hívás befejezve." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "A felhasználó foglalt." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "A felhasználó ideiglenesen nem elérhető" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "A felhasználó nem akarja, hogy zavarják." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Hívás elutasítva" -#: ../coreapi/callbacks.c:544 -#, fuzzy -msgid "No response." -msgstr "időtúllépés után nincs válasz" - -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:564 -#, fuzzy +#: ../coreapi/callbacks.c:875 msgid "Redirected" -msgstr "Átirányítva idw %s..." +msgstr "Átirányítva" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Hívás elutasítva" +msgstr "Nem sikerült a hívás." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1009 +#, c-format msgid "Unregistration on %s done." -msgstr "A regisztáció a %s -n sikerült." +msgstr "A kiregisztrálás kész a következőn: %s ." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "időtúllépés után nincs válasz" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Hitelesítési információ" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" -#: ../coreapi/linphonecall.c:2124 -#, fuzzy, c-format +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "Hitelesítési jel: %s" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." -msgstr[0] "Van %i elhibázott hivás." -msgstr[1] "Van %i elhibázott hivás." - -#~ msgid "Chat with %s" -#~ msgstr "Chat-elés %s -el" - -#, fuzzy -#~ msgid "Choosing a username" -#~ msgstr "felhasználónév:" - -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Információk" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Kapcsolódás" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Engedélyezve" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Hitelesítési információ" - -#, fuzzy -#~ msgid "Unmute" -#~ msgstr "Korlátlan" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "Kapcsolatilista" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Audio kodekek" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "Audio kodekek" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "Információk" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Linphone - Híváselőzmények" - -#, fuzzy -#~ msgid "_Linphone" -#~ msgstr "Linphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Kapcsolódva." - -#, fuzzy -#~ msgid "gtk-ok" -#~ msgstr "Eltávolítás" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Kapcsolódva." - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "Kapcsolatilista" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "A géped úgy tűnik, hogy csatlakozik egy IPv6 hálózathoz. Alapból a " -#~ "linphone mindig az IPv4-et használja. Frissítsd a konfigurációdat, ha " -#~ "használni akarod az IPv6-ot" - -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Beérkező hívás" - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "Kodekek" - -#~ msgid "Accept" -#~ msgstr "Elfogad" - -#, fuzzy -#~ msgid "Incoming call from" -#~ msgstr "Beérkező hívás" - -#, fuzzy -#~ msgid "Linphone - Incoming call" -#~ msgstr "Beérkező hívás" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "Audio és video kodekek" - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Bocsánat, a többszörös egyidejű hívások még nem támogatottak!" - -#~ msgid "Could not reach destination." -#~ msgstr "A cél elérhetetlen." - -#~ msgid "Request Cancelled." -#~ msgstr "Kérelem elutasítva." - -#~ msgid "Bad request" -#~ msgstr "Rossz kérés" - -#~ msgid "User cannot be found at given address." -#~ msgstr "Nem telálható felhasználó at adott címen." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "" -#~ "A távoli felhasználó nem rendelkezik a javasolt kódoló-dekódolókkal " -#~ "(codecs)" - -#~ msgid "Timeout." -#~ msgstr "Időtúllépés." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "A távoli gép elérhető, de a kapcsolatot visszautasította." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "A felhasználó nem elérhető pillanatnyilag de meghívja Önt\n" -#~ "thogy lépjen kapcsolatba vele miközben használja a következő alternatív " -#~ "erőforrást:" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Nincs nat/tűzfal cím megadva!" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Hibás nat cím '%s' : %s" - -#~ msgid "Gone" -#~ msgstr "Elveszítve" - -#~ msgid "Waiting for Approval" -#~ msgstr "Jóváhagyásra vár" - -#~ msgid "Be Right Back" -#~ msgstr "Legyen igazad" - -#~ msgid "On The Phone" -#~ msgstr "Telefonál" - -#~ msgid "Out To Lunch" -#~ msgstr "Ebédelni ment" - -#~ msgid "Closed" -#~ msgstr "Lezárva" - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Sip cím:" - -#, fuzzy -#~ msgid "_View" -#~ msgstr "Video" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "RTP beállítások" - -#, fuzzy -#~ msgid "Show logs" -#~ msgstr "Mutasd a hívásokat" - -#, fuzzy -#~ msgid "_About" -#~ msgstr "Hozzáférés" - -#, fuzzy -#~ msgid "Proxy in use" -#~ msgstr "Használt SIP Proxy:" - -#~ msgid "Sound" -#~ msgstr "Hang" - -#, fuzzy -#~ msgid "Proxy accounts" -#~ msgstr "Használt SIP Proxy:" - -#~ msgid "Go" -#~ msgstr "Ugrás" - -#~ msgid "Exit" -#~ msgstr "Kilépés" - -#~ msgid "Shows the address book" -#~ msgstr "Mutasd a címjegyzéket" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Lerak vagy\n" -#~ "Nem válaszol" - -#~ msgid "Or chat !" -#~ msgstr "Vagy chat-elj!" - -#~ msgid "Show more..." -#~ msgstr "További beállítások..." - -#~ msgid "Playback level:" -#~ msgstr "Lejátszási hangerő:" - -#~ msgid "Recording level:" -#~ msgstr "Felvételi hangerő:" - -#~ msgid "Ring level:" -#~ msgstr "Csengetési hangerő:" - -#~ msgid "Controls" -#~ msgstr "Vezérlés" - -#~ msgid "Reachable" -#~ msgstr "Elérhető" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Foglalt vagyok, jövök vissza" - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "A másik fél tájékoztatva lesz, hogy X perc alatt vissza fogsz jönni" - -#~ msgid "mn" -#~ msgstr "perc" - -#~ msgid "Moved temporarily" -#~ msgstr "Ideiglenesen nem elérhető" - -#~ msgid "Alternative service" -#~ msgstr "Átirányítás" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Elérhető" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Nyomja le a számokat a DTMF küldéshez" - -#~ msgid "" -#~ " 3\n" -#~ "def" -#~ msgstr "" -#~ " 3\n" -#~ "def" - -#~ msgid "" -#~ " 2\n" -#~ "abc" -#~ msgstr "" -#~ " 2\n" -#~ "abc" - -#~ msgid "" -#~ " 4\n" -#~ "ghi" -#~ msgstr "" -#~ " 4\n" -#~ "ghi" - -#~ msgid "" -#~ " 5\n" -#~ "jkl" -#~ msgstr "" -#~ " 5\n" -#~ "jkl" - -#~ msgid "" -#~ " 6\n" -#~ "mno" -#~ msgstr "" -#~ " 6\n" -#~ "mno" - -#~ msgid "" -#~ " 7\n" -#~ "pqrs" -#~ msgstr "" -#~ " 7\n" -#~ "pqrs" - -#~ msgid "" -#~ " 8\n" -#~ "tuv" -#~ msgstr "" -#~ " 8\n" -#~ "tuv" - -#~ msgid "" -#~ " 9\n" -#~ "wxyz" -#~ msgstr "" -#~ " 9\n" -#~ "wxyz" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Elérhető partnerek" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "C: 2001\n" -#~ "Made in Old Europe" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "A Linphone egy web-telefon.\n" -#~ "SIP és RTP kompatíbilis." - -#~ msgid "http://www.linphone.org" -#~ msgstr "http://www.linphone.org" - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "IPv6 hálózat használata (ha elérhető)" - -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "Ha egy IPv6 hálózat elérhető, akkor a linphone használja azt." - -#~ msgid "Global" -#~ msgstr "Általános" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Ez az opció azoknak a felhasználóknak kell, akik egy privát hálózaton " -#~ "tűzfal mögül interneteznek. Egyébként üresen kell hagyni." - -#~ msgid "No firewall" -#~ msgstr "Nincs tűzfal" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "STUN szerver használata a tűzfal címének meghatározásához." - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Tűzfal külső címe:" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "NAT beállítások áttekintése (kísérleti)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "A pufferelt milisecondok száma (jitter compensation):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "RTP port, audió használatra:" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "Használj SIP INFO üzenetet RTP rfc2833 helyett a DTMF átvitelnél" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 az ajánlott." - -#~ msgid "Other" -#~ msgstr "Egyéb" - -#~ msgid "micro" -#~ msgstr "mikrofon" - -#~ msgid "Recording source:" -#~ msgstr "Felvételi forrás:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "" -#~ "Visszhang törlés engedélyezése (törli a visszhangot, amit hall a távoli " -#~ "partner" - -#~ msgid "Choose file" -#~ msgstr "Fájl kiválasztás" - -#~ msgid "Listen" -#~ msgstr "Hallgatás" - -#~ msgid "Sound properties" -#~ msgstr "Hang beállítások" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "SIP felhasználó ügynök által használt port:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Erősen ajánlott az 5060-as port használata." - -#~ msgid "SIP port" -#~ msgstr "SIP port" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Azonosító" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Proxy vagy regisztráció hozzáadás" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "" -#~ "Az összes tárolt hitelesítési információ törlése (felhasználónév, " -#~ "jelszó...)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Az audió kódoló-dekódolók listája, a preferencia rendjében:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Figyelem: A pirosban lévő kodekek nem használhatók a jelenlegi " -#~ "internetkapcsolattal." - -#~ msgid "No information availlable" -#~ msgstr "Nem érhető el információ" - -#~ msgid "Codec information" -#~ msgstr "Kodekinformáció" - -#~ msgid "Address Book" -#~ msgstr "Címjegyzék" - -#~ msgid "Select" -#~ msgstr "Kiválasztás" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "A felhasználó jelenleg nem elérhető, de kéri, hogy lépj vele kapcsolatba " -#~ "itt:" - -#~ msgid "None." -#~ msgstr "Nincs." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/Regisztráció konfigurációs doboz" - -#~ msgid "Send registration:" -#~ msgstr "Regisztárció küldés:" - -#~ msgid "Name:" -#~ msgstr "Név:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Láthatósági szabály:" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Láthatóság küldése (látszik a személy elérhetőségi státusza)" - -#~ msgid "New incoming subscription" -#~ msgstr "Új beérkező előfizetés" - -#~ msgid "You have received a new subscription..." -#~ msgstr "Megkaptál egy új előfizetést." - -#~ msgid "Refuse" -#~ msgstr "Hulladék" - -#~ msgid "Authentication required for realm" -#~ msgstr "Hitelesítési kérelem a tartománynak" - -#~ msgid "userid:" -#~ msgstr "felhasználói azonosító:" - -#~ msgid "realm:" -#~ msgstr "tartomány:" - -#~ msgid "Text:" -#~ msgstr "Szöveg:" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "A hívó forrásfoglalást kér. Egyetértesz?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "A hívó nem használ forrásfoglalást. \t\t\t\t\tÍgy is szeretnéd folytatni?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "linphone - hívást fogad innen %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "Kaptál egy előfizetést tőle %s. Ez azt jelenti, hogy ez a személy " -#~ "szeretné, hogy értesítsék a jelenlétinformációd (online, elfoglalt, " -#~ "away...).\n" -#~ "Egyetértesz?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Hitelesítési kérelem ebből a tartományból %s" - -#~ msgid "Wait" -#~ msgstr "Várakozás" - -#~ msgid "Deny" -#~ msgstr "Tiltás" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "Rossz sip cím: egy sip cím általában így néz ki: user@domain" - -#~ msgid "Stun lookup done..." -#~ msgstr "Stun keresés kész..." +msgstr[0] "" +msgstr[1] "" + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/it.po b/po/it.po index 135faa6cc..12b147d6d 100644 --- a/po/it.po +++ b/po/it.po @@ -1,368 +1,418 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Free Software Foundation, Inc. -# FIRST AUTHOR , YEAR. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Fabrizio Carrai, 2015 msgid "" msgstr "" -"Project-Id-Version: Linphone 3.2.0\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" -"Last-Translator: Matteo Piazza \n" -"Language-Team: it \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-08-03 18:31+0000\n" +"Last-Translator: Fabrizio Carrai\n" +"Language-Team: Italian (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/it/)\n" +"Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy -msgid "Aborted" -msgstr "annullato" - -#: ../gtk/calllogs.c:85 -#, fuzzy -msgid "Missed" -msgstr "mancante" - -#: ../gtk/calllogs.c:88 -#, fuzzy -msgid "Declined" -msgstr "Rifiuta" - -#: ../gtk/calllogs.c:94 -#, c-format -msgid "%i minute" -msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:97 -#, c-format -msgid "%i second" -msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk/calllogs.c:100 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" -msgstr "" - -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 -#, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" -msgstr "" - -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 -msgid "Conference" -msgstr "" - -#: ../gtk/conference.c:41 -#, fuzzy -msgid "Me" -msgstr "" -"Chiudi\n" -"microfono" - -#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "" - -#: ../gtk/main.c:89 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk/main.c:96 -msgid "path to a file to write logs into." -msgstr "" - -#: ../gtk/main.c:103 -msgid "Start linphone with video disabled." -msgstr "" - -#: ../gtk/main.c:110 -msgid "Start only in the system tray, do not show the main interface." -msgstr "" - -#: ../gtk/main.c:117 -msgid "address to call right now" -msgstr "" - -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: c:" -"\\Program Files\\Linphone)" -msgstr "" - -#: ../gtk/main.c:498 -#, fuzzy, c-format -msgid "Call with %s" -msgstr "Chat con %s" - -#: ../gtk/main.c:871 -#, c-format -msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" -"%s voui aggiungere il tuo contatto alla sua listaVoui permettere che lui " -"veda il tuo stato o aggiungerlo alla tua lista dei contatti Se rispondi no " -"questo utente sarà momentaneamente bloccato." - -#: ../gtk/main.c:948 -#, c-format -msgid "" -"Please enter your password for username %s\n" -" at domain %s:" -msgstr "Prego inserire la password per username %s e dominio %s" - -#: ../gtk/main.c:1051 -#, fuzzy -msgid "Call error" -msgstr "Cronologia" - -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 -msgid "Call ended" -msgstr "Chiamata terminata" - -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 -msgid "Incoming call" -msgstr "Chimata in entrata" - -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 -msgid "Answer" -msgstr "" - -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -msgid "Decline" -msgstr "Rifiuta" - -#: ../gtk/main.c:1067 -#, fuzzy -msgid "Call paused" -msgstr "annullato" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" -msgstr "" - -#: ../gtk/main.c:1116 -#, c-format -msgid "%s proposed to start video. Do you accept ?" -msgstr "" - -#: ../gtk/main.c:1278 -msgid "Website link" -msgstr "" - -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "" - -#: ../gtk/main.c:1410 -#, c-format -msgid "%s (Default)" -msgstr "%s (Default)" - -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 -#, c-format -msgid "We are transferred to %s" -msgstr "" - -#: ../gtk/main.c:1724 -msgid "" -"No sound cards have been detected on this computer.\n" -"You won't be able to send or receive audio calls." -msgstr "" - -#: ../gtk/main.c:1833 -msgid "A free SIP video-phone" -msgstr "" - -#: ../gtk/friendlist.c:335 -msgid "Add to addressbook" -msgstr "" - -#: ../gtk/friendlist.c:509 -msgid "Presence status" -msgstr "Presenza" - -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 -msgid "Name" -msgstr "Nome" - -#: ../gtk/friendlist.c:538 -#, fuzzy -msgid "Call" -msgstr "Chiamata %s" - -#: ../gtk/friendlist.c:543 -msgid "Chat" -msgstr "" - -#: ../gtk/friendlist.c:573 -#, c-format -msgid "Search in %s directory" -msgstr "Cerca contatti nella directory %s" - -#: ../gtk/friendlist.c:730 -msgid "Invalid sip contact !" -msgstr "Contatto SIP non valido" - -#: ../gtk/friendlist.c:775 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 #, c-format msgid "Call %s" -msgstr "Chiamata %s" +msgstr "Chiama %s" -#: ../gtk/friendlist.c:776 +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 #, c-format msgid "Send text to %s" msgstr "Invia testo a %s" -#: ../gtk/friendlist.c:777 +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "Chiamate recenti (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "n/d" + +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "Annullata" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "Persa" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "Rifiutata" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "%i minuto" +msgstr[1] "%i minuti" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "%i secondo" +msgstr[1] "%i secondi" + +#: ../gtk/calllogs.c:338 +#, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" +"%s\tQualità: %s\n" +"%s\t%s\t" + +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 +msgid "Conference" +msgstr "Conferenza" + +#: ../gtk/conference.c:46 +msgid "Me" +msgstr "Me" + +#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Impossibile trovare il file pixmap %s" + +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 +msgid "log to stdout some debug information while running." +msgstr "" +"alcune informazioni di debug verranno registrate sullo stdout durante " +"l'esecuzione" + +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "mostra la versione e termina." + +#: ../gtk/main.c:140 +msgid "path to a file to write logs into." +msgstr "percorso del file di log." + +#: ../gtk/main.c:141 +msgid "Start linphone with video disabled." +msgstr "Avvia linphone con il video disabilitato." + +#: ../gtk/main.c:142 +msgid "Start only in the system tray, do not show the main interface." +msgstr "Avvia solo nel system tray, non mostrare l'interfaccia principale." + +#: ../gtk/main.c:143 +msgid "address to call right now" +msgstr "indirizzo da chiamare adesso" + +#: ../gtk/main.c:144 +msgid "" +"Specifiy a working directory (should be the base of the installation, eg: c:" +"\\Program Files\\Linphone)" +msgstr "" +"Specificare una directory di lavoro (dovrebbe essere quella di " +"installazione, es: c:\\Program Files\\Linphone)" + +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "File di configurazione" + +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Avvia l'assistente audio" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Esegui il self test e esci con 0 in caso di successo" + +#: ../gtk/main.c:1058 +#, c-format +msgid "" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" +"If you answer no, this person will be temporarily blacklisted." +msgstr "" +"%s vorrebbe aggiungerti alla sua lista dei contatti.\n" +"Vuoi aggiungerlo/a ai tuoi contatti e pemettergli di conoscere la tua " +"presenza?\n" +"Se rispondi NO questa persona verrà temporaneamente bloccata." + +#: ../gtk/main.c:1135 +#, c-format +msgid "" +"Please enter your password for username %s\n" +" at realm %s:" +msgstr "" +"Digitare la password per l'utente %s\n" +"nel dominio %s:" + +#: ../gtk/main.c:1256 +msgid "Call error" +msgstr "Errore durante la chiamata" + +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 +msgid "Call ended" +msgstr "Chiamata terminata" + +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 +msgid "Incoming call" +msgstr "Chiamata in arrivo" + +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 +msgid "Answer" +msgstr "Risposta" + +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 +msgid "Decline" +msgstr "Rifiuta" + +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "Chiamata in pausa" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "da %s" + +#: ../gtk/main.c:1342 +#, c-format +msgid "%s proposed to start video. Do you accept ?" +msgstr "%s chiede di avviare il video. Accetti ?" + +#: ../gtk/main.c:1508 +msgid "Website link" +msgstr "Collegamento al sito web" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "Un videotelefono su internet" + +#: ../gtk/main.c:1627 +#, c-format +msgid "%s (Default)" +msgstr "%s (Default)" + +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 +#, c-format +msgid "We are transferred to %s" +msgstr "Siamo trasferiti verso %s" + +#: ../gtk/main.c:1983 +msgid "" +"No sound cards have been detected on this computer.\n" +"You won't be able to send or receive audio calls." +msgstr "" +"Non è stata trovata nessuna scheda audio.\n" +"Non sarà possibile effettuare o ricevere chiamate in voce." + +#: ../gtk/main.c:2127 +msgid "A free SIP video-phone" +msgstr "Un videotelefono SIP free" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "Salve\n" + +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "Aggiungi alla rubrica" + +#: ../gtk/friendlist.c:692 +msgid "Presence status" +msgstr "Presenza" + +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 +msgid "Name" +msgstr "Nome" + +#: ../gtk/friendlist.c:722 +msgid "Call" +msgstr "Chiama" + +#: ../gtk/friendlist.c:727 +msgid "Chat" +msgstr "Chat" + +#: ../gtk/friendlist.c:757 +#, c-format +msgid "Search in %s directory" +msgstr "Cerca contatti nella directory %s" + +#: ../gtk/friendlist.c:926 +msgid "Invalid sip contact !" +msgstr "Contatto SIP non valido" + +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Modifica contatto %s" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" -msgstr "Elimina contatto %s" +msgstr "Elimina il contatto %s" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Cancella la cronologia della chat con '%s'" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" -msgstr "" +msgstr "Frequenza (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Stato" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Bitrate Min (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "IP Bitrate (kbit/s)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parametri" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Attivato" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Disattivato" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Inglese" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Francese" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Svedese" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Spagnolo" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" -msgstr "" +msgstr "Portoghese brasiliano" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polacco" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Tedesco" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Russo" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "Giapponese" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Olandese" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Ungherese" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Ceco" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" -msgstr "" +msgstr "Cinese" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" -msgstr "" +msgstr "Cinese tradizionale" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" -msgstr "" +msgstr "Norvegese" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" -msgstr "" +msgstr "Ebraico" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Serbo" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "Arabo" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "Turco" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Riavviare il software per utilizzare la nuova lingua selezionata" -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "" +msgstr "Nessuno" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" -msgstr "" +msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -370,12 +420,12 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" -"Una versione più recente è disponibile da %s.\n" +"Una versione più recente è disponibile su %s.\n" "Vuoi aprire un browser per eseguire il download ?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "Non è stato trovato alcun aggiornamento" +msgstr "Stai eseguendo la versione più aggiornata." #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" @@ -383,7 +433,7 @@ msgstr "Nome, Cognome" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "Errore di comunicazione" +msgstr "Errore di comunicazione con il server." #: ../gtk/buddylookup.c:164 msgid "Connecting..." @@ -391,552 +441,584 @@ msgstr "In connessione..." #: ../gtk/buddylookup.c:168 msgid "Connected" -msgstr "Connessione" +msgstr "Connesso" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." -msgstr "Ricezione data..." +msgstr "Ricezione dei dati..." #: ../gtk/buddylookup.c:180 #, c-format msgid "Found %i contact" msgid_plural "Found %i contacts" msgstr[0] "Trovato %i contatto" -msgstr[1] "Trovato %i contatti" +msgstr[1] "Trovati %i contatti" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"Benvenuti !\n" -"La procedura vi aiutera a configurare un account SIP." +"Benvenuto!\n" +"L'assistente vi aiuterà ad usare un indirizzo SIP per le vostre chiamate." -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "Creare un account scegliendo l'username" +msgstr "Creare un account su linphone.org" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "Ho gia un account e voglio usarlo" +msgstr "Ho già un account su linphone.org che voglio usare." -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "Ho gia un account e voglio usarlo" +msgstr "Ho già un account SIP e voglio usarlo" -#: ../gtk/setupwizard.c:84 +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Voglio specificare un URI per la configurazione remota" + +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "Inserire i dati del vostro account" + +#: ../gtk/setupwizard.c:221 +msgid "Username*" +msgstr "Nome utente*" + +#: ../gtk/setupwizard.c:222 +msgid "Password*" +msgstr "Password*" + +#: ../gtk/setupwizard.c:225 +msgid "Domain*" +msgstr "Dominio*" + +#: ../gtk/setupwizard.c:226 +msgid "Proxy" +msgstr "Proxy" + +#: ../gtk/setupwizard.c:263 msgid "Enter your linphone.org username" -msgstr "" +msgstr "Immettere il vostro nome utente su linphone.org" -#: ../gtk/setupwizard.c:91 +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 msgid "Username:" -msgstr "Manuale utente" +msgstr "Nome utente:" -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Password:" -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 -#, fuzzy -msgid "Username*" -msgstr "Username" - -#: ../gtk/setupwizard.c:121 -#, fuzzy -msgid "Password*" -msgstr "Password" - -#: ../gtk/setupwizard.c:124 -msgid "Domain*" -msgstr "" - -#: ../gtk/setupwizard.c:125 -msgid "Proxy" -msgstr "" - -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Campi obbligatori" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Manuale utente" +msgstr "Nome utente: (*)" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Password:" +msgstr "Password: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "Email: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Confermare la password: (*)" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Mantenetemi aggiornato sugli aggiornamenti di linphone" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Grazie. Il tuo account è configurato e pronto all'uso" +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "Il vostro account è stato creato, attendere." -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" +"Attivate il vostro account cin il link che vi è appena stato inviato per " +"posta elettronica.\n" +"Quindi tornare qui e premere il tasto \"Avanti\"." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "Verifica della validazione dell'account, attendere." + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Errore, account non valido, nome utente già in uso o server non " +"raggiungibile.\n" +"Tornare indietro e riprovare." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Grazie. Il tuo account è configurato e pronto all'uso" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "Assistente per la configurazione di un account SIP" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Benvenuto nel configuratore di account" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Configuratore di account" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "Configurazione SIP account" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -msgid "Error" -msgstr "" +msgid "Configure your account (step 1/1)" +msgstr "Configurare il tuo account (passo 1/1)" #: ../gtk/setupwizard.c:592 -#, fuzzy +msgid "Enter your sip username (step 1/1)" +msgstr "Introdurre il vostro nome utente SIP (passo 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Introdurre le informazioni dell'account (passo 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "Creazione dell'account in corso" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Validazione (passo 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "Controllo della validazione dell'account in corso" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Errore" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "Termina chiamata" +msgstr "Terminando" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "Chiamata %s" +msgstr "Chiamata #%i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" -msgstr "" +msgstr "Trasferimento per chiamare #%i con %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Non usato" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Filtro ICE" +msgid "ICE not activated" +msgstr "ICE non attivato" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "ICE fallito" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "ICE in corso" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Rediretto verso %s..." +msgid "Going through one or more NATs" +msgstr "Attraversando uno o più NAT" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "Diretto" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Attraverso un relay server" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP non attivo" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP in corso" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnP non disponibile" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP in esecuzione" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP ha fallito" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Diretto o attraverso un server" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"download: %f\n" +"upload: %f (kbit/s)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f fps" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f secondi" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" -msgstr "" +msgstr "Riagganciare" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Linguaggio" +msgstr "Chiamando..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Chimata in entrata" +msgstr "Chiamata in ingresso" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "" +msgstr "bene" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "" +msgstr "media" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "" +msgstr "ridotto" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "" +msgstr "molto poco" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "" +msgstr "troppo brutto" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "" +msgstr "non disponibile" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" -msgstr "" +msgstr "Trasmissione sicura con SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "Trasmissione sicura con DTLS" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "Trasmissione sicura con ZRTP - [auth token: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "Marcato con non verificato" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "Marcato come verificato" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" -msgstr "" +msgstr "In conferenza" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "In chiamata con" +msgstr "Chiamata in corso" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "Termina chiamata" +msgstr "Chiamata sospesa" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Chiamata terminata." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "Trasferimento in corso" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "" +msgstr "Trasferimento completato." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Chiamata rifiutata" +msgstr "Trasferimento fallito." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "" +msgstr "Riprendere" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" -msgstr "" +msgstr "Pausa" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Registrare in\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Sospeso)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Prego inserire le proprie credenziali di accesso per %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "prelevando da %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Il trasferimento della configurazione remota da %s è fallito." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Non è stata riconosciuta nessuna voce" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Troppo basso" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "Bene" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Troppo forte" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Hai sentito tre segnali ?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Le preferenze sui suoni non sono state trovate" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Non è possibile eseguire il controllo dell'audio di sistema" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Benvenuto!\n" +"L'assistente ti aiuterà a configurare i settaggi audio di Linphone" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Dispositivo di acquisizione" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "Volume di registrazione" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Nessuna voce" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Preferenze per l'audio di sistema" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Dispositivo di riproduzione" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Riproduci tre segnali" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Premere il pulsante registrazione e parlare" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Ascoltare la voce registrata" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Registra" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Riproduci" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Ora avviamo Linphone" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Assistente Audio" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Assistente Audio" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Calibrazione del guadagano del microfono" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Calibrazione del volume di riproduzione" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Registra e Riproduci" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Chiamata terminata." +msgid "All users" +msgstr "Tutti gli utenti" #: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Invia" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etichetta" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "In chiamata" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Durata" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Self-view abilitato" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone debug window" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "Configuratore di account" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "Indirizzo sip o numero." - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Aggiungi" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Edita" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Aggiungi nuovo contatto dalla directory %s" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "Trovato %i contatto" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "In chiamata" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Identità corrente" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Username" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Password" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Connessione Internet:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Login Automatico" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Credenziali di accesso" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Benvenuto !" - -#: ../gtk/main.ui.h:57 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:58 -#, fuzzy msgid "Online users" -msgstr "" -"Tutti gli utenti\n" -"Utenti Online" +msgstr "Utenti in linea" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 -#, fuzzy +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" -msgstr "" -"ADSL\n" -"Fibra Ottica" +msgstr "Fibra ottica" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "Default" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" -msgstr "" +msgstr "Cancellare" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Options" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "Imposta l' URI di configurazione" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Avvia sempre il video" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Self-view abilitato" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Help" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Mostra la finestra di debug" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Homepage" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Check _Updates" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Assistente per l'account" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "Indirizzo sip o numero." + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Inizia una nuova chiamata" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Contatti" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Ricerca" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Aggiungi contatti dalla directory" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Aggiungi un contatto" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Chiamate recenti" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Identità corrente" #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "Info Linphone" +msgid "About Linphone" +msgstr "Su Linphone" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 -#, fuzzy msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "Un internet video telefono basato sullo standard SIP (rfc3261)" +msgstr "Un videotelefono con protocollo standard SIP (RFC 3261) " #: ../gtk/about.ui.h:5 msgid "" @@ -951,7 +1033,21 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"it: Fabrizio Carrai\n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -975,20 +1071,19 @@ msgstr "Linphone debug window" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "" +msgstr "Vai in fondo" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Linphone - Autenticazione richiesta" +msgstr "Linphone - E' richiesta l'autenticazione" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "Prego inserire la password di dominio" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "Identificativo utente" #: ../gtk/call_logs.ui.h:1 msgid "Call history" @@ -996,12 +1091,11 @@ msgstr "Cronologia" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" -msgstr "" +msgstr "Pulisci tutto" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "Chiamata %s" +msgstr "Richiamata" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" @@ -1013,7 +1107,7 @@ msgstr "Identità SIP" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" -msgstr "" +msgstr "Simile a sip:@" #: ../gtk/sip_account.ui.h:4 msgid "sip:" @@ -1025,304 +1119,414 @@ msgstr "Indirizzo sip proxy:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" -msgstr "" +msgstr "Simile a sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Rotta (opzionale)" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Durata registrazione (sec)" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Parametri del contatto (opzionali)" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" -msgstr "" +msgid "AVPF regular RTCP interval (sec):" +msgstr "AVPF regular RTCP interval (sec):" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Rotta (opzionale)" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Trasporto" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Registro" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Pubblica stato della presenza" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Abilita AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Configurazione SIP account" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "anonimo" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "default scheda audio" -#: ../gtk/parameters.ui.h:2 -#, fuzzy +#: ../gtk/parameters.ui.h:5 msgid "a sound card" -msgstr "una scheda audio\n" +msgstr "una scheda audio" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "default videocamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "" -"Audio codecs\n" -"Video codecs" - -#: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "" -"Audio codecs\n" -"Video codecs" - #: ../gtk/parameters.ui.h:8 -#, fuzzy +msgid "Audio codecs" +msgstr "Codificatori audio" + +#: ../gtk/parameters.ui.h:9 +msgid "Video codecs" +msgstr "Codificatori video" + +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 -#, fuzzy +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" -msgstr "SIP (UDP)" +msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 -#, fuzzy +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" -msgstr "SIP (UDP)" +msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "default" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "high-fps" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "custom" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "Preferenze" -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Imposta Maximum Transmission Unit:" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Invia DTMF come SIP info" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Usa IPv6 invece che IPv4" - -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Transporto" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "" - -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "Audio RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Connessione diretta a internet" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Dietro NAT / Firewall (IP del gateway)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Indirizzo ip pubblico:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Dietro NAT / Firewall (utilizza STUN)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Dietro NAT / Firewall (utilizza STUN)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "Stun server:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT and Firewall" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Impostazioni di rete" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Suoneria:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Dispositivo ALSA (optional):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Dispositivo microfono:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Dispositivo squillo:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Dispositivo uscita audio:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Attiva cancellazione eco" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Dispositivo Video:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Risoluzione video preferita" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Impostazioni multimediali" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "questa sezione definisce il tuo indirizzo SIP se non hai account attivi" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "Nome visualizzato (es: Mario Rossi):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Username" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "Il tuo indirizzo sip:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Identità di default" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" -msgstr "" +msgstr "Wizard" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Aggiungi" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Edita" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Rimuovi" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Account proxy" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Cancella tutte le password" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Privacy" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "Rispondi automaticamente alla chiamata in arrivo" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "Ritardo prima della risposta (ms)" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "Risposta automatica" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Gestici SIP Account" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Attivato" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Suoneria:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Disattivato" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Dispositivo ALSA (optional):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Codecs" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Dispositivo microfono:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Dispositivo squillo:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Dispositivo uscita audio:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Attiva cancellazione eco" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Audio" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Dispositivo Video:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "Risoluzione video preferita:" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Modalità video in uscita:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Mostra il preview della videocamera" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "Preconfigurazione del video:" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "Frame rate video preferito:" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 sta per illimitato" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Velocità massima in upload Kbit/sec:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Velocita massima in Dowload Kbit/sec" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" -msgstr "" +msgstr "Abilita il controllo adattivo del rate" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" +"Il controllo adattivo del rate è una tecnica per la stima dinamica della " +"banda disponibile durante una chiamata" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Gestione banda" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Impostazioni multimediali" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Imposta Maximum Transmission Unit:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Invia DTMF come SIP info" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "Permetti IPv6" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Transporto" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "Porta SIP/UDP" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Casuale" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "Porta SIP/TCP" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "Audio RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Fissa" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Video RTP/UDP" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Tipo di cifratura" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "La cifratura è obbligatoria" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tunnel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "Campi DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Protocollo di rete e porte" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Connessione diretta a internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Dietro ad un NAT / Firewall (specificare IP del gateway)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Dietro NAT / Firewall (utilizza STUN)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "Dietro ad un NAT / Firewall (usa ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "Dietro ad un NAT / Fiewall (usa uPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Indirizzo IP pubblico:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Server STUN:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT and Firewall" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Impostazioni di rete" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Attivato" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Disattivato" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "Codificatori audio" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "Codificatori video" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Codec" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Linguaggio" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" -msgstr "" +msgstr "Mostra la configurazione avanzata" -#: ../gtk/parameters.ui.h:67 -#, fuzzy +#: ../gtk/parameters.ui.h:87 msgid "Level" -msgstr "Linguaggio" +msgstr "Livello" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Interfaccia utente" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Indirizzo del server:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Metodo di autenticazione" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "Configurazione dell' account LDAP" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Fatto" @@ -1338,225 +1542,337 @@ msgstr "Aggiungi alla mia lista" msgid "Search somebody" msgstr "Cerca" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "Prego attendere" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Preferenze" +msgid "DSCP settings" +msgstr "Configurazione DSCP" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" -msgstr "" +msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "campionatore di frequenza" +msgstr "Stream audio RTP" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "Video RTP/UDP" +msgstr "Stream video RTP" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "Valore DSCP (in esadecimale)" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Chiamata %s" +msgstr "Statistiche della chiamata" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "" -"Audio codecs\n" -"Video codecs" +msgstr "Codec audio" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "" -"Audio codecs\n" -"Video codecs" +msgstr "Codec video" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Banda IP impiegata per l'audio" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" -msgstr "" +msgid "Audio Media connectivity" +msgstr "Supporto audio" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Banda IP impiegata per il video" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "Supporto video" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Tempo di andata/ritorno" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Risoluzione video ricevuta" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Risoluzione video trasmessa" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "Profilo RTP" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Contact informazioni" +msgstr "Statistiche della chiamata e informazioni" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Configurazione SIP account" +msgstr "Configurare il tunnel VoIP" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Host" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "Porta" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Configurazione del tunnel" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Username" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Password" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "Configurazione del proxy http (opzionale)" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "annullato" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "Configurazione LDAP" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "comletato" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "Usa connessione TLS" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "mancante" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Not ancora disponibile" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "Connessione" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "Bind DN" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Authname" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Dominio" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "Oggetto di base" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "Filtro (%s per il nome):" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "Attributo Nome:" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "Attributo SIP address" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "Attributo da cercare:" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "Ricerca" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "Tempo limite per la ricerca:" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "Massimo numero di risultati:" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "Segui gli Aliases" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "Varie" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "ANONYMOUS" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "SEMPLICE" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "DIGEST-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "Specificare un URI per la configurazione remota" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s at %s\n" -"Da: %s\n" -"Verso: %s\n" -"Stato: %s\n" -"Durata: %i mn %i sec\n" +"Questo modulo permette di impostare un indirizzo http o https da cui " +"prelevare la configurazione all'avvio.\n" +"Di seguito inserire o modificare l' URI della configurazione. Dopo aver " +"selezionato OK Linphone verrà automaticamente riavvato per leggere ed usare " +"la nuova configurazione." -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Chiamata in uscita" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Configurando..." -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "Caricamento della configurazione dal server, attendere..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Invia" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Nome del chiamato" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Fine della conferenza" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Registra questa chiamata su un file audio" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Video" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Silenzia" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Trasferimento" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "In chiamata" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Durata" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Giudizio della qualità della chiamata" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Connessione Internet:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Login Automatico" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Credenziali di accesso" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Benvenuto!" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Pronto" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Ricerca numero destinazione..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Configurando" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Impossibile risolvere il numero." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Errore nel formato del contatto sip. Usualmente un indirizzo appare sip:" -"user@domain" - -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "In connessione" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "chiamata fallita" +msgstr "Impossibile chiamare" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "" +msgstr "Spiacenti, è stato raggiunto il massimo numero di chiamate simultanee" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "ti sta conttatando." +msgstr "ti sta contattando" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." -msgstr "" +msgstr "e ha richiesto la risposta automatica" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." -msgstr "" +msgstr "Modificando i parametri di chiamata..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Connessione" -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "annullato" +msgstr "Chiamata annullata" -#: ../coreapi/linphonecore.c:3102 -#, fuzzy +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "chiamata fallita" +msgstr "Impossibile sospendere la chiamata" -#: ../coreapi/linphonecore.c:3107 -#, fuzzy +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "Mostra chiamata corrente" +msgstr "Sospensione della chiamata in corso..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Il tuo computer appare utlizzare il driver ALSA.\n" -"Questa è la scelta migliore. Tuttavia il modulo di emulazione pcm oss\n" -"è assente e linphone lo richede. Prego eseguire\n" -"'modprobe snd-pcm-oss' da utente root per caricarlo." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Il tuo computer appare utlizzare il driver ALSA.\n" -"Questa è la scelta migliore. Tuttavia il modulo di emulazione mixer oss\n" -"è assente e linphone lo richede. Prego eseguire\n" -"'modprobe snd-mixer-oss' da utente root per caricarlo." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "Ricerca Stun in progresso ..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "Raccolta dei candidati ICE locali in corso..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1603,10 +1919,14 @@ msgid "Pending" msgstr "Pendente" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Bug-sconosciuto" +msgid "Vacation" +msgstr "Assente" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Stato sconosciuto" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1614,7 +1934,7 @@ msgstr "" "L'indirizzo sip proxy utilizzato è invalido, deve iniziare con \"sip:\" " "seguito dall' hostaname." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1622,524 +1942,186 @@ msgstr "" "L'identità sip utilizza è invalida.\n" "Dovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Ricerca numero destinazione..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Impossibile risolvere il numero." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "impossibile login come %s" -#: ../coreapi/callbacks.c:276 -msgid "Remote ringing." -msgstr "" - -#: ../coreapi/callbacks.c:296 -msgid "Remote ringing..." -msgstr "" - -#: ../coreapi/callbacks.c:307 -msgid "Early media." -msgstr "" - -#: ../coreapi/callbacks.c:352 +#: ../coreapi/proxy.c:1494 #, fuzzy, c-format -msgid "Call with %s is paused." -msgstr "Chat con %s" +msgid "Refreshing on %s..." +msgstr "prelevando da %s" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "Il chiamato sta squillando." + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "Il chiamato sta squillando..." + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "Early media." + +#: ../coreapi/callbacks.c:548 +#, c-format +msgid "Call with %s is paused." +msgstr "La chiamata con %s è stata sospesa." + +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." -msgstr "" +msgstr "Chiamata con %s - in attesa." -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Chiamata terminata" +msgstr "Prosecuzione della chiamata." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." -msgstr "" +msgstr "Risposta da %s." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "" +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "Incompatibile, controllare i codecs o i parametri della sicurezza..." -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Parametri di comunicazione incompatibili." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "" +msgstr "La comunicazione è stata ripresa." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "L'interlocutore ci ha messi in attesa." -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "" +msgstr "Aggiornamento della chiamata dalla parte remota." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Chiamata terminata." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Utente occupato" -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Utente non disponibile" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "L'utente non vuole essere disturbato" -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:544 -#, fuzzy -msgid "No response." -msgstr "timeout no risposta" +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "Richiesta scaduta" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 -#, fuzzy +#: ../coreapi/callbacks.c:875 msgid "Redirected" -msgstr "Rediretto verso %s..." +msgstr "Trasferito" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Chiamata rifiutata" +msgstr "Chiamata non riuscita." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registrazione su %s attiva" -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Unregistrazione su %s" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrazione su %s fallita: %s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Linphone - Autenticazione richiesta" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Servizio non disponibile, nuovo tentativo in corso" -#: ../coreapi/linphonecall.c:2124 +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "Il codice di autenticazione è %s" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "I parametri della chiamata sono stati modificati con successo." + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." -msgstr[0] "" -msgstr[1] "" - -#~ msgid "Chat with %s" -#~ msgstr "Chat con %s" - -#~ msgid "Please choose a username:" -#~ msgstr "Prego scegliere un username" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Controllo se '%s' è disponibile..." - -#~ msgid "Please wait..." -#~ msgstr "Prego attendere ..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "Spiacenti, questo usernsame è gia utilizzato. Prego riprovare" - -#~ msgid "Ok !" -#~ msgstr "Ok !" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Errore di comunicazione, prego riprovare." - -#~ msgid "Choosing a username" -#~ msgstr "Scegli un username" - -#~ msgid "Verifying" -#~ msgstr "Verifica" - -#~ msgid "Confirmation" -#~ msgstr "Informazioni" - -#~ msgid "Creating your account" -#~ msgstr "Creazione account" - -#~ msgid "Now ready !" -#~ msgstr "Pronto !" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "In connessione" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Attivato" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "Inserisci username, numero o indirizzo sip" - -#~ msgid "in" -#~ msgstr "in" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Registrati a FONICS\n" -#~ "virtual network !" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - Autenticazione richiesta" - -#~ msgid "Unmute" -#~ msgstr "" -#~ "Attiva\n" -#~ "microfono" - -#~ msgid "Contact list" -#~ msgstr "Lista contatti" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Audio & Video" - -#~ msgid "Audio only" -#~ msgstr "Solo Audio" - -#~ msgid "Duration:" -#~ msgstr "Durata:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Cronologia" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "Register at startup" -#~ msgstr "Registra all'avvio" - -#~ msgid "Ports" -#~ msgstr "Porte" - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw encoder" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw decoder" - -#~ msgid "Alsa sound source" -#~ msgstr "Alsa sound sorgente" - -#~ msgid "Alsa sound output" -#~ msgstr "Alsa sound riproduzione" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "Sound capture filter for MacOS X Audio Queue Service" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "Sound playback filter for MacOS X Audio Queue Service" - -#~ msgid "DTMF generator" -#~ msgstr "Generatore DTMF" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "GSM full-rate codec" - -#~ msgid "The GSM codec" -#~ msgstr "GSM codec" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "Sound capture filter for MacOS X Audio Queue Service" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "Sound playback filter for MacOS X Audio Queue Service" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Un filtro per fare conferenze" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Raw files and wav reader" - -#~ msgid "Wav file recorder" -#~ msgstr "Registratore Wav file" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "Un filtro che invia alcuni inputs in un unico output" - -#~ msgid "RTP output filter" -#~ msgstr "RTP output filter" - -#~ msgid "RTP input filter" -#~ msgstr "RTP imput filter" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "The free and wonderful speex codec" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "Un filtro che controlla e misura il volume" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "Un video4linux filtro per inviare immagini" - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "un filtro per catturare immagini da video4linux2 videocamere" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "Un filtro che invia una immagine statica" - -#~ msgid "A pixel format converter" -#~ msgstr "Un convertitore di formati pixel" - -#~ msgid "A video size converter" -#~ msgstr "Un convertitore dimesione video " - -#~ msgid "a small video size converter" -#~ msgstr "un piccolo convertitore dimesione video" - -#, fuzzy -#~ msgid "Echo canceller using speex library" -#~ msgstr "Cancellazione eco utilizzando la libreria speex" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "Un filtro che legge gli inout e copia su multipli output." - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "Theora video encoder da xiph.org" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "Open-source and royalty-free 'theora' video codec da xiph.org" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Theora video decoder from xiph.org" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw encoder" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw decoder" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "Un H.263 decoder che utilizza le librerie ffmpeg" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "Un MPEG4 decoder che utilizza le librerie ffmpeg" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "Un RTP/JPEG decoder che utilizza le librerie ffmpeg" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "Un MJPEG decoder che utilizza le librerie ffmpeg" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "Un snow decoder che utilizza le librerie ffmpeg" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "Un H.263 encoder che utilizza le librerie ffmpeg" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "" -#~ "Un H.263 encoder che utilizza le librerie ffmpeg. Compliante con RFC2190 " -#~ "spec." - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "Un MPEG4 encoder che utilizza le librerie ffmpeg" - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "Un snow encoder che utilizza le librerie ffmpeg" - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "Un RTP/JPEG decoder che utilizza le librerie ffmpeg" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "" -#~ "Un H.263 encoder che utilizza le librerie ffmpeg. Compliante con RFC2190 " -#~ "spec." - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "Un MJPEG encoder che utilizza le librerie ffmpeg" - -#, fuzzy -#~ msgid "A SDL-based video display" -#~ msgstr "Un generico video display" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "Un filtro video4windows per lo streaming delle immagini." - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "Un filtro (vfw.h) per catturare immagini." - -#~ msgid "Parametric sound equalizer." -#~ msgstr "Equalizzatore di suono." - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "Un webcam grabber basato su directshow." - -#, fuzzy -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "Un filtro che controlla e misura il volume" - -#, fuzzy -#~ msgid "Inter ticker communication filter." -#~ msgstr "Errore di comunicazione" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "Sound capture filter for MacOS X Audio Queue Service" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "Sound playback filter for MacOS X Audio Queue Service" - -#, fuzzy -#~ msgid "Sound capture filter for Android" -#~ msgstr "Filtro per la cattura audio per i driver OSS" - -#, fuzzy -#~ msgid "Sound playback filter for Android" -#~ msgstr "Filtro per la riproduzione audio per i driver OSS" - -#, fuzzy -#~ msgid "A filter that captures Android video." -#~ msgstr "Un filtro che controlla e misura il volume" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "La tua macchina sembra connessa ad una rete IPv6. Di default linphone " -#~ "utilizza IPv4. Prego aggiorna la tua configurazione se vuoi usare IPv6" - -#~ msgid "Sound capture filter for MacOS X Core Audio drivers" -#~ msgstr "Sound capture filter for MacOS X Core Audio drivers" - -#~ msgid "Sound playback filter for MacOS X Core Audio drivers" -#~ msgstr "Sound playback filter for MacOS X Core Audio drivers" - -#~ msgid "Incoming call from %s" -#~ msgstr "Chiamata proveniente da %s" - -#~ msgid "Assistant" -#~ msgstr "Configuratore" - -#~ msgid "Start call" -#~ msgstr "Inizia chiamata" - -#~ msgid "_Modes" -#~ msgstr "_Modi" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "Creato da Simon Morlat\n" - -#~ msgid "Accept" -#~ msgstr "Accetta" - -#~ msgid "Incoming call from" -#~ msgstr "Chiama in entrata da" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone - Chiamata in entrata" - -#~ msgid "default soundcard\n" -#~ msgstr "default scheda audio\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "L'utente remoto sembra disconesso, la chiamata verrà terminata" - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Spiacenti, le chiamate multiple non sono supportate" - -#~ msgid "Could not reach destination." -#~ msgstr "Non posso raggiungere la destinazione" - -#~ msgid "Request Cancelled." -#~ msgstr "Richiesta cancellata" - -#~ msgid "Bad request" -#~ msgstr "Richiesta errata" - -#~ msgid "User cannot be found at given address." -#~ msgstr "L'utente non trovato." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "L'utente remoto non supporta alcun code proposto." - -#~ msgid "Timeout." -#~ msgstr "Timeout." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Utente remoto trovato ma ha rifiutato la connessione." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "L'utente non è raggiungibile ma ti ha invitato\n" -#~ "per contattarlo usare l'indirizzo alternativo:" - -#~ msgid "Digits" -#~ msgstr "Caratteri" - -#~ msgid "Main view" -#~ msgstr "Vista principale" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Non è stato fornito un indirizzo nat/firewall!" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Indirizzo NAT invalido '%s' : %s" - -#~ msgid "Gone" -#~ msgstr "Uscita" - -#~ msgid "Waiting for Approval" -#~ msgstr "In attesa di approvazione" - -#~ msgid "Be Right Back" -#~ msgstr "Torno subito" - -#~ msgid "On The Phone" -#~ msgstr "Al telefono" - -#~ msgid "Out To Lunch" -#~ msgstr "Fuori per pranzo" - -#~ msgid "Closed" -#~ msgstr "Chiuso" - -#~ msgid "Unknown" -#~ msgstr "Sconosciuto" - -#~ msgid "SIP address" -#~ msgstr "Indirizzi SIP" - -#~ msgid "Bresilian" -#~ msgstr "Brasiliano" +msgstr[0] "%i chiamata persa." +msgstr[1] "%i chiamate perse." + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "annulata" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "completata" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "persa" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "sconosciuto" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s a %s\n" +"Da: %s\n" +"A: %s\n" +"Stato: %s\n" +"Durata: %i min %i sec\n" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "chiamata in uscita" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "Impossibile riprodurre %s." diff --git a/po/ja.po b/po/ja.po index c2ed8c87d..c0d7b5838 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,368 +1,408 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# 山口善也 , 2002. -# -#, fuzzy +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Alexander, 2014 +# Alexander, 2014-2015 msgid "" msgstr "" -"Project-Id-Version: linphone 0.10\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2003-01-21 00:05+9000\n" -"Last-Translator: YAMAGUCHI YOSHIYA \n" -"Language-Team: \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Japanese (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/ja/)\n" +"Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "%s を呼び出し中" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "%s に文章を送信" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "通話時間 (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "n/a" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "通話はキャンセルされました。" +msgstr "中断" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "" +msgstr "失敗" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "ライン入力" +msgstr "辞退" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i 分" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i 秒" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" +"%s品質: %s\n" +"%s⇥%s⇥" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" -msgstr "" +msgid "%s\t%s" +msgstr "%s⇥%s" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" -msgstr "" +msgstr "会議" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" -msgstr "" +msgstr "自分" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." +msgstr "実行中にいくつかのデバッグ情報をstdoutに送信します。" + +#: ../gtk/main.c:139 +msgid "display version and exit." msgstr "" -#: ../gtk/main.c:96 +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "" +msgstr "ログを書き込むファイルへのパス。" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "ビデオを無効にしてLinphoneを開始します。" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "" +msgstr "主なインターフェイスを表示しないでシステムトレイに移動します。" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "" +msgstr "今すぐに呼び出す" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" +"作業ディレクトリをSpecifiy (インストールした時のベースである必要があります。" +"例:c:\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "設定ファイル" + +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "オーディオアシスタントを実行" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "通話はキャンセルされました。" +msgstr "呼出エラー" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 -#, fuzzy +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "通話は拒否されました。" +msgstr "呼出終了" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" -msgstr "" +msgstr "着信" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" -msgstr "" +msgstr "応答" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "ライン入力" +msgstr "拒否" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "通話はキャンセルされました。" +msgstr "呼び出しの一時停止" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "" +msgid "by %s" +msgstr "%s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" +msgstr "ウェブサイトリンク" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "" - -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "" +msgstr "%s (デフォルト)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" -msgstr "" +msgstr "%s に転送しました" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" +msgstr "無料 SIP ビデオ-電話" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" msgstr "" -#: ../gtk/friendlist.c:335 -#, fuzzy +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" -msgstr "電話帳" +msgstr "電話帳に追加する" -#: ../gtk/friendlist.c:509 -#, fuzzy +#: ../gtk/friendlist.c:692 msgid "Presence status" -msgstr "状態" +msgstr "状態のステータス" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名前" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "通話はキャンセルされました。" +msgstr "通話" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "" +msgstr "チャット" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" -msgstr "" +msgstr "%s のディレクトリ内を検索" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" -msgstr "" +msgstr "無効なSIP接続です!" -#: ../gtk/friendlist.c:775 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format msgid "Edit contact '%s'" -msgstr "(接続するための情報がありません!)" +msgstr "'%s' の連絡先を編集" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" -msgstr "" +msgstr "'%s' の連絡先を削除" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "'%s' のチャット履歴を削除" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" -msgstr "" +msgstr "レート (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "状態" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "最低限のビットレート (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "IP ビットレート (kbit/s)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "パラメーター" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "使用する" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "使用しない" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" -msgstr "" +msgstr "アカウント" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" -msgstr "" +msgstr "English" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" -msgstr "" +msgstr "Svenska" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" -msgstr "" +msgstr "Italiano" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" -msgstr "" +msgstr "Español" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" -msgstr "" +msgstr "Português do Brasil" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" -msgstr "" +msgstr "Polski" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" -msgstr "" +msgstr "Deutsch" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" -msgstr "" +msgstr "Pусский" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" -msgstr "" +msgstr "Nederlands" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" -msgstr "" +msgstr "繁体中文" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" -msgstr "" +msgstr "Norsk" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" +msgstr "עברית" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Cрпски" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." -msgstr "" +msgstr "言語の選択を有効にするには、 Linphoneを再起動する必要があります。" -#: ../gtk/propertybox.c:912 -#, fuzzy +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "ありません。" +msgstr "なし" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" +msgstr "SRTP" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -370,572 +410,600 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" +"%s よりも新しいバージョンが利用可能です。\n" +"ダウンロードするために、ブラウザを開きますか?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "" +msgstr "最新版です。" #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" -msgstr "" +msgstr "名前、名字" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "" +msgstr "サーバーとの通信エラーが発生しました。" #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "コネクション" +msgstr "接続中..." #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "接続しました。" +msgstr "接続" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." -msgstr "" +msgstr "データを受信中…" #: ../gtk/buddylookup.c:180 #, c-format msgid "Found %i contact" msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i 件発見" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" +"ようこそ!\n" +"あなたの通話のためのSIPアカウント設定をお手伝いします。" -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "" +msgstr "linphone.orgのアカウントを作成" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "" +msgstr "linphone.orgのアカウントを持っているのでそれを使います" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" +msgstr "SIPアカウントを持っているのでそれを使います" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "ユーザーマニュアル" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "パスワード" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "ユーザーマニュアル" +msgstr "ユーザー名*" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "パスワード" +msgstr "パスワード*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" -msgstr "" +msgstr "ドメイン*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" -msgstr "" +msgstr "プロキシ*" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "linphone.orgで取得したユーザー名を入力" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "ユーザー名:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "パスワード:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) 必須" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "ユーザーマニュアル" +msgstr "ユーザー名: (*)" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "パスワード" +msgstr "パスワード: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "メールアドレス: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" +msgstr "パスワードを再入力: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "アップデートでLinphoneを常に最新にする" + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" +"送信されたメールの本文内にあるリンクをクリックしてアカウントを有効にしてくだ" +"さい。\n" +"その後こちらへ戻って「次へ」を押してください。" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "" +"ありがとう。あなたのアカウントは無事に設定され、使用する準備ができました。" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "SIPアカウント設定アシスタント" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:559 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:565 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "アカウント設定アシスタントへようこそ" #: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" +msgid "Account setup assistant" +msgstr "アカウント設定アシスタント" #: ../gtk/setupwizard.c:588 -msgid "Error" -msgstr "" +msgid "Configure your account (step 1/1)" +msgstr "アカウントを設定します (1/1)" #: ../gtk/setupwizard.c:592 -msgid "Terminating" +msgid "Enter your sip username (step 1/1)" +msgstr "SIPのユーザー名を入力してください (1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "アカウント情報を入力してください (1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format -msgid "Call #%i" -msgstr "通話はキャンセルされました。" +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "検証します (2/2)" -#: ../gtk/incall_view.c:150 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "エラー" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "終了" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "呼び出し #%i" + +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "使用しない" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "通話はキャンセルされました。" +msgid "ICE not activated" +msgstr "ICE 未認証" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "ICE 失敗" #: ../gtk/incall_view.c:225 +msgid "ICE in progress" +msgstr "ICE 進行中" + +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:227 -msgid "Direct" -msgstr "" - #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "直接" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" +msgstr "間接的にリレーサーバーを使う" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnPは作動しておりません" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnPを使用中" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnPは利用できません" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP作動中" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP失敗" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"ダウンロード: %f\n" +"アップロード: %f (kbit/s)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f fps" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f 秒" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "接続中" +msgstr "かけています…" -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "接続中" +msgstr "着信" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "" +msgstr "良い" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "" +msgstr "アベレージ" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "" +msgstr "悪い" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "" +msgstr "非常にプアな" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "" +msgstr "非常にバッドな" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "" +msgstr "利用できません" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" +msgstr "SRTPのセキュリティ" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "ZRTP によるセキュリティ - [auth token: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "セット未検証" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "セット検証済" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" -msgstr "" +msgstr "会議で" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "接続中" +msgstr "呼び出し中" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "接続中" +msgstr "呼び出し停止" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 -#, fuzzy +#: ../gtk/incall_view.c:834 msgid "Call ended." -msgstr "通話は拒否されました。" +msgstr "呼び出し終了" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "進行中の転送" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "" +msgstr "転送完了。" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "通話はキャンセルされました。" +msgstr "転送失敗。" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "" +msgstr "レジューム" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" +msgstr "一時停止" + +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(停止中)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "音声が検出できません" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "小さい" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "丁度よい" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "大きい" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "3回のビープ音が聞こえましたか?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "音声の設定が見つかりません" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "音声制御システムを起動できません" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "キャプチャーデバイス" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "録音音量" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "音声なし" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "システムサウンド設定" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "3回分のビープ音を再生する" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "録音した音声を聞く" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "録音" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "再生" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Linphoneをはじめる" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "音声アシスタント" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "音声アシスタント" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "マイクのゲイン測定" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "スピーカーの音量測定" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "録音して再生" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "通話は拒否されました。" +msgid "All users" +msgstr "すべての利用者" #: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "サウンド" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "接続中" - -#: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "情報" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "使用する" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "レジストラサーバーのSIPアドレス" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "追加する" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "コーデックの情報" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "(接続するための情報がありません!)" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "接続中" - -#: ../gtk/main.ui.h:50 -#, fuzzy -msgid "My current identity:" -msgstr "個人情報" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "ユーザーマニュアル" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "パスワード" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "コーデックの情報" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "接続中" - -#: ../gtk/main.ui.h:57 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:58 -#, fuzzy msgid "Online users" -msgstr "ライン入力" +msgstr "オンラインの利用者" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" -msgstr "" +msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:61 -#, fuzzy +#: ../gtk/main.ui.h:5 msgid "Default" -msgstr "個人情報" +msgstr "デフォルト" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" +msgstr "削除" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_オプション" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "いつでもビデオをスタートする" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "セルフビューを有効にする" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_ヘルプ" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "デバッグウインドウを見る" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_ホームページ" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "チェック _アップデート" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "アカウントのアシスタント" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIPアドレスもしくは電話番号:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "検索" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "連絡相手に追加する" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" msgstr "" #: ../gtk/about.ui.h:1 -#, fuzzy -msgid "About linphone" -msgstr "Linphone" +msgid "About Linphone" +msgstr "Linphoneについて" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "" +"インターネットによる動画送信には標準的なSIPプロトコル (rfc3261) を使用してい" +"ます。" #: ../gtk/about.ui.h:5 msgid "" @@ -950,12 +1018,24 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "アドレス" +msgstr "SIPアドレス" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" @@ -966,38 +1046,36 @@ msgid "Allow this contact to see my presence status" msgstr "" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "コーデックの情報" +msgstr "" #: ../gtk/log.ui.h:1 msgid "Linphone debug window" -msgstr "" +msgstr "Linphoneデバッグウインドウ" #: ../gtk/log.ui.h:2 msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "コーデックの情報" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "ユーザーID" #: ../gtk/call_logs.ui.h:1 msgid "Call history" -msgstr "" +msgstr "呼出履歴" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" -msgstr "" +msgstr "すべて消去する" #: ../gtk/call_logs.ui.h:3 msgid "Call back" @@ -1008,9 +1086,8 @@ msgid "Linphone - Configure a SIP account" msgstr "" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "個人情報" +msgstr "" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" @@ -1021,354 +1098,438 @@ msgid "sip:" msgstr "sip:" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "Sipアドレス:" +msgstr "SIP プロキシ:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" +msgid "Registration duration (sec):" msgstr "" #: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "登録しました。" +msgid "Contact params (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "コーデックの情報" +msgid "Route (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "転送" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "登録" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "パブリッシュ情報" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "AVPFを有効にする" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "anonymous" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "" -#: ../gtk/parameters.ui.h:2 -msgid "a sound card" -msgstr "" - -#: ../gtk/parameters.ui.h:3 -msgid "default camera" -msgstr "" - -#: ../gtk/parameters.ui.h:4 -msgid "CIF" -msgstr "" - #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "オーディオコーデックのプロパティー" +msgid "a sound card" +msgstr "サウンドカード" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "オーディオコーデックのプロパティー" +msgid "default camera" +msgstr "デフォルトのカメラ" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" -msgstr "" +msgid "Audio codecs" +msgstr "オーディオのコーデック" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" -msgstr "" +msgid "Video codecs" +msgstr "ビデオのコーデック" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" -msgstr "" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "" +msgid "SIP (UDP)" +msgstr "SIP (UDP)" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "" +msgid "SIP (TCP)" +msgstr "SIP (TCP)" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "" +msgid "SIP (TLS)" +msgstr "SIP (TLS)" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "接続中" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "設定" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "Sipアドレス:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "使用するサウンドデバイス" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "接続中" - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "ネットワーク" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "録音する音源" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "使用するサウンドデバイス" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "使用するサウンドデバイス" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "使用するサウンドデバイス" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "接続中" - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "使用するサウンドデバイス" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "接続中" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" -msgstr "" +msgstr "あなたの表示名 (例: John Doe):" -#: ../gtk/parameters.ui.h:44 -#, fuzzy +#: ../gtk/parameters.ui.h:20 msgid "Your username:" -msgstr "ユーザーマニュアル" +msgstr "あなたのユーザー名:" -#: ../gtk/parameters.ui.h:45 -#, fuzzy +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "あなたのSIPアドレス" - -#: ../gtk/parameters.ui.h:46 -#, fuzzy -msgid "Default identity" -msgstr "個人情報" - -#: ../gtk/parameters.ui.h:47 -msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:22 +msgid "Default identity" +msgstr "" + +#: ../gtk/parameters.ui.h:23 +msgid "Wizard" +msgstr "ウィザード" + +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "追加する" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "編集する" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "削除する" -#: ../gtk/parameters.ui.h:51 -#, fuzzy +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "接続中" +msgstr "プロキシアカウント" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" +msgstr "すべてのパスワードを消去する" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "プライバシー" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" msgstr "" -#: ../gtk/parameters.ui.h:53 -#, fuzzy -msgid "Privacy" -msgstr "接続中" +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "使用する" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "鳴動音:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "使用しない" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "" -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "接続中" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "エコーキャンセラーを有効にする" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "オーディオ" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "ビデオ" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" -msgstr "" +msgstr "アップロード速度制限 Kbit/sec:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" -msgstr "" +msgstr "ダウンロード速度制限 Kbit/sec:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" +msgstr "帯域幅制御" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "マルチメディア設定" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" msgstr "" +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "DTMFをSIP情報で送信する" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "転送" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "SIP/UDP ポート" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "SIP/TCP ポート" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "オーディオ RTP/UDP:" + #: ../gtk/parameters.ui.h:64 -#, fuzzy +msgid "Fixed" +msgstr "" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "ビデオ RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "メディアの暗号化の種類" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "トンネル" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "DSCP値" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "ネットワークのプロトコルとポート" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "パブリック IP アドレス:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Stunサーバー:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT と ファイヤーウォール" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "ネットワーク設定" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "使用する" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "使用しない" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "コーデック" -#: ../gtk/parameters.ui.h:65 -#, fuzzy +#: ../gtk/parameters.ui.h:85 msgid "Language" -msgstr "接続中" +msgstr "言語" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" +msgstr "拡張設定を表示する" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "レベル" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "ユーザーインターフェイス" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "サーバーアドレス:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" msgstr "" -#: ../gtk/parameters.ui.h:67 -#, fuzzy -msgid "Level" -msgstr "接続中" +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" -#: ../gtk/parameters.ui.h:68 -#, fuzzy -msgid "User interface" -msgstr "ユーザーマニュアル" +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" -#: ../gtk/parameters.ui.h:69 -#, fuzzy +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "ありません。" +msgstr "完了" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "コーデックの情報" +msgstr "" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" msgstr "" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "接続中" - -#: ../gtk/waiting.ui.h:1 -#, fuzzy -msgid "Linphone" -msgstr "Linphone" +msgstr "" #: ../gtk/waiting.ui.h:2 msgid "Please wait" -msgstr "" +msgstr "お待ちください" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "ネットワーク" +msgid "DSCP settings" +msgstr "DSCP設定" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1376,11 +1537,11 @@ msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 msgid "Audio RTP stream" -msgstr "" +msgstr "オーディオのRTP" #: ../gtk/dscp_settings.ui.h:4 msgid "Video RTP stream" -msgstr "" +msgstr "ビデオのRTP" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" @@ -1388,34 +1549,51 @@ msgstr "" #: ../gtk/call_statistics.ui.h:1 msgid "Call statistics" -msgstr "" +msgstr "通信統計" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "オーディオコーデックのプロパティー" +msgstr "オーディオのコーデック" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "オーディオコーデックのプロパティー" +msgstr "ビデオのコーデック" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "音声で使用しているIP通信帯域" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" -msgstr "" +msgid "Audio Media connectivity" +msgstr "接続している音声用メディア" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "ビデオで使用しているIP通信帯域" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "接続しているビデオ用メディア" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "RTPプロファイル" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "コーデックの情報" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" @@ -1423,156 +1601,262 @@ msgstr "" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "ホスト" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "ポート" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "ユーザー名" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "パスワード" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "LDAP設定" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "TLS接続を使用する" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" msgstr "" -#: ../coreapi/linphonecore.c:235 -msgid "completed" +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "接続" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" msgstr "" -#: ../coreapi/linphonecore.c:238 -msgid "missed" +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Authname" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Realm" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" msgstr "" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "検索" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "種々" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "匿名" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "シンプル" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "ダイジェスト-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." msgstr "" -#: ../coreapi/linphonecore.c:1226 -#, fuzzy +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "送信" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "会議を終了する" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "この通話をファイルに録音する" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "ビデオ" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "消音" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "転送" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "着信" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "期限" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "インターネット接続:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "自動的にログインする" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "ログイン情報" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" -msgstr "準備完了。" +msgstr "準備" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "" - -#: ../coreapi/linphonecore.c:2121 -#, fuzzy -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"SIPアドレスの形式エラーです。SIPアドレスは、のような" -"形式です。" - -#: ../coreapi/linphonecore.c:2312 -#, fuzzy +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" -msgstr "接続中" +msgstr "" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "pixmapファイルが見つかりません %s" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "から電話です。" +msgstr "" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." -msgstr "" +msgstr "と自動応答を尋ねる" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." -msgstr "" +msgstr "コールパラメーターの変更..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "接続しました。" -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "通話はキャンセルされました。" +msgstr "呼び出しを打ち切る" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "" +msgstr "呼び出しを一時停止できませんでした" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "" +msgstr "現在の通話を一時停止..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"このコンピューターはALSAサウンドドライバーを使用しているようです。\n" -"それは最良の選択です。しかし、Linphoneが必要とする\n" -"pcm ossエミュレーションモジュールが見つかりません。\n" -"ロードするために、ルート権限で'modprobe snd-pcm-oss'を実行してください。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"このコンピューターはALSAサウンドドライバーを使用しているようです。\n" -"それは最良の選択です。しかし、Linphoneが必要とする\n" -"mixer ossエミュレーションモジュールが見つかりません。\n" -"ロードするために、ルート権限で'modprobe snd-mixer-oss'を実行してください。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." -msgstr "" +msgstr "Stunによるルックアップの進行中…" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" #: ../coreapi/friend.c:33 -#, fuzzy msgid "Online" -msgstr "ライン入力" +msgstr "オンライン" #: ../coreapi/friend.c:36 msgid "Busy" -msgstr "" +msgstr "ビジー" #: ../coreapi/friend.c:39 msgid "Be right back" @@ -1580,12 +1864,11 @@ msgstr "" #: ../coreapi/friend.c:42 msgid "Away" -msgstr "退席中" +msgstr "離席中" #: ../coreapi/friend.c:45 -#, fuzzy msgid "On the phone" -msgstr "Linphone" +msgstr "" #: ../coreapi/friend.c:48 msgid "Out to lunch" @@ -1596,527 +1879,215 @@ msgid "Do not disturb" msgstr "手が離せません" #: ../coreapi/friend.c:54 -#, fuzzy msgid "Moved" -msgstr "コーデック" +msgstr "移動中" #: ../coreapi/friend.c:57 msgid "Using another messaging service" msgstr "" #: ../coreapi/friend.c:60 -#, fuzzy msgid "Offline" -msgstr "ライン入力" +msgstr "オフライン" #: ../coreapi/friend.c:63 msgid "Pending" -msgstr "" +msgstr "保留" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "" +msgid "Vacation" +msgstr "休暇中" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "不明なステータス" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format -msgid "Could not login as %s" -msgstr "pixmapファイルが見つかりません %s" - -#: ../coreapi/callbacks.c:276 -#, fuzzy -msgid "Remote ringing." -msgstr "登録中……" - -#: ../coreapi/callbacks.c:296 -#, fuzzy -msgid "Remote ringing..." -msgstr "登録中……" - -#: ../coreapi/callbacks.c:307 -msgid "Early media." +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/callbacks.c:352 +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "" + +#: ../coreapi/proxy.c:1407 +#, c-format +msgid "Could not login as %s" +msgstr "" + +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "" + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "" + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "Early media." + +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "通話は拒否されました。" +msgstr "" -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:575 +#, c-format msgid "Call answered by %s." msgstr "" -"電話をかける\n" -"電話に出る" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 -msgid "We have been resumed." -msgstr "" - -#: ../coreapi/callbacks.c:446 -msgid "We are paused by other party." -msgstr "" - -#: ../coreapi/callbacks.c:452 -msgid "Call is updated by remote." -msgstr "" - -#: ../coreapi/callbacks.c:521 -#, fuzzy -msgid "Call terminated." -msgstr "通話は拒否されました。" - -#: ../coreapi/callbacks.c:528 -msgid "User is busy." -msgstr "ユーザーはビジーです" - -#: ../coreapi/callbacks.c:529 -msgid "User is temporarily unavailable." -msgstr "ユーザーは、今出られません。" - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 -msgid "User does not want to be disturbed." -msgstr "ユーザーは手が離せないようです。" - -#: ../coreapi/callbacks.c:532 -msgid "Call declined." -msgstr "通話は拒否されました。" - -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "" - -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 -msgid "Redirected" -msgstr "" - -#: ../coreapi/callbacks.c:600 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "" + +#. we are being paused +#: ../coreapi/callbacks.c:642 +msgid "We are paused by other party." +msgstr "" + +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 +msgid "Call is updated by remote." +msgstr "" + +#: ../coreapi/callbacks.c:797 +msgid "Call terminated." +msgstr "呼び出し終了。" + +#: ../coreapi/callbacks.c:825 +msgid "User is busy." +msgstr "相手はビジーです。" + +#: ../coreapi/callbacks.c:826 +msgid "User is temporarily unavailable." +msgstr "相手は、今出られません。" + +#. char *retrymsg=_("%s. Retry after %i minute(s)."); +#: ../coreapi/callbacks.c:828 +msgid "User does not want to be disturbed." +msgstr "相手は手が離せないようです。" + +#: ../coreapi/callbacks.c:829 +msgid "Call declined." +msgstr "通話は拒否されました。" + +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "リクエストは時間切れです。" + +#: ../coreapi/callbacks.c:875 +msgid "Redirected" +msgstr "" + +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "通話はキャンセルされました。" +msgstr "" -#: ../coreapi/callbacks.c:701 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1008 +#, c-format msgid "Registration on %s successful." -msgstr "登録しました。" +msgstr "" -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1009 +#, c-format msgid "Unregistration on %s done." -msgstr "登録しました。" +msgstr "" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:725 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1030 +#, c-format msgid "Registration on %s failed: %s" -msgstr "登録しました。" +msgstr "" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format msgid "Authentication token is %s" -msgstr "コーデックの情報" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" -msgstr[1] "" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "情報" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "接続中" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "使用する" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "コーデックの情報" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "接続中" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "オーディオコーデックのプロパティー" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "オーディオ" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "情報" - -#, fuzzy -#~ msgid "_Linphone" -#~ msgstr "Linphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "接続しました。" - -#, fuzzy -#~ msgid "gtk-ok" -#~ msgstr "削除する" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "接続しました。" - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "接続中" - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "コーデック" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "オーディオコーデックのプロパティー" - -#, fuzzy -#~ msgid "Request Cancelled." -#~ msgstr "通話はキャンセルされました。" - -#~ msgid "User cannot be found at given address." -#~ msgstr "ユーザーが見つかりません。" - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "相手側では、提案したコーデックを一つもサポートしていません。" - -#~ msgid "Timeout." -#~ msgstr "時間切れです。" - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "リモートホストが見つかりましたが、接続を拒否されました。" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "ユーザーに接続することができませんが、ユーザーは代わりの手段に招待していま" -#~ "す。\n" -#~ "他の手段で連絡をとってください。" - -#, fuzzy -#~ msgid "Gone" -#~ msgstr "ありません。" - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "アドレス" - -#, fuzzy -#~ msgid "Display filters" -#~ msgstr "表示される名前" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "RTPのプロパティー" - -#~ msgid "Sound" -#~ msgstr "サウンド" - -#~ msgid "Address book" -#~ msgstr "電話帳" - -#, fuzzy -#~ msgid "Shows the address book" -#~ msgstr "電話帳" - -#~ msgid "Show more..." -#~ msgstr "詳細" - -#~ msgid "Playback level:" -#~ msgstr "受話音量" - -#~ msgid "Recording level:" -#~ msgstr "送話音量" - -#, fuzzy -#~ msgid "Ring level:" -#~ msgstr "送話音量" - -#~ msgid "Reachable" -#~ msgstr "在席中" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "今席をはずしています。" - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "発信者は、あなたがX分後に戻ってくることが分かります。" - -#~ msgid "mn" -#~ msgstr "分" - -#~ msgid "Moved temporarily" -#~ msgstr "すぐ戻ります" - -#~ msgid "Alternative service" -#~ msgstr "他の連絡手段を使って下さい" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "状態" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "DTMFを送信するための数字を押して下さい。" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphoneはインターネット電話です。\n" -#~ "SIP・RTPプロトコルと互換性があります。" - -#, fuzzy -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "ユーザーは、今出られません。" - -#, fuzzy -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "" -#~ "バッファするミリ秒\n" -#~ "(音声が途切れるときは大きくします)" - -#~ msgid "RTP port used for audio:" -#~ msgstr "オーディオに使用するRTPポート番号" - -#~ msgid "micro" -#~ msgstr "マイク入力" - -#~ msgid "Recording source:" -#~ msgstr "録音する音源" - -#~ msgid "Sound properties" -#~ msgstr "サウンドのプロパティー" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "SIPユーザーエージェントが起動するポート" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "5060番ポートを使うことを強く推奨します。" - -#~ msgid "SIP port" -#~ msgstr "SIPのポート" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "個人情報" - -#, fuzzy -#~ msgid "Add proxy/registrar" -#~ msgstr "SIPレジストラを使う" - -#~ msgid "Remote services" -#~ msgstr "リモートのサービス" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "コーデックのリストです。使いたい順に並べてください。" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "注意:赤い色のコーデックは、現在のネットワーク接続方法では使えません。" - -#, fuzzy -#~ msgid "No information availlable" -#~ msgstr "特に情報はありません" - -#~ msgid "Codec information" -#~ msgstr "コーデックの情報" - -#~ msgid "Address Book" -#~ msgstr "電話帳" - -#~ msgid "Select" -#~ msgstr "選択する" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "ユーザーに接続することができませんが、ユーザーは代わりの手段に招待していま" -#~ "す。他の手段で連絡をとってください。" - -#~ msgid "None." -#~ msgstr "ありません。" - -#, fuzzy -#~ msgid "Name:" -#~ msgstr "名前" - -#, fuzzy -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "" -#~ "SIPアドレスの形式エラーです。SIPアドレスは、のよ" -#~ "うな形式です。" - -#~ msgid "Communication ended." -#~ msgstr "会話は終了しました。" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "サーバーのアドレス" - -#~ msgid "28k modem" -#~ msgstr "28kのモデム" - -#~ msgid "56k modem" -#~ msgstr "56kのモデム" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64Kのモデム(ISDN)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL・CATVモデム" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "イーサネットなど" - -#~ msgid "Connection type:" -#~ msgstr "接続のタイプ" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphoneはオーディオデバイスをオープンできませんでした。サウンドカードの設" -#~ "定が完全で、正しく動いているかどうか確認して下さい。" - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "電話をかけたい相手のSIPアドレスを入力して下さい。" - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "電話を切る\n" -#~ "会話を拒否" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s。%i 分後にかけ直して下さい。" - -#, fuzzy -#~ msgid "Timeout..." -#~ msgstr "時間切れです。" - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "リモートサーバーに登録するときは、チェックして下さい。" - -#~ msgid "Address of record:" -#~ msgstr "登録するアドレス" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "登録にパスワードを用います。必須でないサーバーもあります。" - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "レジストラサーバーをアウトバウンドプロクシとして使用します。" - -#~ msgid "sip address:" -#~ msgstr "SIPアドレス" - -#~ msgid "Modify" -#~ msgstr "修正" - -#, fuzzy -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "現在、i810オーディオドライバーを使っています。\n" -#~ "このドライバーにはバグがあり、Linphoneではうまく動作しません。\n" -#~ "ALSAドライバーに相当する\n" -#~ "あなたのディストリビュージョンのパッケージか、\n" -#~ "ALSAドライバー(http://www.alsa-project.org)への交換を推奨します。" - -#~ msgid "Unregistration successfull." -#~ msgstr "登録を解除しました。" - -#~ msgid "Select network interface to use:" -#~ msgstr "使用するネットワークインターフェースを選んで下さい" - -#~ msgid "Network interface properties" -#~ msgstr "ネットワークインターフェースのプロパティー" - -#~ msgid "RTP" -#~ msgstr "RTP" - -#~ msgid "C: 2001" -#~ msgstr "C: 2001" - -#~ msgid "/dev/dsp" -#~ msgstr "/dev/dsp" - -#~ msgid "/dev/dsp1" -#~ msgstr "/dev/dsp1" - -#~ msgid "/dev/dsp2" -#~ msgstr "/dev/dsp2" - -#~ msgid "/dev/dsp3" -#~ msgstr "/dev/dsp3" - -#~ msgid "Set the selected address in linphone'main window." -#~ msgstr "選択したアドレスがLinphoneのメインウインドウに現れます。" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "不明" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "%s が再生出来ません。" diff --git a/po/nb_NO.po b/po/nb_NO.po index 7ae0827eb..638f894ed 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -1,108 +1,124 @@ -# Copyright (C) 2011 Free Software Foundation, Inc. -# This file is distributed under the same license as the PACKAGE package. -# -# Øyvind Sæther , 2011. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Øyvind Sæther , 2011 msgid "" msgstr "" -"Project-Id-Version: \n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2011-04-05 01:56+0200\n" -"Last-Translator: Øyvind Sæther \n" -"Language-Team: Norwegian Bokmål \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Norwegian Bokmål (Norway) (http://www.transifex.com/" +"belledonne-communications/linphone-gtk/language/nb_NO/)\n" +"Language: nb_NO\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Lokalize 1.2\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "Ring %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Send tekst til %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "avbrutt" +msgstr "" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "ubesvart" +msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "Avvis" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 -#, fuzzy +#: ../gtk/conference.c:46 msgid "Me" -msgstr "Skru mikrofonen av" +msgstr "" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "skriv logg-informasjon under kjøring" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "Start skjult i systemkurven, ikke vis programbildet." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "address som skal ringes nå" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "besvarer innkommende samtaler automatisk om valgt" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,88 +126,91 @@ msgstr "" "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:" "\\Programfiler\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Ring med %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"&s vil legge deg til i hans/hennes kontaktliste.\n" -"Vil du tillate vedkommende å se din tilstedestatus eller legge vedkommende i " -"din kontaktliste?\n" -"Hvis du svarer nei vil personen bli svartelyst midlertidig." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"Skriv inn ditt passord for brukernavn %s\n" -" på domene %s:i>:" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Samtalehistorikk" +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "Svarer" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Avvis" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "Samtale avbrutt" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "Peker til nettsted" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - en video Internet telefon" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (Standard)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "Vi er overført til %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -199,175 +218,190 @@ msgstr "" "Klarte ikke å finne noe lydkort på denne datamaskinen.\n" "Du vil ikke kunne sende eller motta lydsamtaler." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Tilstedestatus" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Navn" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Ring %s" +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Søk i %s katalogen" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "Ugyldig SIP kontakt !" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "Ring %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Send tekst til %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Rediger kontakt '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Legg til kontakt fra %s katalogen" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min. datahastighet (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parametere" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Engelsk" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Svensk" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italisensk" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Spansk" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "Portugisisk" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polsk" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Tysk" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Russisk" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "Japansk" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Nederlandsk" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Ungarsk" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Tjekkisk" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "Kinesisk" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Du må restarte linphone for at det nye språkvalget skal iverksettes." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -411,523 +445,554 @@ msgid_plural "Found %i contacts" msgstr[0] "Fant kontakt %i" msgstr[1] "Hittat kontakt %i" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"Velkommen\n" -"Denne veiviseren vil hjelpe deg sette opp en SIP-konto for dine samtaler." -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "Lag en konto ved å velge ett brukernavn" +msgstr "" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "Jeg har allerede en brukerkonto og vil bruke den." +msgstr "" -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "Jeg har allerede en brukerkonto og vil bruke den." - -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "Brukernavn:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "Passord:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "Brukernavn" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "Passord" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Brukernavn:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Passord:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Brukernavn:" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Passord:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Takk. Ditt konto er nå satt opp og klart til bruk." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Takk. Ditt konto er nå satt opp og klart til bruk." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Velkommen til brukerkontoveiviseren" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "Konfigurer en SIP konto" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -msgid "Error" +msgid "Configure your account (step 1/1)" msgstr "" #: ../gtk/setupwizard.c:592 -#, fuzzy +msgid "Enter your sip username (step 1/1)" +msgstr "" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "Lägg på" +msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "Ring %s" +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "Ikke funnet" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" msgstr "" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "ICE filter" +msgid "ICE not activated" +msgstr "" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Omdirigert" +msgid "Going through one or more NATs" +msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +#, fuzzy +msgid "00:00:00" msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "I samtale med" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "Pauset samtale" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i:%02i:%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Samtale avsluttet." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 -#, fuzzy +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "Overfører" +msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Overfører" +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "Fortsett" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "Pause" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Skriv inn påloggingsinformasjon for %s:" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Samtale avsluttet." - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Send" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "Overfører" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "I samtale" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Varighet" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_Alternativer" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Vis video av deg selv" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "_Hjelp" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "Vis avlusningsvindu" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "H_jemmeside" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "Sjekk _Oppdateringer" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "Brukerkontoveiviser" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "Sip adresse eller telefonnummer:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "Start en ny samtale" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Legg til" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Rediger" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Søk" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Legg til kontakter fra katalogen" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "Legg til kontakt" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "Tastatur" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "I samtale" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Min nåværende identitet:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Brukernavn" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Passord" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Internet forbindelse:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Logg meg på automatisk" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Innlogginsinformasjon" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Velkommen!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "Alle brukere" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "Tilkoblede brukere" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "Fiber Kanal" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "Standard" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Alternativer" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Vis video av deg selv" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Hjelp" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Vis avlusningsvindu" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "H_jemmeside" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Sjekk _Oppdateringer" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "Sip adresse eller telefonnummer:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Start en ny samtale" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Kontakter" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Søk" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Legg til kontakter fra katalogen" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Legg til kontakt" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Min nåværende identitet:" + #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "Om Linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "(C) Belledonne Communications,2011\n" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -948,18 +1013,8 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" -"fr: Simon Morlat\n" -"en: Simon Morlat og Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonym\n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -993,7 +1048,7 @@ msgstr "Linphone - Autorisering kreves" msgid "Please enter the domain password" msgstr "Skriv inn passordet for domenet" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "BrukerID" @@ -1034,292 +1089,408 @@ msgid "Looks like sip:" msgstr "Ser ut som sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (valgfritt):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registreringsfrekvens (sek.):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Route (valgfritt):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publiser tilstedestatus" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Konfigurer en SIP konto" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "standard lydkort" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "ett lydkort" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "standard kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Lyd kodek" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Video kodek" -#: ../gtk/parameters.ui.h:8 -#, fuzzy -msgid "SIP (UDP)" -msgstr "SIP (UDP):" - -#: ../gtk/parameters.ui.h:9 -#, fuzzy -msgid "SIP (TCP)" -msgstr "SIP (TCP):" - #: ../gtk/parameters.ui.h:10 -#, fuzzy -msgid "SIP (TLS)" -msgstr "SIP (TCP):" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "Innstillinger" +msgid "SIP (UDP)" +msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Velg MTU (Maximum Transmission Unit):" +msgid "SIP (TCP)" +msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Send DTMF som SIP-info" +msgid "SIP (TLS)" +msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Bruk IPv6 istedet for IPv4" +msgid "default" +msgstr "" #: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Transport" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "Innstillinger" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "Video RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "Lyd RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Tilkoblet Internett direkte" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Bak NAT / Brannmur (spesifiser gateway IP under)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Offentlig IP-addresse:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "STUN tjener:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT og Brannvegg" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Nettverksinnstillinger" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Ringelyd:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Spesiell ALSA enhet (valgfritt):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Mikrofonenhet:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Ringe-enhet:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Avspillingsenhet:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Bruk ekko-kansellering" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Lyd" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Videoenhet:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Foretrukke video-oppløsning:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Multimediainnstillinger" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "Denne seksjonen velger SIP-addresse når du ikke bruker en SIP-konto" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "Vist navn (eks: Ola Nordmann):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Ditt brukernavn:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "Din resulterende SIP addresse:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Standard identitet" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Legg til" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Rediger" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Fjern" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Proxy kontoer" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Slett alle passord" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Personvern" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Behandle SIP-kontoer" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aktiver" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Ringelyd:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Deaktiver" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Spesiell ALSA enhet (valgfritt):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Kodeker" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Mikrofonenhet:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Ringe-enhet:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Avspillingsenhet:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Bruk ekko-kansellering" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Lyd" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Videoenhet:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 betyr \"ubegrenset\"" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Maks opplastningshastighet i Kbit/sek:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Nedlastningsbegrensning i Kbit/sek:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Båndbreddekontrol" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Multimediainnstillinger" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Velg MTU (Maximum Transmission Unit):" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Send DTMF som SIP-info" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Transport" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "Lyd RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Video RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Tilkoblet Internett direkte" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Offentlig IP-addresse:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN tjener:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT og Brannvegg" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Nettverksinnstillinger" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Aktiver" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Deaktiver" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Kodek" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Språk" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "Vis avanserte innstillinger" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Nivå" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Brukergrensesnitt" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Ferdig" @@ -1335,58 +1506,48 @@ msgstr "Legg til listen min" msgid "Search somebody" msgstr "Søk noen" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "Vennligst vent" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Innstillinger" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "Lydomformer" +msgstr "" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "Video RTP/UDP:" +msgstr "" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" msgstr "" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Ringer %s" +msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Lyd kodek" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Video kodek" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1394,14 +1555,32 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Kontaktinformasjon" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Konfigurer en SIP konto" +msgstr "" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" @@ -1415,136 +1594,242 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Brukernavn" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Passord" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "avbrutt" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "Fullført" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "ubesvart" - -#: ../coreapi/linphonecore.c:243 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s på %s\n" -"Fra: %s\n" -"Til: %s\n" -"Status: %s\n" -"Lengde: %i min %i sek\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Utgående samtale" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Send" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Overfører" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "I samtale" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Varighet" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Internet forbindelse:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Logg meg på automatisk" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Innlogginsinformasjon" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Klar" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Ser etter telefonnummer for destinasjonen..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Kan ikke tilkoble dette nummeret." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"Klarer ikke å tolke angitt SIP-adresse. En SIP-adresse er vanligvis ut som " -"sip: brukernavn@domenenavn" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Tilknytter" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "Kunne ikke ringe" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Beklager, du har nådd maksimalt antall samtidige samtaler" -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "Kontakter deg." -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr " og ba om autosvar." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "." - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "Endrer ringeparametre..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Tilkoblet" -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" -"Dette er det beste alternativet. Det ser ut til at pcm oss " -"emulasjonsmodulen\n" -"mangler og linphone trenger den. Vennligst kjør\n" -"'modprobe snd-pcm-oss' som root for å laste den." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" -"Dette er det beste alternativet. Det ser ut til at mixermodulen for oss " -"emulering\n" -"mangler og linphone trenger den. Vennligst kjør\n" -"'modprobe snd-mixer-oss' som root for å laste den." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "STUN oppslag pågår..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1593,10 +1878,14 @@ msgid "Pending" msgstr "Pågående" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Ukjent feil" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1604,7 +1893,7 @@ msgstr "" "SIP proxy adressen du har angitt er ugyldig, den må begynne med \"sip:\" " "etterfult av vertsnavn." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1612,576 +1901,181 @@ msgstr "" "SIP adressen du har angitt er feil. Adressen bør se ut som sip: " "brukernavn@domenenavn, f.eks sip:ola@eksempel.no" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Ser etter telefonnummer for destinasjonen..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Kan ikke tilkoble dette nummeret." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "Ikke ikke logge inn som %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Ringer hos motparten." +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "Tidlig media" -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "Samtalen med %s er pauset." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "Samtale besvart av %s - på vent." -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "Samtale gjenopptatt." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "Samtale besvart av %s." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 -#, fuzzy -msgid "We have been resumed." -msgstr "Vi har blitt gjenopptatt..." +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" -#: ../coreapi/callbacks.c:446 +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "" + +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Samtale avsluttet." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Brukeren er opptatt." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Brukeren er midlertidig ikke tilgjengelig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "Brukeren vil ikke bli forstyrret." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Samtale avvist." -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "Ikke noe svar." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "Protokollfeil." - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "Omdirigert" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "Samtale feilet." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lykkes." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lykkes." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "ingen svar innen angitt tid" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislykkes: %s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Autorisering kreves" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Du har %i ubesvarte anrop." msgstr[1] "Du har %i missade samtal" -#~ msgid "Chat with %s" -#~ msgstr "Chat med %s" - -#~ msgid "Please choose a username:" -#~ msgstr "Velg ett brukernavn:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Sjekker om %s' er tilgjengelig..." - -#~ msgid "Please wait..." -#~ msgstr "Vennligst vent..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "Beklager, brukernavnet er allerede tatt. Forsøk ett annet." - -#~ msgid "Ok !" -#~ msgstr "Ok !" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Kommunikasjonsproblem, forsøk igjen senere." - -#~ msgid "Choosing a username" -#~ msgstr "Velg ett brukernavn" - -#~ msgid "Verifying" -#~ msgstr "Verifiserer" - -#~ msgid "Confirmation" -#~ msgstr "Bekreftelse" - -#~ msgid "Creating your account" -#~ msgstr "Lager brukerkontoen din" - -#~ msgid "Now ready !" -#~ msgstr "Klar nå!" - -#~ msgid "Contacts" -#~ msgstr "Kontakter" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "På" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "Skriv inn brukernavn, telefonnummer eller full SIP-addresse" - -#~ msgid "Lookup:" -#~ msgstr "Slå opp:" - -#~ msgid "in" -#~ msgstr "i" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Registrer hos FONICS\n" -#~ "virtuelle nettverk !" - -#~ msgid "We are being paused..." -#~ msgstr "Vi er satt på vent..." - -#~ msgid "No common codecs" -#~ msgstr "Ingen felles kodek" - -#~ msgid "Authentication failure" -#~ msgstr "Autorisering kreves" - -#~ msgid "Windows" -#~ msgstr "Vinduer" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "Pauser alle samtaler\n" -#~ "og svarer" - -#~ msgid "Unmute" -#~ msgstr "Skru mikrofonen på" - -#~ msgid "Contact list" -#~ msgstr "Kontaktliste" - -#~ msgid "Audio & video" -#~ msgstr "Lyd og Video" - -#~ msgid "Audio only" -#~ msgstr "Kun lyd" - -#~ msgid "Duration:" -#~ msgstr "Varighet:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Samtalehistorikk" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "gtk-cancel" -#~ msgstr "gtk-avbryt" - -#~ msgid "gtk-ok" -#~ msgstr "gtk-ok" - -#~ msgid "Register at startup" -#~ msgstr "Registrer ved oppstart" - -#~ msgid "gtk-close" -#~ msgstr "gtk-lukk" - -#~ msgid "Ports" -#~ msgstr "Porter" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "Beklager, du må pause eller avslutte den nåværende samtalen først !" - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "Det er allerede en samtale igang, pause eller avslutt den først." - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw enkoder" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw dekoder" - -#~ msgid "Alsa sound source" -#~ msgstr "Alasa lydkilde" - -#~ msgid "Alsa sound output" -#~ msgstr "alsa lydutgang" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "Lydfangefilter for MacOS X Audio Queue Service" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "Lydavspillingsfilter for MacOS X Audio Queue Service" - -#~ msgid "DTMF generator" -#~ msgstr "DTMF generator" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "Høyhastighets GSM kodek" - -#~ msgid "The GSM codec" -#~ msgstr "GSM kodek" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "Lydfangefilter for MacOS X Core Audio drivere" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "Lydavspillingsfilter for MacOS X Core Audio drivere" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Ett filter for telekonferanser" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Få filer og wav leser" - -#~ msgid "Wav file recorder" -#~ msgstr "WAV filopptaker" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "Ett filer for å sende flere inn-kilder til en utgang" - -#~ msgid "RTP output filter" -#~ msgstr "RTP ut-filter" - -#~ msgid "RTP input filter" -#~ msgstr "RTP inn-filter" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "En fri og fantatisk speex kodek" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "Ett filer som kontrollerer og måler lydvolumet" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "Ett video4linux kompatiblet kildefilter for bildestrømmer." - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "Ett filter for å fange bilder fra Video4Linux2-støttede kameraer" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "En filter som sender ett statisk bilde." - -#~ msgid "A pixel format converter" -#~ msgstr "En pixel format omformer" - -#~ msgid "A video size converter" -#~ msgstr "En videostørrelsesomformer" - -#~ msgid "a small video size converter" -#~ msgstr "En liten video størrelsesomformer" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "Ekko fjerning ved hjelp av speex" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "Ett filter som leser innkoder og kopierer det til flere utganger" - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "En Theora videokoder fra xpih.org" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "" -#~ "Et åpen kildekode og betalingsfritt 'theora' video kodek fra xpih.org" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Theora video dekoder fra xiph.org" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw enkoder" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw dekoder" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "En H.263 dekoder som bruker ffmpeg biblioteket" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "En MPEG4 dekoder som bruker ffmpeg biblioteket" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "En RTP/JPEG dekoder som bruker ffmpeg biblioteket" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "En MJPEG dekoder som bruker ffmpeg biblioteket" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "En snow dekoder som bruker ffmpeg biblioteket" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "En H.263 videodekoder som bruker ffmpeg biblioteket" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "" -#~ "En H.263 enkoder som bruker ffmpeg biblioteket. Den følger den eldre " -#~ "RFC2190 spesifikasjonen." - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "En video MPEG4 enkoder som bruker ffmpeg biblioteket." - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "En show video enkoder som bruker ffmpeg biblioteket." - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "En RTP/MJPEG enkoder som bruker ffmpeg biblioteket" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "" -#~ "En h.264 video enkoder som bruker ffmpeg biblioteket, kompatibelt med den " -#~ "eldre RFC2190 spesifikasjonen." - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "Snow video-kodeksen har åpen kildekode og er vedelagsfri.\n" -#~ "Den bruker moderne teknikker som gjør den til en god video kodek. Den er " -#~ "implementert innen ffmpeg prosjektet.\n" -#~ "Den er under stadig utvikling, er ganske ustabil og kompatiblitet med " -#~ "andre utgaver kan ikke garanteres." - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "En MJPEG enkoder som bruker ffmpeg biblioteket." - -#~ msgid "A SDL-based video display" -#~ msgstr "Ett SDL-basert video-bibliotek" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "Ett video4windows-kompatibelt kildefiler for bildestrømmer." - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "" -#~ "Ett video for vinduer (vfw.h) baserte kildefilter for å fange bilder" - -#~ msgid "" -#~ "A filter that trashes its input (useful for terminating some graphs)." -#~ msgstr "" -#~ "Ett filter som ødelegger input (nyttig for å terminere noen grafer)." - -#~ msgid "Parametric sound equalizer." -#~ msgstr "Parameterisk lyd-mixer" - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "En webcam-fanger basert på directshow." - -#~ msgid "A video display based on windows DrawDib api" -#~ msgstr "Videovisning basert på windows DrawDib api" - -#~ msgid "A filter that mixes down 16 bit sample audio streams" -#~ msgstr "Ett filter som mixer ned til 16 bits lydstrømmer" - -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "Ett filter som konverterer fra mono til stereo og motsatt." - -#~ msgid "Inter ticker communication filter." -#~ msgstr "Inter ticker kommunikasjonsfilter." - -#~ msgid "A display filter sending the buffers to draw to the upper layer" -#~ msgstr "" -#~ "Et visningsfilter for å sende buffere for å tegne det oppdaterte nivået" - -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "Lydfangefilter for MacOS X Audio Unit Service" - -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "Lydavspillingsfilter for MacOS X Audio Unit Service" - -#~ msgid "A video display using X11+Xv" -#~ msgstr "En videovisning som bruker X11-Xv" - -#~ msgid "Sound capture filter for Android" -#~ msgstr "Lydfangefilter for Android" - -#~ msgid "Sound playback filter for Android" -#~ msgstr "Lydavspillingsfilter for Android" - -#~ msgid "A filter that captures Android video." -#~ msgstr "Ett filter som fanger Android video." - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Din dator er tilkoblet ett IPv6 nettverk. Linphone bruker IPv6 som " -#~ "standard. Oppdater oppsettet om du vil bruke IPv6. " - -#~ msgid "Incoming call from %s" -#~ msgstr "Inkommande samtal från %s" - -#~ msgid "Assistant" -#~ msgstr "Assistent" - -#~ msgid "Show debug messages" -#~ msgstr "Visa debugfönstret" - -#~ msgid "Start call" -#~ msgstr "Ring" - -#~ msgid "_Modes" -#~ msgstr "_Media" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "Skapad av Simon Morlat\n" - -#~ msgid "Accept" -#~ msgstr "Godkänn" - -#~ msgid "Incoming call from" -#~ msgstr "Inkommande samtal från" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone - Inkommande samtal" - -#~ msgid "default soundcard\n" -#~ msgstr "default ljudkort\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "" -#~ "Motparten verkar ha avbrutit samtalet, samtalet kommer att avslutas." - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Förlåt, men linphone stödjer inte flera samtliga samtal än!" - -#~ msgid "Could not reach destination." -#~ msgstr "Kunde inte nå motparten." - -#~ msgid "Request Cancelled." -#~ msgstr "Förfrågan avbruten." - -#~ msgid "Bad request" -#~ msgstr "Fel förfråga." - -#~ msgid "User cannot be found at given address." -#~ msgstr "Användaren kan inte hittas vid den angivna adressen." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "Motparten stödjer ingen av de föreslagna codecs." - -#~ msgid "Timeout." -#~ msgstr "time out." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Motparten hittades men ville inte ta emot samtalet." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Användaren kan inte nås för tillfället men han/hon ber digatt kontakta " -#~ "honom/henna vid följande resurs:" - -#~ msgid "Digits" -#~ msgstr "Tangenter" - -#~ msgid "Main view" -#~ msgstr "Huvud vy" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Ingen NAT / brandväggs adress angiven!" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Fel NAT adress '%s': %s" - -#~ msgid "Gone" -#~ msgstr "Har gått" - -#~ msgid "Waiting for Approval" -#~ msgstr "Väntar för godkännandet" - -#~ msgid "Be Right Back" -#~ msgstr "Kommer strax tillbaka" - -#~ msgid "On The Phone" -#~ msgstr "På telefon" - -#~ msgid "Out To Lunch" -#~ msgstr "Lunchar" - -#~ msgid "Closed" -#~ msgstr "Stängt" - -#~ msgid "Unknown" -#~ msgstr "Okänd" - -#~ msgid "SIP address" -#~ msgstr "SIP Adress" - -#~ msgid "Bresilian" -#~ msgstr "Brasiliansk" - -#~ msgid "_View" -#~ msgstr "_Vy" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/nl.po b/po/nl.po index 84f297c20..647840d44 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,369 +1,416 @@ -# translation of nl.po to Nederlands -# Dutch translation of linphone. -# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the linphone package. -# Taco Witte , 2005. -# Hendrik-Jan Heins , 2005. -# Hendrik-Jan Heins , 2007. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Heimen Stoffels , 2015 msgid "" msgstr "" -"Project-Id-Version: nl\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2007-09-05 10:40+0200\n" -"Last-Translator: Hendrik-Jan Heins \n" -"Language-Team: Nederlands \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Dutch (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/nl/)\n" +"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "%s bellen" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "SMS versturen aan %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "Recent oproepen (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "n.v.t." + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "afgebroken" +msgstr "Afgebroken" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "gemist" +msgstr "Gemist" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "lijn" +msgstr "Geweigerd" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i minuut" +msgstr[1] "%i minuten" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i seconde" +msgstr[1] "%i seconden" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" +"%s\tKwaliteit: %s\n" +"%s\t%s\t" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" -msgstr "" +msgid "%s\t%s" +msgstr "%s\t%s" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" -msgstr "" +msgstr "Vergadering" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" -msgstr "" +msgstr "Ik" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" -msgstr "Kon pixmap bestand %s niet vinden" +msgstr "Het pixmap-bestand %s kon niet worden gevonden" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "" +"loggen naar stdout om wat foutopsporingsinformatie te verkrijgen tijdens " +"uitvoeren." -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "" +msgstr "Pad naar een bestand om logbestanden heen te schrijven." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Linphone opstarten met uitgeschakelde video." -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "" +msgstr "Alleen in het systeemvak opstarten, niet met venster en al." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "" +msgstr "adres om nu naar toe te bellen" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" +"Specificeer een werkmap (dit moet de basis van uw installatie zijn, bijv.: C:" +"\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, fuzzy, c-format -msgid "Call with %s" -msgstr "Chat met %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Configuratiebestand" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Doorloop de audio-instelwizard" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Draai een zelftest en exit 0 wanneer succesvol" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" +"Vul uw wachtwoord in voor gebruikersnaam %s\n" +"op realm %s" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Linphone - Oproepgeschiedenis" +msgstr "Oproepfout" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "Oproep beeindigd" +msgstr "Oproep beëindigd" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" -msgstr "" +msgstr "Opnemen" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "lijn" +msgstr "Weigeren" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "afgebroken" +msgstr "Oproep gepauzeerd" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "" +msgid "by %s" +msgstr "door %s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s stelt u voor om video in te schakelen. Wilt u dit accepteren?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" +msgstr "Websitelink" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "" - -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "" +msgstr "%s (Standaard)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" -msgstr "" +msgstr "We zijn overgeschakeld naar %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" +"Er zijn geluidskaarten aangetroffen op deze computer.\n" +"U zult niet in staat zijn om audio-oproepen te ontvangen of versturen." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" -msgstr "Een Vrije SIP video-telefoon" +msgstr "Een gratis SIP-videotelefoon" -#: ../gtk/friendlist.c:335 -#, fuzzy +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" -msgstr "Adresboek" +msgstr "Toevoegen aan adresboek" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Aanwezigheidsstatus" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Naam" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Oproepgeschiedenis" +msgstr "Bellen" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Chat box" +msgstr "Chatten" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" -msgstr "" +msgstr "Zoeken in de map %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" -msgstr "" +msgstr "Ongeldig SIP-contactpersoon" -#: ../gtk/friendlist.c:775 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Oproepgeschiedenis" - -#: ../gtk/friendlist.c:776 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format msgid "Edit contact '%s'" -msgstr "Bewerk contactgegevens" +msgstr "Contactpersoon '%s' bewerken" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" -msgstr "" +msgstr "Contactpersoon '%s' verwijderen" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Chatgeschiedenis van '%s' verwijderen" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" -msgstr "" +msgstr "Nieuw contactpersoon toevoegen vanuit de map %s" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Frequentie (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Minimale bitrate (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "IP-bitrate (kbit/s)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" -msgstr "Parameters" +msgstr "Argumenten" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" -msgstr "Aan" +msgstr "Ingeschakeld" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" -msgstr "Uit" +msgstr "Uitgeschakeld" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" -msgstr "" +msgstr "Engels" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" -msgstr "" +msgstr "Frans" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" -msgstr "" +msgstr "Zweeds" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" -msgstr "" +msgstr "Italiaans" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" -msgstr "" +msgstr "Spaans" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" -msgstr "" +msgstr "Braziliaans Portugees" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" -msgstr "" +msgstr "Pools" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" -msgstr "" +msgstr "Duits" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" -msgstr "" +msgstr "Russisch" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" -msgstr "" +msgstr "Japans" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" -msgstr "" +msgstr "Nederlands" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" -msgstr "" +msgstr "Hongaars" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" -msgstr "" +msgstr "Tjechisch" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" -msgstr "" +msgstr "Chinees" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" -msgstr "" +msgstr "Traditioneel Chinees" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" -msgstr "" +msgstr "Noors" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" +msgstr "Hebreeuws" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Servisch" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" +"U moet linphone herstarten om de nieuw geselecteerde taal toe te passen." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "Geen" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" -msgstr "" +msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -371,576 +418,607 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" +"Er is een nieuwere versie beschikbaar op %s.\n" +"Wilt een webbrowser openen en deze downloaden?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "" +msgstr "U gebruikt de nieuwste versie." #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" -msgstr "" +msgstr "Voornaam, Achternaam" #: ../gtk/buddylookup.c:160 msgid "Error communicating with server." -msgstr "" +msgstr "Er is een fout opgetreden tijdens het communiceren met de server." #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "Verbinden" +msgstr "Bezig met verbinden..." #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "Verbonden." +msgstr "Verbonden" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." -msgstr "" +msgstr "Bezig met ontvangen van gegevens..." #: ../gtk/buddylookup.c:180 #, c-format msgid "Found %i contact" msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i contactpersoon gevonden" +msgstr[1] "%i contactpersonen gevonden" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" +"Welkom!\n" +"Deze instelwizard zal u begeleiden bij het gebruiken van een SIP-account " +"voor oproepen." -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Creëer een account op linphone.org" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "" +msgstr "Ik heb al een linphone.org-account en wil deze graag gebruiken" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" +msgstr "Ik heb al een SIP-account en wil deze graag gebruiken" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Ik wil een externe URI-configuratie opgeven" + +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" -msgstr "" - -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "gebruikersnaam:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "wachtwoord:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "" - -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "gebruikersnaam:" +msgstr "Gebruikersnaam*" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "wachtwoord:" +msgstr "Wachtwoord*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" -msgstr "" +msgstr "Domeinnaam*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" -msgstr "" +msgstr "Proxy" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Vul uw linphone.org-gebruikersnaam in" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Gebruikersnaam:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Wachtwoord:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Verplichte velden" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "gebruikersnaam:" +msgstr "Gebruikersnaam: (*)" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "wachtwoord:" +msgstr "Wachtwoord: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "" +msgstr "E-mailadres: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" +msgstr "Bevestig uw wachtwoord: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Houdt me op de hoogte van linphone-updates" + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" - -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" +"Valideer uw account door te klikken op de link die we zojuist naar uw e-" +"mailadres hebben verstuurd.\n" +"Kom dan terug naar dit venster en klik op de knop Volgende." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Er is een fout opgetreden: uw account is niet gevalideerd, de gebruikersnaam " +"wordt al door iemand anders gebruikt of de server is onbereikbaar.\n" +"Ga terug en probeer het opnieuw." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Bedankt. Uw account is nu ingesteld en klaar voor gebruik." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "SIP-account-instelwizard" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:559 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk/setupwizard.c:565 -msgid "Configure your account (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "Welkom bij de account-instelwizard" #: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" +msgid "Account setup assistant" +msgstr "Account-instelwizard" #: ../gtk/setupwizard.c:588 -msgid "Error" -msgstr "" +msgid "Configure your account (step 1/1)" +msgstr "Uw account instellen (stap 1/1)" #: ../gtk/setupwizard.c:592 -msgid "Terminating" +msgid "Enter your sip username (step 1/1)" +msgstr "Vul uw SIP-gebruikersnaam in (stap 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Vul uw accountinformatie in (stap 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format -msgid "Call #%i" -msgstr "Oproepgeschiedenis" +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Geldigheid (stap 2/2)" -#: ../gtk/incall_view.c:150 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Fout" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "Bezig met vernietigen" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "#%i bellen" + +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" -msgstr "" +msgstr "Overschakelen naar gesprek #%i met %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Niet in gebruik" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Oproep geannuleerd." +msgid "ICE not activated" +msgstr "ICE is niet geactiveerd" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "ICE is mislukt" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "ICE is bezig" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Doorgeschakeld naar %s..." +msgid "Going through one or more NATs" +msgstr "Die door één of meer NATs gaan" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "Direct" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Via een relay-server" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP is niet geactiveerd" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP is bezig" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnP is niet beschikbaar" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP wordt uitgevoerd" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "uPnP is mislukt" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Direct of via een server" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"download: %f\n" +"upload: %f (kbit/s)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f fps" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f seconden" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" -msgstr "" +msgstr "Ophangen" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Contactlijst" +msgstr "Bezig met bellen..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Inkomende oproep" +msgstr "Inkomende oproep" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "" +msgstr "goed" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "" +msgstr "gemiddeld" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "" +msgstr "slecht" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "" +msgstr "erg slecht" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "" +msgstr "verschrikkelijk" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "" +msgstr "niet beschikbaar" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" -msgstr "" +msgstr "Beveiligd door SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "Beveiligd door DTLS" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "Beveiligd door ZRTP - [authenticatiesleutel: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "" +msgstr "Instellen als niet-geverifieerd" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "" +msgstr "Instellen als geverifieerd" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" -msgstr "" +msgstr "In een vergadering" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Contactlijst" +msgstr "In gesprek" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "Contactlijst" +msgstr "Gepauzeerde oproep" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk/incall_view.c:699 -#, fuzzy +#: ../gtk/incall_view.c:834 msgid "Call ended." -msgstr "Oproep beeindigd" +msgstr "Oproep is beëindigd." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "De overdracht is bezig" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "" +msgstr "De overdracht is voltooid." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Oproep geannuleerd." +msgstr "De overdracht is mislukt." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" -msgstr "" +msgstr "Hervatten" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" -msgstr "" +msgstr "Pauzeren" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "Bezig met opnemen naar%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Gepauzeerd)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" +msgstr "Vul uw inloggegevens in voor %s" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "bezig met ophalen van %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Het downloaden van de externe configuratie van %s is mislukt." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Er is geen stem gedetecteerd" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Te zacht" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "Goed" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Te hard" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Heeft u drie pieptonen gehoord?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "De geluidsvoorkeuren zijn niet gevonden" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Het systeemgeluidspaneel kon niet worden gestart" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" msgstr "" +"Welkom!\n" +"Deze instelwizard zal u begeleiden bij het instellen van de audio-" +"instellingen van Linphone" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Opname-apparaat" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "Opgenomen volume" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Geen stem" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Systeemgeluidsinstellingen" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Afspeelapparaat" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Drie pieptonen afspelen" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Klik op de opnameknop en zeg enkele woorden" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Luister naar uw opgenomen stem" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Opnemen" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Afspelen" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Laten we nu Linphone opstarten" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Audio-instelwizard" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Audio-instelwizard" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Kalibratie van het microfoonbereik" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Kalibratie van het luidsprekervolume" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Opnemen en afspelen" #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Oproep beeindigd" +msgid "All users" +msgstr "Alle gebruikers" #: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "Geluid" +msgid "Online users" +msgstr "Online gebruikers" -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 +msgid "ADSL" +msgstr "ADSL" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 +msgid "Fiber Channel" +msgstr "Fiber-kanaal" + +#: ../gtk/main.ui.h:5 +msgid "Default" +msgstr "Standaard" + +#: ../gtk/main.ui.h:6 +msgid "Delete" +msgstr "Verwijderen" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Opties" #: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" +msgid "Set configuration URI" +msgstr "Configuratie-URI instellen" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Video altijd starten" #: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" +msgid "Enable self-view" +msgstr "Eigen weergave inschakelen" #: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" +msgid "_Help" +msgstr "_Hulp" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Foutopsporingsvenster weergeven" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Website" #: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "Inkomende oproep" +msgid "Check _Updates" +msgstr "Controleren op _updates" #: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "Informatie" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" +msgid "Account assistant" +msgstr "Account-instelwizard" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" +msgid "SIP address or phone number:" +msgstr "SIP-adres of telefoonnummer:" #: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" +msgid "Initiate a new call" +msgstr "Een nieuw gesprek beginnen" #: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "Video aan" +msgid "Contacts" +msgstr "Contactpersonen" #: ../gtk/main.ui.h:20 -#, fuzzy -msgid "_Help" -msgstr "Help" +msgid "Search" +msgstr "Zoeken" #: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "" +msgid "Add contacts from directory" +msgstr "Voeg contactpersonen toe uit map" #: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" +msgid "Add contact" +msgstr "Contactpersoon toevoegen" #: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" +msgid "Recent calls" +msgstr "Recente gesprekken" #: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Geef het SIP adres of telefoonnummer in" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -#, fuzzy -msgid "Add" -msgstr "Adres" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Bewerken" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Contact informatie" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "Bewerk contactgegevens" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "Inkomende oproep" - -#: ../gtk/main.ui.h:50 -#, fuzzy msgid "My current identity:" -msgstr "SIP-identiteit:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "gebruikersnaam:" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "wachtwoord:" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -#, fuzzy -msgid "Automatically log me in" -msgstr "Automatisch een geldige hostnaam raden" - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "Contact informatie" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "Contactlijst" - -#: ../gtk/main.ui.h:57 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:58 -#, fuzzy -msgid "Online users" -msgstr "Aanwezig" - -#: ../gtk/main.ui.h:59 -msgid "ADSL" -msgstr "" - -#: ../gtk/main.ui.h:60 -msgid "Fiber Channel" -msgstr "" - -#: ../gtk/main.ui.h:61 -#, fuzzy -msgid "Default" -msgstr "SIP-identiteit:" - -#: ../gtk/main.ui.h:62 -msgid "Delete" -msgstr "" +msgstr "Mijn huidige identiteit:" #: ../gtk/about.ui.h:1 -#, fuzzy -msgid "About linphone" -msgstr "linphone" +msgid "About Linphone" +msgstr "Over Linphone" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "" +"Een internetvideotelefoon gebruikmakende van het standaard SIP (rfc3261) " +"protocol." #: ../gtk/about.ui.h:5 msgid "" @@ -955,429 +1033,519 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "Adres" +msgstr "SIP-adres" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" -msgstr "" +msgstr "De aanwezigheidsstatus van dit contactpersoon weergeven" #: ../gtk/contact.ui.h:4 msgid "Allow this contact to see my presence status" msgstr "" +"Toestaan dat deze contactpersoon mijn aanwezigheidsstatus kan weergeven" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "Contact informatie" +msgstr "Contactinformatie" #: ../gtk/log.ui.h:1 msgid "Linphone debug window" -msgstr "" +msgstr "Linphone-foutopsporingsvenster" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "" +msgstr "Scroll naar het einde" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Authorisatie gevraagd" +msgstr "Linphone - Authenticatie is vereist" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" -msgstr "" +msgstr "Vul het domeinnaamwachtwoord in" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "" +msgstr "Gebruikersidentificatie" #: ../gtk/call_logs.ui.h:1 -#, fuzzy msgid "Call history" -msgstr "Linphone - Oproepgeschiedenis" +msgstr "Gespreksgeschiedenis" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" -msgstr "" +msgstr "Alles wissen" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "Oproepgeschiedenis" +msgstr "Terugbellen" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" -msgstr "" +msgstr "Linphone - Een SIP-account instellen" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "SIP-identiteit:" +msgstr "Uw SIP-identiteit:" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" -msgstr "" +msgstr "Lijkt op:@" #: ../gtk/sip_account.ui.h:4 msgid "sip:" msgstr "sip:" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "SIP-proxy:" +msgstr "SIP-proxyadres:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" -msgstr "" +msgstr "Lijkt op sip:" #: ../gtk/sip_account.ui.h:7 +msgid "Registration duration (sec):" +msgstr "Registratieduur (sec):" + +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Contactparameters (optioneel):" + +#: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "AVPF regulier RTCP-tussenpose (sec):" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (optioneel):" -#: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Registratieperiode:" - -#: ../gtk/sip_account.ui.h:9 -msgid "Register" -msgstr "" - -#: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "Toon informatie over aanwezigheid:" - #: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Overdracht" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Registreren" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "Aanwezigheidsinformatie publiceren" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "AVPF inschakelen" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" -msgstr "" +msgstr "Een SIP-account instellen" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" -msgstr "" +msgid "anonymous" +msgstr "anoniem" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" -msgstr "" +msgid "GSSAPI" +msgstr "GSSAPI" #: ../gtk/parameters.ui.h:3 -msgid "default camera" -msgstr "" +msgid "SASL" +msgstr "SASL" #: ../gtk/parameters.ui.h:4 -msgid "CIF" -msgstr "" +msgid "default soundcard" +msgstr "standaard geluidskaart" #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "Video codecs" +msgid "a sound card" +msgstr "een geluidskaart" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "Video codecs" +msgid "default camera" +msgstr "standaard camera" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" #: ../gtk/parameters.ui.h:8 +msgid "Audio codecs" +msgstr "Audio-codecs" + +#: ../gtk/parameters.ui.h:9 +msgid "Video codecs" +msgstr "Video-codecs" + +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "" - -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "" - #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "Contactlijst" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "Instellingen" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "SIP-adres:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "Geluidsapparaat" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Contactlijst" - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "Netwerk" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "Belgeluid:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "Geluidsapparaat gebruiken:" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "Geluidsapparaat gebruiken:" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Geluidsapparaat gebruiken:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "Contactlijst" - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "Geluidsapparaat" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "Contactlijst" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" -msgstr "" +msgstr "Uw weergavenaam (bijv.: Jan Noniem):" -#: ../gtk/parameters.ui.h:44 -#, fuzzy +#: ../gtk/parameters.ui.h:20 msgid "Your username:" -msgstr "gebruikersnaam:" +msgstr "Uw gebruikersnaam:" -#: ../gtk/parameters.ui.h:45 -#, fuzzy +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "Uw SIP-adres:" - -#: ../gtk/parameters.ui.h:46 -#, fuzzy -msgid "Default identity" -msgstr "SIP-identiteit:" - -#: ../gtk/parameters.ui.h:47 -msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:22 +msgid "Default identity" +msgstr "Standaardidentiteit" + +#: ../gtk/parameters.ui.h:23 +msgid "Wizard" +msgstr "Instelhulp" + +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Toevoegen" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Bewerken" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Verwijderen" -#: ../gtk/parameters.ui.h:51 -#, fuzzy +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "Contactlijst" +msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:53 -#, fuzzy +#: ../gtk/parameters.ui.h:29 msgid "Privacy" -msgstr "Contactlijst" +msgstr "" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aan" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Belgeluid:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Uit" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "ALSA speciaal apparaat (optioneel)" -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "Contactlijst" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Opnameapparaat:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Belapparaat:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Afspeelapparaat:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Echo-onderdrukking inschakelen" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Audio" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Videoingang-apparaat:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Videouitgangsmethode:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Cameravoorbeeld weergeven" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:59 -#, fuzzy +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" -msgstr "Upload bandbreedte (kbit/sec):" +msgstr "" -#: ../gtk/parameters.ui.h:60 -#, fuzzy +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" -msgstr "Download bandbreedte (kbit/sec):" +msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Multimedia-instellingen" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Maximale Transmissie-unit instellen:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "DTMF's als SIP-informatie versturen" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Overdracht" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "SIP/UDP-poort" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Willekeurig" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "SIP/TCP-poort" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "AUDIO RTP/UDP:" + #: ../gtk/parameters.ui.h:64 -#, fuzzy -msgid "Codecs" -msgstr "Codecs" +msgid "Fixed" +msgstr "Vastgezet" #: ../gtk/parameters.ui.h:65 -#, fuzzy -msgid "Language" -msgstr "Contactlijst" +msgid "Video RTP/UDP:" +msgstr "Video RTP/UDP:" #: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Mediaversleutelingstype" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Mediaversleuteling is vereist" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tunnel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "DSCP-velden" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Netwerkprotocol en -poorten" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Directe verbinding met het internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Achter een NAT / Firewall (specificeer de gateway IP)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Openbaar IP-adres:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Stun-server" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT en Firewall" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Netwerkinstellingen" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Aan" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Uit" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "" + +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:67 -#, fuzzy +#: ../gtk/parameters.ui.h:87 msgid "Level" -msgstr "Contactlijst" +msgstr "" -#: ../gtk/parameters.ui.h:68 -#, fuzzy +#: ../gtk/parameters.ui.h:88 msgid "User interface" -msgstr "gebruikersnaam:" +msgstr "" -#: ../gtk/parameters.ui.h:69 -#, fuzzy +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "Weg" +msgstr "" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "Contact informatie" +msgstr "" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" msgstr "" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "Contactlijst" - -#: ../gtk/waiting.ui.h:1 -#, fuzzy -msgid "Linphone" -msgstr "linphone" +msgstr "" #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Netwerk" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1396,26 +1564,23 @@ msgid "Set DSCP values (in hexadecimal)" msgstr "" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Oproepgeschiedenis" +msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Video codecs" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Video codecs" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1423,9 +1588,28 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Contact informatie" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" @@ -1443,139 +1627,242 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Gebruikersnaam" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Wachtwoord" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "afgebroken" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "voltooid" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "gemist" - -#: ../coreapi/linphonecore.c:243 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s op %s\n" -"Van: %s\n" -"Aan: %s\n" -"Status: %s\n" -"Tijdsduur: %i mins %i secs\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Uitgaande oproep" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Verzenden" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Bellernaam" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Vergadering beëindigen" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Deze oproep opnemen naar een audiobestand" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Video" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Dempen" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Overdracht" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "In gesprek" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Duur" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Waardering van de gesprekskwaliteit" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Internetverbinding:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Automatisch inloggen" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Inloginformatie" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Welkom!" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Gereed." -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Zoekt de lokatie van het telefoonnummer..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Kon dit nummer niet vinden." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" -"gebruikersnaam@domeinnaam" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Verbinden" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "Kon niet oproepen" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "belt u." +msgstr "" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Verbonden." -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "afgebroken" +msgstr "" -#: ../coreapi/linphonecore.c:3102 -#, fuzzy +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "Kon niet oproepen" +msgstr "" -#: ../coreapi/linphonecore.c:3107 -#, fuzzy +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "Kon niet oproepen" - -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." msgstr "" -"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" -"Dit is de beste keuze. Maar de pcm oss emulatie module mist\n" -"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" -"'modprobe snd-pcm-oss' als root om de module te laden." -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" -"Dit is de beste keuze. Maar de mixer oss emulatie module mist\n" -"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" -"'modprobe snd-mixer-oss' als root om de module te laden." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "STUN adres wordt opgezocht..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1588,776 +1875,236 @@ msgid "Busy" msgstr "Bezet" #: ../coreapi/friend.c:39 -#, fuzzy msgid "Be right back" -msgstr "Kom zo terug" +msgstr "" #: ../coreapi/friend.c:42 msgid "Away" msgstr "Afwezig" #: ../coreapi/friend.c:45 -#, fuzzy msgid "On the phone" -msgstr "Aan de telefoon" +msgstr "" #: ../coreapi/friend.c:48 -#, fuzzy msgid "Out to lunch" -msgstr "Aan het lunchen" +msgstr "" #: ../coreapi/friend.c:51 msgid "Do not disturb" msgstr "Niet storen" #: ../coreapi/friend.c:54 -#, fuzzy msgid "Moved" -msgstr "Codecs" +msgstr "" #: ../coreapi/friend.c:57 msgid "Using another messaging service" msgstr "" #: ../coreapi/friend.c:60 -#, fuzzy msgid "Offline" -msgstr "Aanwezig" +msgstr "" #: ../coreapi/friend.c:63 msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" +msgid "Vacation" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Zoekt de lokatie van het telefoonnummer..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Kon dit nummer niet vinden." + +#: ../coreapi/proxy.c:1407 +#, c-format msgid "Could not login as %s" -msgstr "Kon pixmap bestand %s niet vinden" +msgstr "" -#: ../coreapi/callbacks.c:276 -#, fuzzy +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "bezig met ophalen van %s" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." -msgstr "Externe diensten" +msgstr "" -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Externe diensten" +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:352 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:548 +#, c-format msgid "Call with %s is paused." -msgstr "Chat met %s" +msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Oproep beeindigd" +msgstr "" -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:575 +#, c-format msgid "Call answered by %s." msgstr "" -"Oproepen of\n" -"beantwoorden" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Oproep beeindigd." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Gebruiker is bezet." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Gebruiker is tijdelijk niet beschikbaar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "De gebruiker wenst niet gestoord te worden." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Oproep geweigerd." -#: ../coreapi/callbacks.c:544 -msgid "No response." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 -#, fuzzy +#: ../coreapi/callbacks.c:875 msgid "Redirected" -msgstr "Doorgeschakeld naar %s..." - -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Oproep geannuleerd." +msgstr "" -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1009 +#, c-format msgid "Unregistration on %s done." -msgstr "Registratie op %s gelukt." +msgstr "" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:725 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1030 +#, c-format msgid "Registration on %s failed: %s" -msgstr "Registratie op %s mislukt (time-out)." +msgstr "" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format msgid "Authentication token is %s" -msgstr "Authorisatie gegevens" +msgstr "" -#: ../coreapi/linphonecall.c:2124 -#, fuzzy, c-format +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." -msgstr[0] "U heeft %i oproep(en) gemist." -msgstr[1] "U heeft %i oproep(en) gemist." - -#~ msgid "Chat with %s" -#~ msgstr "Chat met %s" - -#, fuzzy -#~ msgid "Choosing a username" -#~ msgstr "gebruikersnaam:" - -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informatie" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Verbinden" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Aan" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Authorisatie gegevens" - -#, fuzzy -#~ msgid "Unmute" -#~ msgstr "Ongelimiteerd" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "Contactlijst" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Audio codecs" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "Audio codecs" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "Informatie" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Linphone - Oproepgeschiedenis" - -#, fuzzy -#~ msgid "_Linphone" -#~ msgstr "linphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Verbonden." - -#, fuzzy -#~ msgid "gtk-ok" -#~ msgstr "Verwijderen" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Verbonden." - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "Contactlijst" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Uw machine lijkt verbonden te zijn met een IPv6 netwerk. Standaard " -#~ "gebruikt linphone altijd IPv4. Wijzig uw configuratie wanneer u IPv6 wilt " -#~ "gebruiken." - -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Inkomende oproep" - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "Codecs" - -#~ msgid "Accept" -#~ msgstr "Accepteren" - -#, fuzzy -#~ msgid "Incoming call from" -#~ msgstr "Inkomende oproep" - -#, fuzzy -#~ msgid "Linphone - Incoming call" -#~ msgstr "Inkomende oproep" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "Audio en video codecs" - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "" -#~ "Helaas, meerdere gelijktijdige gesprekken wordt nog niet ondersteund!" - -#~ msgid "Could not reach destination." -#~ msgstr "Kon bestemming niet bereiken." - -#~ msgid "Request Cancelled." -#~ msgstr "Verzoek geannuleerd." - -#~ msgid "Bad request" -#~ msgstr "Slecht geformuleerd verzoek" - -#~ msgid "User cannot be found at given address." -#~ msgstr "Gebruiker kan niet worden gevonden bij opgegeven adres." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "De externe gebruiker ondersteunt geen van de voorgestelde codecs." - -#~ msgid "Timeout." -#~ msgstr "Time-out." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Externe machine is gevonden, maar verbinding is geweigerd." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "De gebruiker is op dit moment niet bereikbaar, maar hij nodigt u uit om\n" -#~ "op de volgende, alternatieve, manier contact met hem op te nemen:" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Geen NAT/firewall adres opgegeven" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Ongeldig NAT adres '%s' : %s" - -#~ msgid "Gone" -#~ msgstr "Weg" - -#~ msgid "Waiting for Approval" -#~ msgstr "Wachten op accoord" - -#~ msgid "Be Right Back" -#~ msgstr "Kom zo terug" - -#~ msgid "On The Phone" -#~ msgstr "Aan de telefoon" - -#~ msgid "Out To Lunch" -#~ msgstr "Aan het lunchen" - -#~ msgid "Closed" -#~ msgstr "Gesloten" - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adres" - -#, fuzzy -#~ msgid "_View" -#~ msgstr "Video" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "RTP-eigenschappen" - -#, fuzzy -#~ msgid "Show logs" -#~ msgstr "Oproepen weergeven" - -#, fuzzy -#~ msgid "_About" -#~ msgstr "Account" - -#, fuzzy -#~ msgid "Proxy in use" -#~ msgstr "Te gebruiken proxy:" - -#~ msgid "Sound" -#~ msgstr "Geluid" - -#, fuzzy -#~ msgid "Proxy accounts" -#~ msgstr "Te gebruiken proxy:" - -#~ msgid "Go" -#~ msgstr "Ga" - -#~ msgid "Exit" -#~ msgstr "Einde" - -#~ msgid "Shows the address book" -#~ msgstr "Het adresboek weergeven" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Ophangen\n" -#~ "of weigeren" - -#~ msgid "Or chat !" -#~ msgstr "Of chat!" - -#~ msgid "Show more..." -#~ msgstr "Meer weergeven..." - -#~ msgid "Playback level:" -#~ msgstr "Geluidssterkte afspelen:" - -#~ msgid "Recording level:" -#~ msgstr "Geluidssterkte opname:" - -#, fuzzy -#~ msgid "Ring level:" -#~ msgstr "Geluidssterkte opname:" - -#~ msgid "Controls" -#~ msgstr "Functies" - -#~ msgid "Reachable" -#~ msgstr "Bereikbaar" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Bezig; ik ben terug over " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "" -#~ "De andere partij zal worden geïnformeerd dat u over X minuten terug bent" - -#~ msgid "mn" -#~ msgstr "min" - -#~ msgid "Moved temporarily" -#~ msgstr "Tijdelijk verplaatst" - -#~ msgid "Alternative service" -#~ msgstr "Alternatieve dienst" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Aanwezigheid" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Druk op de cijfers om DTMF's te sturen" - -#~ msgid "" -#~ " 3\n" -#~ "def" -#~ msgstr "" -#~ " 3\n" -#~ "def" - -#~ msgid "" -#~ " 2\n" -#~ "abc" -#~ msgstr "" -#~ " 2\n" -#~ "abc" - -#~ msgid "" -#~ " 4\n" -#~ "ghi" -#~ msgstr "" -#~ " 4\n" -#~ "ghi" - -#~ msgid "" -#~ " 5\n" -#~ "jkl" -#~ msgstr "" -#~ " 5\n" -#~ "jkl" - -#~ msgid "" -#~ " 6\n" -#~ "mno" -#~ msgstr "" -#~ " 6\n" -#~ "mno" - -#~ msgid "" -#~ " 7\n" -#~ "pqrs" -#~ msgstr "" -#~ " 7\n" -#~ "pqrs" - -#~ msgid "" -#~ " 8\n" -#~ "tuv" -#~ msgstr "" -#~ " 8\n" -#~ "tuv" - -#~ msgid "" -#~ " 9\n" -#~ "wxyz" -#~ msgstr "" -#~ " 9\n" -#~ "wxyz" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Mijn online vrienden" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "C: 2001\n" -#~ "Gemaakt in antiek Europa" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone is een webtelefoon.\n" -#~ "Het werkt met de SIP- en RTP-protocollen." - -#~ msgid "http://www.linphone.org" -#~ msgstr "http://www.linphone.org" - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Gebruik IPv6 netwerk (wanneer het beschikbaar is)" - -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "" -#~ "Wijzig dit wanneer u op een IPv6 netwerk zit en linphone daarop wilt " -#~ "gebruiken." - -#~ msgid "Global" -#~ msgstr "Globaal" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Deze optie is alleen voor gebruikers in een lokaal netwerk, achter een " -#~ "gateway: Wanneer u niet in deze situatie zit, laat dit dan leeg." - -#~ msgid "No firewall" -#~ msgstr "Geen firewall" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "Gebruik deze STUN server om het firewall adres te achterhalen" - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Geef het firewall adres handmatig op" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "NAT-doorstuur opties (experimenteel)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Aantal gebufferde miliseconden (jitter compensatie):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "RTP-poort voor geluid:" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "" -#~ "Gebruik SIP INFO bericht in plaats van RTP rfc2833 voor DTMF berichten" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 is de aanbevolen manier." - -#~ msgid "Other" -#~ msgstr "Overige" - -#~ msgid "micro" -#~ msgstr "microfoon" - -#~ msgid "Recording source:" -#~ msgstr "Bron voor opname:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "" -#~ "Activeer de echo-onderdrukking (onderdrukt de echo die de andere partij " -#~ "hoort)" - -#~ msgid "Choose file" -#~ msgstr "Kies bestand" - -#~ msgid "Listen" -#~ msgstr "Luisteren" - -#~ msgid "Sound properties" -#~ msgstr "Geluidseigenschappen" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Start SIP gebruikerssysteem op poort:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Het wordt sterk aangeraden om poort 5060 te gebruiken." - -#~ msgid "SIP port" -#~ msgstr "SIP-poort" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Identiteit" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Voeg proxy/registratieserver toe" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "" -#~ "Schoon alle opgeslagen authorisatie gegevens op (gebruikersnaam, " -#~ "wachtwoord...)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Lijst met audio codecs, in volgorde van voorkeur:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Opmerking: Met rood weergegeven codecs zijn niet bruikbaar vanwege het " -#~ "soort internetverbinding dat u heeft" - -#, fuzzy -#~ msgid "No information availlable" -#~ msgstr "Geen informatie beschikbaar" - -#~ msgid "Codec information" -#~ msgstr "Codec informatie" - -#~ msgid "Address Book" -#~ msgstr "Adresboek" - -#~ msgid "Select" -#~ msgstr "Kiezen" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "De gebruiker is op dit moment niet bereikbaar, maar hij nodigt u uit op " -#~ "de volgende, alternatieve, manier contact met hem op te nemen:" - -#~ msgid "None." -#~ msgstr "Geen." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/registratieserver registratieveld" - -#~ msgid "Send registration:" -#~ msgstr "Verstruur registratie:" - -#~ msgid "Name:" -#~ msgstr "Naam:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Aanmeldbeleid:" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Verstruur aanmelding (bekijk de online status van een persoon)" - -#~ msgid "New incoming subscription" -#~ msgstr "Nieuwe inkomende aanmelding" - -#~ msgid "You have received a new subscription..." -#~ msgstr "U heeft een nieuwe aanmelding ontvangen..." - -#~ msgid "Refuse" -#~ msgstr "Weigeren" - -#~ msgid "Authentication required for realm" -#~ msgstr "Authorisatie benodigd voor gebied" - -#~ msgid "userid:" -#~ msgstr "gebruikersID:" - -#~ msgid "realm:" -#~ msgstr "gebied:" - -#~ msgid "Text:" -#~ msgstr "Tekst:" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "De beller vraagt om reservering van bronnen. Gaat u accoord?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "De beller gebruikt geen bron reservatie. \t\t\t\t\tWilt u toch doorgaan?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "Linphone - binnenkomend gesprek van %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "U heeft een aanmelding ontvangen van %s. Dit betekent dat deze persoon " -#~ "een melding wil ontvangen wat betreft uw status (online, bezig, weg...).\n" -#~ "Gaat u accoord?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Authorisatie benodigd voor gebied %s" - -#~ msgid "Wait" -#~ msgstr "Wachten" - -#~ msgid "Deny" -#~ msgstr "Weigeren" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "" -#~ "Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" -#~ "gebruikersnaam@domeinnaam" - -#~ msgid "Stun lookup done..." -#~ msgstr "STUN adres gevonden..." - -#~ msgid "User manual" -#~ msgstr "Handleiding" - -#~ msgid "Ring sound selection" -#~ msgstr "Belgeluid keuze" - -#~ msgid "Communication ended." -#~ msgstr "Communicatie beëindigd." - -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "Extern IP adres van de firewall (in x.x.x.x notatie):" - -#~ msgid "Index" -#~ msgstr "Index" - -#~ msgid "Server address" -#~ msgstr "Serveradres" - -#~ msgid "28k modem" -#~ msgstr "28k modem" - -#~ msgid "56k modem" -#~ msgstr "56k modem" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64k modem (ISDN)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL- of kabelmodem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet of vergelijkbaar" - -#~ msgid "Connection type:" -#~ msgstr "Soort verbinding:" - -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone kon het geluidsapparaat %s niet openen. Controleer of uw " -#~ "geluidskaart goed is ingesteld en werkt." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "Geef hier het SIP-adres op van de persoon die u wilt bellen." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Ophangen\n" -#~ "of weigeren" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. Opnieuw proberen na %i minu(u)t(en)." +msgstr[0] "" +msgstr[1] "" + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/pl.po b/po/pl.po index 419af8a98..27329ea36 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,71 +1,89 @@ -# SIP Telephony Application. -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. -# Simon Morlat , 2001. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: linphone 0.7.1\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2003-08-22 12:50+0200\n" -"Last-Translator: Robert Nasiadek \n" -"Language-Team: Polski \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Polish (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/pl/)\n" +"Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8-bit\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "Połączenie odwołane." +msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:321 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "linia" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" +msgstr[2] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" +msgstr[2] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "" @@ -74,291 +92,314 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" +#: ../gtk/main.c:145 +msgid "Configuration file" msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Połączenie odwołane." +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 -#, fuzzy +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "Rozmowa odrzucona." +msgstr "" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "linia" - -#: ../gtk/main.c:1067 -#, fuzzy -msgid "Call paused" -msgstr "Połączenie odwołane." - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" msgstr "" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:335 -#, fuzzy +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" -msgstr "Książka adresowa" +msgstr "" -#: ../gtk/friendlist.c:509 -#, fuzzy +#: ../gtk/friendlist.c:692 msgid "Presence status" -msgstr "Obecność" +msgstr "" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nazwa" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Połączenie odwołane." +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/friendlist.c:775 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format msgid "Edit contact '%s'" -msgstr "(Brak informacji kontaktowych !)" +msgstr "" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Jakość (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min przepustowość (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parametr" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Włączone" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Wyłączone" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:912 -#, fuzzy +#: ../gtk/propertybox.c:1325 msgid "None" -msgstr "Brak." +msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -382,14 +423,12 @@ msgid "Error communicating with server." msgstr "" #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "Lącze" +msgstr "" #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "Połączony" +msgstr "" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." @@ -401,535 +440,554 @@ msgid "Found %i contact" msgid_plural "Found %i contacts" msgstr[0] "" msgstr[1] "" +msgstr[2] "" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "Podręcznik" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "Twoje hasło:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "Podręcznik" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "Twoje hasło:" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Podręcznik" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Twoje hasło:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:565 +#: ../gtk/setupwizard.c:588 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:570 +#: ../gtk/setupwizard.c:592 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:574 +#: ../gtk/setupwizard.c:596 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:583 +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:588 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "Połączenie odwołane." +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:219 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Połączenie odwołane." - #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -msgid "Direct" +msgid "Going through one or more NATs" msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Dzwonie do " - -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:444 -#, fuzzy -msgid "Incoming call" -msgstr "Dzwonie do " +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:524 +msgid "Incoming call" +msgstr "" + +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Dzwonie do " - -#: ../gtk/incall_view.c:669 -#, fuzzy -msgid "Paused call" -msgstr "Dzwonie do " - -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:699 -#, fuzzy -msgid "Call ended." -msgstr "Rozmowa odrzucona." +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "" + +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Połączenie odwołane." +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Rozmowa odrzucona." - -#: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "Dźwięk" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "Informacja" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "Włączone" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Adres serwera rejestracji sip" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -#, fuzzy -msgid "Add" -msgstr "Adres" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Informacje o kodeku" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "(Brak informacji kontaktowych !)" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:50 -#, fuzzy -msgid "My current identity:" -msgstr "Tożsamość" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Podręcznik" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Twoje hasło:" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "Informacje o kodeku" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:58 -#, fuzzy +#: ../gtk/main.ui.h:2 msgid "Online users" -msgstr "linia" +msgstr "" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:61 -#, fuzzy +#: ../gtk/main.ui.h:5 msgid "Default" -msgstr "Tożsamość" +msgstr "" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "" + #: ../gtk/about.ui.h:1 -#, fuzzy -msgid "About linphone" -msgstr "linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 @@ -949,12 +1007,12 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "Adres" +msgstr "" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" @@ -965,9 +1023,8 @@ msgid "Allow this contact to see my presence status" msgstr "" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "Informacje o kodeku" +msgstr "" #: ../gtk/log.ui.h:1 msgid "Linphone debug window" @@ -978,15 +1035,14 @@ msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Informacje o kodeku" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "" @@ -1007,9 +1063,8 @@ msgid "Linphone - Configure a SIP account" msgstr "" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "Tożsamość" +msgstr "" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" @@ -1020,354 +1075,438 @@ msgid "sip:" msgstr "sip:" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "Adres sip:" +msgstr "" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" +msgid "Registration duration (sec):" msgstr "" #: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Rejestracja powiodła się." +msgid "Contact params (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "Informacje o kodeku" +msgid "Route (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "Kodeki audio" +msgid "a sound card" +msgstr "" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "Kodeki audio" +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" +msgid "Audio codecs" msgstr "" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" +msgid "Video codecs" msgstr "" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" +msgid "C" msgstr "" #: ../gtk/parameters.ui.h:11 -msgid "Settings" +msgid "SIP (UDP)" msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" +msgid "SIP (TCP)" msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" +msgid "SIP (TLS)" msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "Dzwonie do " +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" +msgid "Settings" msgstr "" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "Adres sip:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "Dźwięk" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Dzwonie do " - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "Sieć" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "Źródło nagrywania:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "Użyj tego urządzenia dźwięku:" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "Użyj tego urządzenia dźwięku:" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Użyj tego urządzenia dźwięku:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "Dzwonie do " - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "Dźwięk" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "Dzwonie do " - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:44 -#, fuzzy +#: ../gtk/parameters.ui.h:20 msgid "Your username:" -msgstr "Podręcznik" +msgstr "" -#: ../gtk/parameters.ui.h:45 -#, fuzzy +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "Twój adres sip:" +msgstr "" -#: ../gtk/parameters.ui.h:46 -#, fuzzy +#: ../gtk/parameters.ui.h:22 msgid "Default identity" -msgstr "Tożsamość" +msgstr "" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "" -#: ../gtk/parameters.ui.h:51 -#, fuzzy +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "Dzwonie do " +msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:53 -#, fuzzy +#: ../gtk/parameters.ui.h:29 msgid "Privacy" -msgstr "Dzwonie do " +msgstr "" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Włączony" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Wyłącz" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "" -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "Dzwonie do " +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "" + #: ../gtk/parameters.ui.h:64 -#, fuzzy -msgid "Codecs" -msgstr "Kodeki" +msgid "Fixed" +msgstr "" #: ../gtk/parameters.ui.h:65 -#, fuzzy -msgid "Language" -msgstr "Dzwonie do " +msgid "Video RTP/UDP:" +msgstr "" #: ../gtk/parameters.ui.h:66 -msgid "Show advanced settings" +msgid "Media encryption type" msgstr "" #: ../gtk/parameters.ui.h:67 -#, fuzzy -msgid "Level" -msgstr "Dzwonie do " +msgid "Media encryption is mandatory" +msgstr "" #: ../gtk/parameters.ui.h:68 -#, fuzzy -msgid "User interface" -msgstr "Podręcznik" +msgid "Tunnel" +msgstr "" #: ../gtk/parameters.ui.h:69 -#, fuzzy +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Włączony" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Wyłącz" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "Brak." +msgstr "" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "Informacje o kodeku" +msgstr "" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" msgstr "" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "Dzwonie do " - -#: ../gtk/waiting.ui.h:1 -#, fuzzy -msgid "Linphone" -msgstr "linphone" +msgstr "" #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Sieć" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1390,21 +1529,19 @@ msgid "Call statistics" msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Kodeki audio" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Kodeki audio" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1412,9 +1549,28 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Informacje o kodeku" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" @@ -1432,140 +1588,248 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -#: ../coreapi/linphonecore.c:235 -msgid "completed" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" msgstr "" -#: ../coreapi/linphonecore.c:238 -msgid "missed" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" msgstr "" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." msgstr "" -#: ../coreapi/linphonecore.c:1226 -#, fuzzy +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" -msgstr "Gotowy." - -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -#: ../coreapi/linphonecore.c:2121 -#, fuzzy -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "Nie poprawny adres sip. Adres sip wygląda tak " - -#: ../coreapi/linphonecore.c:2312 -#, fuzzy +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" -msgstr "Dzwonie do " +msgstr "" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "Nie można znaleźć pixmapy: %s" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "dzwoni do Ciebie." +msgstr "" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Połączony" -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "Połączenie odwołane." +msgstr "" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Używasz sterowników ALSA do dźwięku.\n" -"To jest najlepszy wybór. Jednak brakuje modułu emulacji pcm oss,\n" -"a Linphone go wymaga. Uruchom 'modprobe snd-pcm-oss' jako root,\n" -"aby go załadować" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Używasz sterowników ALSA do dźwięku.\n" -"To jest najlepszy wybór. Jednak brakuje modułu emulacji mixera oss,\n" -"a Linphone go wymaga. Uruchom 'modprobe snd-mixer-oss' jako root,\n" -"aby go załadować" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" #: ../coreapi/friend.c:33 -#, fuzzy msgid "Online" -msgstr "linia" +msgstr "" #: ../coreapi/friend.c:36 msgid "Busy" @@ -1580,9 +1844,8 @@ msgid "Away" msgstr "Zajęty" #: ../coreapi/friend.c:45 -#, fuzzy msgid "On the phone" -msgstr "linphone" +msgstr "" #: ../coreapi/friend.c:48 msgid "Out to lunch" @@ -1593,511 +1856,217 @@ msgid "Do not disturb" msgstr "Nie przeszkadzać" #: ../coreapi/friend.c:54 -#, fuzzy msgid "Moved" -msgstr "Kodeki" +msgstr "" #: ../coreapi/friend.c:57 msgid "Using another messaging service" msgstr "" #: ../coreapi/friend.c:60 -#, fuzzy msgid "Offline" -msgstr "linia" +msgstr "" #: ../coreapi/friend.c:63 msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" +msgid "Vacation" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "" + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "" + +#: ../coreapi/proxy.c:1407 +#, c-format msgid "Could not login as %s" -msgstr "Nie można znaleźć pixmapy: %s" +msgstr "" -#: ../coreapi/callbacks.c:276 -#, fuzzy +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." -msgstr "Rejestruje..." +msgstr "" -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Rejestruje..." +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Rozmowa odrzucona." +msgstr "" -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:575 +#, c-format msgid "Call answered by %s." msgstr "" -"Zadzwoń lub\n" -"Odpowiedz" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 -#, fuzzy +#: ../coreapi/callbacks.c:797 msgid "Call terminated." -msgstr "Rozmowa odrzucona." +msgstr "" -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Osoba jest zajęta." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Osoba jest tymczasowo niedostępna." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "Osoba nie chce, aby jej przeszkadzać." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:544 -msgid "No response." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." +#: ../coreapi/callbacks.c:930 +msgid "Call failed." msgstr "" -#: ../coreapi/callbacks.c:606 -#, fuzzy -msgid "Call failed." -msgstr "Połączenie odwołane." - -#: ../coreapi/callbacks.c:701 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1008 +#, c-format msgid "Registration on %s successful." -msgstr "Rejestracja powiodła się." +msgstr "" -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1009 +#, c-format msgid "Unregistration on %s done." -msgstr "Rejestracja powiodła się." +msgstr "" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:725 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1030 +#, c-format msgid "Registration on %s failed: %s" -msgstr "Rejestracja powiodła się." +msgstr "" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format msgid "Authentication token is %s" -msgstr "Informacje o kodeku" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" msgstr[1] "" - -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informacja" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Dzwonie do " - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Włączone" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Informacje o kodeku" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "Dzwonie do " - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Kodeki audio" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "Kodeki audio" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "Informacja" - -#, fuzzy -#~ msgid "_Linphone" -#~ msgstr "linphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Połączony" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Połączony" - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "Dzwonie do " - -#, fuzzy -#~ msgid "_Modes" -#~ msgstr "Kodeki" - -#, fuzzy -#~ msgid "" -#~ "Audio codecs\n" -#~ "Video codecs" -#~ msgstr "Kodeki audio" - -#, fuzzy -#~ msgid "Request Cancelled." -#~ msgstr "Połączenie odwołane." - -#~ msgid "User cannot be found at given address." -#~ msgstr "Osoba nie istnieje pod tym adresem." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "Osoba nie posiada żadnych zaproponowanych kodeków." - -#~ msgid "Timeout." -#~ msgstr "Upłynął limit czasu." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Serwer istnieje, ale odrzucił połączenie." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Użytkownik nie jest dostępny, ale proponuje kontakt poprzez alternatywny " -#~ "adres:" - -#, fuzzy -#~ msgid "Gone" -#~ msgstr "Brak." - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adres" - -#, fuzzy -#~ msgid "Display filters" -#~ msgstr "Wyświetlana nazwa:" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "Właściwości RTP" - -#~ msgid "Sound" -#~ msgstr "Dźwięk" - -#~ msgid "Address book" -#~ msgstr "Książka adresowa" - -#~ msgid "Shows the address book" -#~ msgstr "Pokazuje książkę adresową" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "Show more..." -#~ msgstr "Pokaż więcej" - -#~ msgid "Playback level:" -#~ msgstr "Poziom odtwarzania:" - -#~ msgid "Recording level:" -#~ msgstr "Poziom nagrywania:" - -#, fuzzy -#~ msgid "Ring level:" -#~ msgstr "Poziom nagrywania:" - -#~ msgid "Reachable" -#~ msgstr "Dostępny" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Zajęty, wrócę za " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "Osoba zostanie powiadomiona, że wrócisz za X minut." - -#~ msgid "mn" -#~ msgstr "mn" - -#~ msgid "Moved temporarily" -#~ msgstr "Tymczasowo niedostępny" - -#~ msgid "Alternative service" -#~ msgstr "Alternatywny adres" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Obecność" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Nacisnij cyfry, aby wysłać DTMFy." - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone jest telefonem internetowym.\n" -#~ "Jest kompatybilny z protokolami SIP i RTP." - -#, fuzzy -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Osoba jest tymczasowo niedostępna." - -#, fuzzy -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Ta opcja jest tylko dla osób w sieci prywatnej, znajdujących się za " -#~ "firewallem. Jeżeli nie jesteś w takiej sytuacji, nie zmieniaj tej opcji." - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "Opcje NAT traversal (eksperymentalne)" - -#, fuzzy -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Czas bufora w milisekundach (kompensacja jitter):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "Port RTP dla dźwięku:" - -#~ msgid "micro" -#~ msgstr "mikrofon" - -#~ msgid "Recording source:" -#~ msgstr "Źródło nagrywania:" - -#~ msgid "Sound properties" -#~ msgstr "Właściwości dźwięku" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Uruchom agenta sip na porcie:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Rekomendowane jest użycie portu 5060." - -#~ msgid "SIP port" -#~ msgstr "Port SIP" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Tożsamość" - -#, fuzzy -#~ msgid "Add proxy/registrar" -#~ msgstr "Użyj rejestracji sip" - -#~ msgid "Remote services" -#~ msgstr "Zdalne usługi" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Lista kodeków audio, w kolejności preferencji:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Uwaga: Czerwone kodeki nie mogą być użyte, ze względu na typTwojego " -#~ "połącznia z internetem." - -#, fuzzy -#~ msgid "No information availlable" -#~ msgstr "Brak informacji" - -#~ msgid "Codec information" -#~ msgstr "Informacje o kodeku" - -#~ msgid "Address Book" -#~ msgstr "Książka adresowa" - -#~ msgid "Select" -#~ msgstr "Wybierz" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Użytkownik nie jest dostępny, ale proponuje kontakt poprzez alternatywny " -#~ "adres:" - -#~ msgid "None." -#~ msgstr "Brak." - -#, fuzzy -#~ msgid "Name:" -#~ msgstr "Nazwa" - -#, fuzzy -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "Nie poprawny adres sip. Adres sip wygląda tak " - -#~ msgid "Communication ended." -#~ msgstr "Komunikacja zakończona." - -#, fuzzy -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "Adres IP firewall'u (w notacji kropkowej):" - -#~ msgid "Index" -#~ msgstr "Indeks" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Adres serwera:" - -#~ msgid "28k modem" -#~ msgstr "Modem 28K" - -#~ msgid "56k modem" -#~ msgstr "Modem 56K" - -#~ msgid "64k modem (numeris)" -#~ msgstr "Modem ISDN 64K" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL lub połączenie kablowe" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "LAN lub podobne" - -#~ msgid "Connection type:" -#~ msgstr "Typ połączenia:" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone nie mógł otworzyć urządzenia dźwięku. Sprawdź czy Twoja karta " -#~ "jest dobrze skonfigurowana." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "Tutaj wpisz adres sip osoby, do której chcesz zadzwonić" - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Rozłącz lub\n" -#~ "Odmów" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. Spróbuj za %i minut." - -#, fuzzy -#~ msgid "Timeout..." -#~ msgstr "Upłynął limit czasu." - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "Włącz to, jeżeli chcesz się zarejestrować na zdalnym serwerze." - -#~ msgid "Address of record:" -#~ msgstr "Adres do rejestracji:" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "Hasło do rejestracji. Na niektórych serwerach nie jest wymagane" - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "Użyj tego serwera rejestracji jako zewnętrznego proxy" - -#~ msgid "sip address:" -#~ msgstr "Adres SIP:" - -#~ msgid "Modify" -#~ msgstr "Zmień" - -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "Używasz sterownika i810_audio.\n" -#~ "Ten sterownik ma błędy i nie działa z Linphone\n" -#~ "Sugerujemy zmiane sterowników na ich odpowiedniki ALSA z pakietów Twojej " -#~ "dystrybucji,\n" -#~ "lub ze strony http://www.alsa-project.org/." - -#~ msgid "Unregistration successfull." -#~ msgstr "Derejestracja powiodła się." +msgstr[2] "" + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po index 59cde92ef..bf6aa49b8 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,74 +1,86 @@ -# Portuguese translations for gnomebaker package. -# Copyright (C) 2005 THE linphone COPYRIGHT HOLDER -# This file is distributed under the same license as the linphone package. -# Rafael Caesar Lenzi , 2005. -# -#, fuzzy +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: linphone-1.1.0\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2006-07-11 23:30+0200\n" -"Last-Translator: Rafael Caesar Lenzi \n" -"Language-Team: pt_BR \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/belledonne-" +"communications/linphone-gtk/language/pt_BR/)\n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "Abortado" +msgstr "" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "Perdido" +msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "linha" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" msgstr "" @@ -77,291 +89,314 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:498 -#, fuzzy, c-format -msgid "Call with %s" -msgstr "Bate-papo com %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Linphone - Histórico de chamadas" +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 -#, fuzzy +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "Chamada cancelada." +msgstr "" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 -#, fuzzy +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" -msgstr "linha" - -#: ../gtk/main.c:1067 -#, fuzzy -msgid "Call paused" -msgstr "Abortado" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" msgstr "" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:335 -#, fuzzy -msgid "Add to addressbook" -msgstr "Catálogo de endereços" +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "" + +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Status de presença" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Histórico de chamadas" +msgstr "" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Sala de bate-papo" +msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/friendlist.c:775 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Histórico de chamadas" - -#: ../gtk/friendlist.c:776 +#: ../gtk/friendlist.c:978 #, c-format -msgid "Send text to %s" +msgid "Edit contact '%s'" msgstr "" -#: ../gtk/friendlist.c:777 -#, fuzzy, c-format -msgid "Edit contact '%s'" -msgstr "Edicar informação de contato" - -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Taxa (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Bitrate mínimo (kbits/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parâmetros" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "Ativado" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Desativado" -#: ../gtk/propertybox.c:619 -#, fuzzy +#: ../gtk/propertybox.c:901 msgid "Account" -msgstr "Aceitar" +msgstr "" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "Nenhum" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -385,14 +420,12 @@ msgid "Error communicating with server." msgstr "" #: ../gtk/buddylookup.c:164 -#, fuzzy msgid "Connecting..." -msgstr "Contatando " +msgstr "" #: ../gtk/buddylookup.c:168 -#, fuzzy msgid "Connected" -msgstr "Conectado." +msgstr "" #: ../gtk/buddylookup.c:172 msgid "Receiving data..." @@ -405,534 +438,552 @@ msgid_plural "Found %i contacts" msgstr[0] "" msgstr[1] "" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:91 -#, fuzzy -msgid "Username:" -msgstr "Usuário" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -#, fuzzy -msgid "Password:" -msgstr "Senha:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "Usuário" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "Senha:" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Usuário" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Senha:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:565 +#: ../gtk/setupwizard.c:588 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:570 +#: ../gtk/setupwizard.c:592 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:574 +#: ../gtk/setupwizard.c:596 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:583 +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:588 +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "Histórico de chamadas" +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:219 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Histórico de chamadas" - #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Redirecionado para %s..." +msgid "Going through one or more NATs" +msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 -#, fuzzy +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Contatando " - -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:444 -#, fuzzy -msgid "Incoming call" -msgstr "Camadas recebidas" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:524 +msgid "Incoming call" +msgstr "" + +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Contatando " - -#: ../gtk/incall_view.c:669 -#, fuzzy -msgid "Paused call" -msgstr "Contatando " - -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:699 -#, fuzzy -msgid "Call ended." -msgstr "Chamada cancelada." +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "" + +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Histórico de chamadas" +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Chamada cancelada." - -#: ../gtk/main.ui.h:2 -#, fuzzy -msgid "Send" -msgstr "Som" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -#, fuzzy -msgid "In call" -msgstr "Camadas recebidas" - -#: ../gtk/main.ui.h:15 -#, fuzzy -msgid "Duration" -msgstr "Informações" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -#, fuzzy -msgid "Enable self-view" -msgstr "Ativado" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -#, fuzzy -msgid "Add" -msgstr "Endereço" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Editar" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:46 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Informação de contato" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "Edicar informação de contato" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "Camadas recebidas" - -#: ../gtk/main.ui.h:50 -#, fuzzy -msgid "My current identity:" -msgstr "Identificação SIP:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Usuário" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Senha:" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:54 -#, fuzzy -msgid "Automatically log me in" -msgstr "Adquirir automaticamente um nome de servidor válido." - -#: ../gtk/main.ui.h:55 -#, fuzzy -msgid "Login information" -msgstr "Informação de contato" - -#: ../gtk/main.ui.h:56 -#, fuzzy -msgid "Welcome !" -msgstr "Contatando " - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:58 -#, fuzzy +#: ../gtk/main.ui.h:2 msgid "Online users" -msgstr "linha" +msgstr "" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:61 -#, fuzzy +#: ../gtk/main.ui.h:5 msgid "Default" -msgstr "Identificação SIP:" +msgstr "" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "" + #: ../gtk/about.ui.h:1 -msgid "About linphone" +msgid "About Linphone" msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 @@ -952,12 +1003,12 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 -#, fuzzy msgid "SIP Address" -msgstr "Endereço" +msgstr "" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" @@ -968,9 +1019,8 @@ msgid "Allow this contact to see my presence status" msgstr "" #: ../gtk/contact.ui.h:5 -#, fuzzy msgid "Contact information" -msgstr "Informação de contato" +msgstr "" #: ../gtk/log.ui.h:1 msgid "Linphone debug window" @@ -981,40 +1031,36 @@ msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Autenticação requerida" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "" #: ../gtk/call_logs.ui.h:1 -#, fuzzy msgid "Call history" -msgstr "Linphone - Histórico de chamadas" +msgstr "" #: ../gtk/call_logs.ui.h:2 msgid "Clear all" msgstr "" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "Histórico de chamadas" +msgstr "" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" msgstr "" #: ../gtk/sip_account.ui.h:2 -#, fuzzy msgid "Your SIP identity:" -msgstr "Identificação SIP:" +msgstr "" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" @@ -1025,343 +1071,429 @@ msgid "sip:" msgstr "" #: ../gtk/sip_account.ui.h:5 -#, fuzzy msgid "SIP Proxy address:" -msgstr "Proxy SIP:" +msgstr "" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Rota (opcional):" +msgid "Registration duration (sec):" +msgstr "" #: ../gtk/sip_account.ui.h:8 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Período do registo:" +msgid "Contact params (optional):" +msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 -#, fuzzy -msgid "Publish presence information" -msgstr "Informar informação de presença" +msgid "Route (optional):" +msgstr "Rota (opcional):" #: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "Codec's de áudio" +msgid "a sound card" +msgstr "" #: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "Codec's de áudio" +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" +msgid "Audio codecs" msgstr "" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" +msgid "Video codecs" msgstr "" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" +msgid "C" msgstr "" #: ../gtk/parameters.ui.h:11 -msgid "Settings" +msgid "SIP (UDP)" msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" +msgid "SIP (TCP)" msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" +msgid "SIP (TLS)" msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" +msgid "default" msgstr "" #: ../gtk/parameters.ui.h:15 -#, fuzzy -msgid "Transport" -msgstr "Contatando " +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" +msgid "Settings" msgstr "" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk/parameters.ui.h:25 -#, fuzzy -msgid "Public IP address:" -msgstr "Endereço sip:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use ICE)" -msgstr "" - -#: ../gtk/parameters.ui.h:28 -#, fuzzy -msgid "Stun server:" -msgstr "Dispositivo de som" - -#: ../gtk/parameters.ui.h:29 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Contatando " - -#: ../gtk/parameters.ui.h:30 -#, fuzzy -msgid "Network settings" -msgstr "Rede" - -#: ../gtk/parameters.ui.h:31 -#, fuzzy -msgid "Ring sound:" -msgstr "Som do toque:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "" - -#: ../gtk/parameters.ui.h:33 -#, fuzzy -msgid "Capture device:" -msgstr "Dispositivo de captura de som:" - -#: ../gtk/parameters.ui.h:34 -#, fuzzy -msgid "Ring device:" -msgstr "Dispositivo de som" - -#: ../gtk/parameters.ui.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Dispositivo de som:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "" - -#: ../gtk/parameters.ui.h:37 -#, fuzzy -msgid "Audio" -msgstr "Contatando " - -#: ../gtk/parameters.ui.h:38 -#, fuzzy -msgid "Video input device:" -msgstr "Dispositivo de som" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk/parameters.ui.h:40 -#, fuzzy -msgid "Video" -msgstr "Contatando " - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:44 -#, fuzzy +#: ../gtk/parameters.ui.h:20 msgid "Your username:" -msgstr "Usuário" +msgstr "" -#: ../gtk/parameters.ui.h:45 -#, fuzzy +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "Seu endereço SIP:" +msgstr "" -#: ../gtk/parameters.ui.h:46 -#, fuzzy +#: ../gtk/parameters.ui.h:22 msgid "Default identity" -msgstr "Identificação SIP:" +msgstr "" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Editar" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Remover" -#: ../gtk/parameters.ui.h:51 -#, fuzzy +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "Contatando " +msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:53 -#, fuzzy +#: ../gtk/parameters.ui.h:29 msgid "Privacy" -msgstr "Contatando " +msgstr "" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Ativado" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Desativar" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "" -#: ../gtk/parameters.ui.h:57 -#, fuzzy -msgid "Codecs" -msgstr "Contatando " +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "" + #: ../gtk/parameters.ui.h:64 -#, fuzzy -msgid "Codecs" -msgstr "Codec's de áudio" +msgid "Fixed" +msgstr "" #: ../gtk/parameters.ui.h:65 -#, fuzzy -msgid "Language" -msgstr "Contatando " +msgid "Video RTP/UDP:" +msgstr "" #: ../gtk/parameters.ui.h:66 -msgid "Show advanced settings" +msgid "Media encryption type" msgstr "" #: ../gtk/parameters.ui.h:67 -#, fuzzy -msgid "Level" -msgstr "Contatando " +msgid "Media encryption is mandatory" +msgstr "" #: ../gtk/parameters.ui.h:68 -#, fuzzy -msgid "User interface" -msgstr "Usuário" +msgid "Tunnel" +msgstr "" #: ../gtk/parameters.ui.h:69 -#, fuzzy +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Ativado" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Desativar" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" -msgstr "Nenhum" +msgstr "" #: ../gtk/buddylookup.ui.h:1 -#, fuzzy msgid "Search contacts in directory" -msgstr "Informação de contato" +msgstr "" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" msgstr "" #: ../gtk/buddylookup.ui.h:3 -#, fuzzy msgid "Search somebody" -msgstr "Contatando " - -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" msgstr "" #: ../gtk/waiting.ui.h:2 @@ -1369,9 +1501,8 @@ msgid "Please wait" msgstr "" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Rede" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1390,26 +1521,23 @@ msgid "Set DSCP values (in hexadecimal)" msgstr "" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Histórico de chamadas" +msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Codec's de áudio" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Codec's de áudio" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1417,9 +1545,28 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Informação de contato" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 msgid "Configure VoIP tunnel" @@ -1437,135 +1584,248 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "Abortado" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "Competado" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "Perdido" - -#: ../coreapi/linphonecore.c:243 -#, fuzzy, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s em %sDe: %s\n" -"Para: %s\n" -"Status: %s\n" -"Duração: %i min %i seg\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Chamadas efetuadas" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 -#, fuzzy +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" -msgstr "Pronto." - -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Procurando por telefone de destino..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Não foi possível encontrar este número." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" msgstr "" -#: ../coreapi/linphonecore.c:2312 -#, fuzzy +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "" + +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" -msgstr "Contatando " +msgstr "" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "Não é possível achar arquivo pixmap: %s" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "está chamado você." +msgstr "" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "Abortado" +msgstr "" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" #: ../coreapi/friend.c:33 -#, fuzzy msgid "Online" -msgstr "linha" +msgstr "" #: ../coreapi/friend.c:36 msgid "Busy" @@ -1600,496 +1860,208 @@ msgid "Using another messaging service" msgstr "" #: ../coreapi/friend.c:60 -#, fuzzy msgid "Offline" -msgstr "linha" +msgstr "" #: ../coreapi/friend.c:63 msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" +msgid "Vacation" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1053 -#, fuzzy, c-format +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Procurando por telefone de destino..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Não foi possível encontrar este número." + +#: ../coreapi/proxy.c:1407 +#, c-format msgid "Could not login as %s" -msgstr "Não é possível achar arquivo pixmap: %s" +msgstr "" -#: ../coreapi/callbacks.c:276 -#, fuzzy +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." -msgstr "Serviços remotos" +msgstr "" -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Serviços remotos" +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:352 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:548 +#, c-format msgid "Call with %s is paused." -msgstr "Bate-papo com %s" +msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Chamada cancelada." +msgstr "" -#: ../coreapi/callbacks.c:381 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:575 +#, c-format msgid "Call answered by %s." msgstr "" -"Ligar ou\n" -"atender" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "" -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Usuário está ocupado." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Usuário está temporáriamente indisponível." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "" -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "" -#: ../coreapi/callbacks.c:544 -msgid "No response." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:564 -#, fuzzy +#: ../coreapi/callbacks.c:875 msgid "Redirected" -msgstr "Redirecionado para %s..." - -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Histórico de chamadas" +msgstr "" -#: ../coreapi/callbacks.c:701 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1008 +#, c-format msgid "Registration on %s successful." -msgstr "Registro em %s efetuado." +msgstr "" -#: ../coreapi/callbacks.c:702 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1009 +#, c-format msgid "Unregistration on %s done." -msgstr "Registro em %s efetuado." +msgstr "" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:725 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1030 +#, c-format msgid "Registration on %s failed: %s" -msgstr "Registro falhou (tempo esgotado)." +msgstr "" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format msgid "Authentication token is %s" -msgstr "Informações de autenticação" +msgstr "" -#: ../coreapi/linphonecall.c:2124 -#, fuzzy, c-format +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." -msgstr[0] "Você perdeu %i ligação(ões)." -msgstr[1] "Você perdeu %i ligação(ões)." - -#~ msgid "Chat with %s" -#~ msgstr "Bate-papo com %s" - -#, fuzzy -#~ msgid "Choosing a username" -#~ msgstr "Usuário" - -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informações" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Contatando " - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "Ativado" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Informações de autenticação" - -#, fuzzy -#~ msgid "Contact list" -#~ msgstr "Contatando " - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Codec's de áudio" - -#, fuzzy -#~ msgid "Audio only" -#~ msgstr "Codec's de áudio" - -#, fuzzy -#~ msgid "Duration:" -#~ msgstr "Informações" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Linphone - Histórico de chamadas" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Conectado." - -#, fuzzy -#~ msgid "gtk-ok" -#~ msgstr "Remover" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Conectado." - -#, fuzzy -#~ msgid "Ports" -#~ msgstr "Contatando " - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Sua máquina aparentemente está conectada em uma rede IPv6. Por padrão o " -#~ "linphone sempre usa IPv4. Por favor atualize sua configuração se deseja " -#~ "usar IPv6" - -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Camadas recebidas" - -#~ msgid "Accept" -#~ msgstr "Aceitar" - -#, fuzzy -#~ msgid "Incoming call from" -#~ msgstr "Camadas recebidas" - -#, fuzzy -#~ msgid "Linphone - Incoming call" -#~ msgstr "Camadas recebidas" - -#~ msgid "Could not reach destination." -#~ msgstr "Não foi possível alcançar o detino." - -#~ msgid "Request Cancelled." -#~ msgstr "Pedido cancelado." - -#~ msgid "User cannot be found at given address." -#~ msgstr "Usuário não pode ser encontrado no endereço especificado." - -#~ msgid "Timeout." -#~ msgstr "Tempo esgotado." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Servidor de destino encontrado, porém recusou a conexão." - -#, fuzzy -#~ msgid "Gone" -#~ msgstr "Nenhum" - -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Endereço" - -#, fuzzy -#~ msgid "_Properties" -#~ msgstr "Propriedades RTP:" - -#, fuzzy -#~ msgid "Show logs" -#~ msgstr "Exibir chamadas" - -#, fuzzy -#~ msgid "_About" -#~ msgstr "Aceitar" - -#, fuzzy -#~ msgid "Proxy in use" -#~ msgstr "Proxy à usar:" - -#~ msgid "Sound" -#~ msgstr "Som" - -#, fuzzy -#~ msgid "Proxy accounts" -#~ msgstr "Proxy à usar:" - -#~ msgid "Go" -#~ msgstr "Ir" - -#, fuzzy -#~ msgid "Exit" -#~ msgstr "Editar" - -#~ msgid "Shows the address book" -#~ msgstr "Exibe o catálogo de endereços" - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Desligar\n" -#~ "ou recusar" - -#~ msgid "Or chat !" -#~ msgstr "Ou bate-papo!" - -#~ msgid "Show more..." -#~ msgstr "Exibir mais..." - -#~ msgid "Playback level:" -#~ msgstr "Volume do auto-falante:" - -#~ msgid "Recording level:" -#~ msgstr "Volume do microfone:" - -#, fuzzy -#~ msgid "Ring level:" -#~ msgstr "Volume do microfone:" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Ocupado, volto em " - -#~ msgid "mn" -#~ msgstr "min" - -#~ msgid "Moved temporarily" -#~ msgstr "Movido temporáriamente" - -#~ msgid "Alternative service" -#~ msgstr "Serviço alternativo" - -#~ msgid "Presence" -#~ msgstr "Presença" - -#~ msgid "My online friends" -#~ msgstr "Meus amigos online" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone é um web-fone.\n" -#~ "Ele é compatível com os protocolos SIP e RTP." - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Usar rede IPv6 (se disponível)" - -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "" -#~ "Marque isto se você estiver em uma rede IPv6, e deseja que o linphone " -#~ "este protocolo." - -#, fuzzy -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Esta opção é somente para usuários de uma rede privada, atrás de um " -#~ "gateway. Se você não está nesta situação, deixe isto em braco." - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "Opções de NAT(Experimental)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Número de segundos em bueffer:" - -#~ msgid "RTP port used for audio:" -#~ msgstr "Porta RTP usada para audio:" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "" -#~ "Usar mensagem SIP INFO em vez de RTP rfc2833 para transmissão de DTMF" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 é a maneira recomendada." - -#~ msgid "Other" -#~ msgstr "Outro" - -#~ msgid "micro" -#~ msgstr "microfone" - -#~ msgid "Recording source:" -#~ msgstr "Origem de gravação:" - -#~ msgid "Listen" -#~ msgstr "Escutar" - -#~ msgid "Sound properties" -#~ msgstr "Propriedades de som" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Executar agente sip na porta:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "É altamente recomendavel usar a porta 5060." - -#~ msgid "SIP port" -#~ msgstr "Porta SIP" - -#~ msgid "Identity" -#~ msgstr "Identificação" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Adicionar proxy/registrador" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "" -#~ "Limpar todas as informações de autenticação (nomes de usuário, senha...)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Lista de codecs de audio, em ordem de preferência:" - -#~ msgid "No information availlable" -#~ msgstr "Informações não disponíveis" - -#~ msgid "Codec information" -#~ msgstr "Informações sobre o codec" - -#~ msgid "Address Book" -#~ msgstr "Catálogo de endereços" - -#~ msgid "Select" -#~ msgstr "Selecionar" - -#~ msgid "None." -#~ msgstr "Nenhum" - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Configuração de proxy/registrador" - -#~ msgid "Send registration:" -#~ msgstr "Enviar registro:" - -#~ msgid "Name:" -#~ msgstr "Nome:" - -#~ msgid "Refuse" -#~ msgstr "Recusar" - -#~ msgid "userid:" -#~ msgstr "Identificação:" - -#~ msgid "Text:" -#~ msgstr "Texto:" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "Linphone - Recebendo chamada de %s" - -#~ msgid "User manual" -#~ msgstr "Manual do usuário" - -#~ msgid "Ring sound selection" -#~ msgstr "Seleção de toque" - -#~ msgid "Communication ended." -#~ msgstr "Comunicação encerrada." - -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "Endereço externo do firewall:" - -#~ msgid "Index" -#~ msgstr "Índice" - -#~ msgid "Server address" -#~ msgstr "Endereço do servidor" - -#~ msgid "28k modem" -#~ msgstr "Modem 28k" - -#~ msgid "56k modem" -#~ msgstr "Modem 56l" - -#~ msgid "64k modem (numeris)" -#~ msgstr "Modem 64k" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL ou Cable modem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet ou equivalente" - -#~ msgid "Connection type:" -#~ msgstr "Tipo de conexão:" - -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone não pode abrir dispositivo de áudio %s. Verifique se sua placa " -#~ "de som está configurada e funcionando." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "Escreva aqui o endereço sip da pessoa que você quer ligar." +msgstr[0] "" +msgstr[1] "" + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/ru.po b/po/ru.po index 84e09cb04..48f1f7880 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,380 +1,428 @@ -# SIP Telephony Application. -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. -# Simon Morlat , 2001. +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. # +# Translators: +# AlexL , 2014 +# AlexL , 2014-2015 +# AlexL , 2014 +# Maxim Prokopyev , 2010 +# Simon Morlat , 2001 msgid "" msgstr "" -"Project-Id-Version: linphone 0.7.1\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2010-01-22 18:43+0300\n" -"Last-Translator: Maxim Prokopyev \n" -"Language-Team: Russian \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:40+0000\n" +"Last-Translator: AlexL \n" +"Language-Team: Russian (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/ru/)\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "Звонок %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Послать текст для %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "Последние вызовы (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "—" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "отмененный" +msgstr "Прервано" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "пропущенный" +msgstr "Пропущено" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "Отклонить" +msgstr "Отклонено" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i минута" msgstr[1] "%i минуты" msgstr[2] "%i минут" +msgstr[3] "%i минут" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i секунда" msgstr[1] "%i секунды" msgstr[2] "%i секунд" +msgstr[3] "%i секунд" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -"%s\t%s\tКачество: %s\n" -"%s\t%s %s\t" +"%s\tКачество: %s\n" +"%s\t%s\t" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "н/д" +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" -#: ../gtk/calllogs.c:105 -#, fuzzy, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" -msgstr "" -"%s\t%s\tКачество: %s\n" -"%s\t%s %s\t" - -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "Конференция" -#: ../gtk/conference.c:41 +#: ../gtk/conference.c:46 msgid "Me" -msgstr "Я" +msgstr "Мне" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "" "Вывод некоторой отладочной информации на устройство стандартного вывода во " -"время работы" +"время работы." -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "показать версию и выйти." + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." -msgstr "путь к файлу для записи журнала работы." +msgstr "Путь к файлу для записи логов." -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Запуск linphone с видео отключен." -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." -msgstr "Запускать только в системном лотке, не показывая главное окно" +msgstr "Показывать только в системном лотке, не запуская главное окно." -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" -msgstr "адрес для звонка" +msgstr "Адрес для звонка прямо сейчас." -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "автоматически принимать входящие вызовы, если включено" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -"Укажите рабочий каталог (должен содержать установленные файлы приложения, " -"например: c:\\Program Files\\Linphone)" +"Определить рабочий каталог (относительно каталога установки, например: c:" +"\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Чат с %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Файл конфигурации" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Запустить помощника аудио" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Запустить самотест и выйти при успехе со статусом 0" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s хочет добавить вас в свой контакт-лист.\n" -"Вы разрешаете ему(ей) видеть статус вашего присутствия или хотите добавить " -"его(её) в свой контактный лист?\n" -"Если вы ответите Нет, этот человек будет временно заблокирован." +"%s хочет добавить Вас в его/её список контактов.\n" +"Вы бы добавили его/её в свой список контактов и позволили ему/ей видеть ваш " +"статус присутствия?\n" +"Если вы ответите нет, то этот человек будет временно занесён в чёрный список." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Пожалуйста, введите пароль для пользователя %s\n" -" в домене %s:" +" для реалм (рилм) %s:" -#: ../gtk/main.c:1051 +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Ошибка вызова" +msgstr "Ошибка звонка" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" -msgstr "Разговор окончен" +msgstr "Звонок окончен" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" -msgstr "Входящий вызов" +msgstr "Входящий звонок" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" -msgstr "Ответить" +msgstr "Ответ" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Отклонить" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "Вызов приостановлен" +msgstr "Звонок приостановлен" -#: ../gtk/main.c:1067 +#: ../gtk/main.c:1272 #, c-format -msgid "by %s" -msgstr "со стороны: %s" +msgid "by %s" +msgstr "%s" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s предложил запустить видео. Вы принимаете?" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" -msgstr "Ссылка на сайт" +msgstr "Домашняя страница" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - видео-телефон для интернета" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "Видео интернет телефон" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" -msgstr "%s (По умолчанию)" +msgstr "%s (по умолчанию)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" -msgstr "Мы переведены на %s" +msgstr "Мы передали в %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -"На этом компьютере не обнаружено ни одной звуковой карты.\n" -"Вы не сможете совершать или принимать аудио-вызовы." +"Звуковые карты не были обнаружены на этом компьютере.\n" +"Вы не сможете отправлять или получать аудио звонки." -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "Свободный SIP видео-телефон" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "Привет\n" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "Добавить в адресную книгу" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Статус присутствия" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Имя" -#: ../gtk/friendlist.c:538 +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Вызов" +msgstr "Звонок" -#: ../gtk/friendlist.c:543 -#, fuzzy +#: ../gtk/friendlist.c:727 msgid "Chat" -msgstr "Комната чата" +msgstr "Чат" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Поиск в директории %s" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" -msgstr "Неверный sip-контакт!" +msgstr "Неверный sip контакт!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "Набрать %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Послать текст к %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Редактировать контакт '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Удалить историю чата для '%s'" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Добавить новый контакт из директории '%s'" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Частота (Гц)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Статус" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Минимальный битрейт (кбит/с)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "IP битрейт (КБит/сек)" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Параметры" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" -msgstr "Включен" +msgstr "Разрешён" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" -msgstr "Отключен" +msgstr "Не разрешён" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" -msgstr "Учетная запись" +msgstr "Учётная запись" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Английский" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Французский" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Шведский" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Итальянский" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Испанский" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "Бразильский португальский" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Польский" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Немецкий" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "Японский" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" -msgstr "Нидерландский" +msgstr "Датский" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Венгерский" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Чешский" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "Китайский" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "Традиционный китайский" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "Норвежский" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" -msgstr "" +msgstr "Иврит" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Сербский" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "Арабский" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "Турецкий" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -"Вы должны перезапустить Linphone для того, чтобы языковые настройки вступили " +"Вы должны перезагрузить linphone для того, чтобы языковые настройки вступили " "в силу." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "Нет" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "ZRTP" @@ -384,12 +432,12 @@ msgid "" "A more recent version is availalble from %s.\n" "Would you like to open a browser to download it ?" msgstr "" -"Доступна более новая версия с %s\n" +"Доступна новая версия с %s.\n" "Открыть браузер для загрузки?" #: ../gtk/update.c:91 msgid "You are running the lastest version." -msgstr "Вы используете самую последнюю версию." +msgstr "Вы работаете с последней версией." #: ../gtk/buddylookup.c:85 msgid "Firstname, Lastname" @@ -418,525 +466,576 @@ msgid_plural "Found %i contacts" msgstr[0] "Найден %i контакт" msgstr[1] "Найдено %i контакта" msgstr[2] "Найдено %i контактов" +msgstr[3] "Найдено %i контактов" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" "Добро пожаловать!\n" -"Этот помощник поможет вам использовать учётную запись SIP для ваших звонков." +"Этот ассистент поможет вам использовать SIP аккаунт для ваших звонков." -#: ../gtk/setupwizard.c:42 +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" msgstr "Создать учётную запись на linphone.org" -#: ../gtk/setupwizard.c:43 +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" msgstr "" -"У меня уже есть учётная запись на linphone.org и я хочу использовать её" +"Я уже имею учётную запись на linphone.org и только хочу использовать её" -#: ../gtk/setupwizard.c:44 +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "У меня уже есть учётная запись SIP и я хочу использовать её" +msgstr "Я уже имею учётную запись sip и только хочу использовать её" -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" -msgstr "Введите ваше имя пользователя на linphone.org" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Я хочу указать удалённую конфигурацию URI" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "Имя пользователя:" +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "Введите вашу информацию об учётной записи" -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "Пароль:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" -msgstr "Введите информацию о вашей учётной записи" - -#: ../gtk/setupwizard.c:120 +#: ../gtk/setupwizard.c:221 msgid "Username*" msgstr "Имя пользователя*" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:222 msgid "Password*" msgstr "Пароль*" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "Домен*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "Прокси" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Введите ваше имя пользователя для linphone.org" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Имя пользователя:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Пароль:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "(*) Обязательные поля" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" msgstr "Имя пользователя: (*)" -#: ../gtk/setupwizard.c:300 +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" msgstr "Пароль: (*)" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" -msgstr "Email: (*)" +msgstr "Электронная почта: (*)" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "Подтвердите ваш пароль: (*)" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." -msgstr "" -"Ошибка, непроверенная учётная запись, имя пользователя уже существует или " -"сервер недоступен.\n" -"Вернитесь и попробуйте ещё раз." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Информировать об обновлениях linphone" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Спасибо! Учетная запись успешно настроена и готова к использованию." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "Ваша учётная запись создаётся, пожалуйста, подождите." -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -"Пожалуйста, подтвердите свою учётную запись, пройдя по ссылке, которую мы " -"только что выслали вам на электронную почту.\n" -"Затем вернитесь и нажмите на кнопку Далее." +"Пожалуйста, подтвердите вашу учётную запись, щёлкнув на ссылку, которую вы " +"только\n" +"что получили по электронной почте. Затем вернитесь сюда и нажмите кнопку " +"Далее." -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" +"Проверяется действительность вашей учётной записи, пожалуйста, подождите." + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Ошибка, учётная запись не подтверждена, имя пользователя уже используется " +"или\n" +"сервер недоступен. Пожалуйста, зайдите снова и попробуйте ещё раз." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Спасибо! Учётная запись успешно настроена и готова к использованию." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "Помощник настройки учётной записи SIP" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Добро пожаловать в помощник настройки учётной записи" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/setupwizard.c:565 -msgid "Configure your account (step 1/1)" -msgstr "Настройте свою учётную запись (шаг 1/1)" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "Введите ваше имя пользователя SIP (шаг 1/1)" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "Введи информация об учётной записи (шаг 1/2)" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "Проверка (шаг 2/2)" - #: ../gtk/setupwizard.c:588 +msgid "Configure your account (step 1/1)" +msgstr "Настроить вашу учётную запись (шаг 1/1)" + +#: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "Введите ваше sip имя пользователя (шаг 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Введите информацию об учётной записи (шаг 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "Создание учётной записи в прогрессе" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Подтверждение (шаг 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "Проверка действительности учётной записи в прогрессе" + +#: ../gtk/setupwizard.c:614 msgid "Error" msgstr "Ошибка" -#: ../gtk/setupwizard.c:592 +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "Завершение" +msgstr "Прерывание" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" -msgstr "Вызов #%i" +msgstr "Звонок #%i" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" -msgstr "Перевести на #%i с %s" +msgstr "Передача позвонить #%i с %s" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "Не найден" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" -msgstr "" +msgstr "Не используется" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "ICE фильтр" +msgid "ICE not activated" +msgstr "ICE не активировано" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" -msgstr "" +msgid "ICE failed" +msgstr "Неудача ICE" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" -msgstr "" +msgid "ICE in progress" +msgstr "ICE в прогрессе" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Переадресован" +msgid "Going through one or more NATs" +msgstr "Пройти через один или несколько NAT" #: ../gtk/incall_view.c:229 -msgid "Through a relay server" -msgstr "" +msgid "Direct" +msgstr "Напрямую" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Через сервер ретрансляции" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "uPnP не активировано" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "uPnP в прогрессе" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "uPnp недоступен" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "uPnP выполняется" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "Неудача uPnP" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Напрямую или через сервер" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"загрузка: %f\n" +"отдача: %f (КБит/сек)" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f кадр/сек" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f секунд" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" -msgstr "" +msgstr "Повесить трубку" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." -msgstr "Вызов..." +msgstr "Звоним..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Входящий вызов" +msgstr "Входящий звонок" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" -msgstr "хорошее" +msgstr "хороший" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" -msgstr "среднее" +msgstr "средний" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" -msgstr "плохое" +msgstr "плохой" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" -msgstr "очень плохое" +msgstr "очень плохой" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" -msgstr "слишком плохое" +msgstr "совсем плохой" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" -msgstr "недоступно" +msgstr "недоступен" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" -msgstr "Защищено SRTP" +msgstr "Защищённые с помощью SRTP" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "Защищённые с помощью DTLS" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "Защищено ZRTP - [токен: %s]" +msgstr "Защищённые с помощью ZRTP - [знак аутентификации: %s]" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" -msgstr "Не проверен" +msgstr "Установить непроверенный" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" -msgstr "Проверен" +msgstr "Установить проверенный" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "В конференции" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "Соединен с" +msgstr "Звоним" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "Приостановленный вызов" +msgstr "Звонок приостановлен" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i::%02i::%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Звонок закончен." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" -msgstr "" +msgstr "Передача в прогрессе" -#: ../gtk/incall_view.c:734 -#, fuzzy +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "Перевести" +msgstr "Передача завершена." -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Перевести" +msgstr "Передача неудачна." -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "Продолжить" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "Пауза" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Записывается в\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Пауза)" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" -msgstr "Введите информацию для входа %s" +msgstr "Пожалуйста, введите информацию для входа %s:" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "получение от %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Загрузка удалённой конфигурации из %s неудачна." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Голос не обнаружен" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Слишком тихо" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "Хорошо" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Слишком громко" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Вы слышали 3 сигнала?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Настройки звука не найдены" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Не удаётся запустить системное управление звуком" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Добро пожаловать!\n" +"Этот ассистент поможет вам настроить настройки аудио для Linphone." + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Устройство захвата" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "Уровень записи" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Нет голоса" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Системные настройки звука" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Устройство воспроизведения" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Проиграть три сигнала" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Нажмите кнопку записи и скажите несколько слов" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Прослушайте ваш записанный голос" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Запись" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Воспроизведение" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Давайте сейчас запустим linphone" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Помощник аудио" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Помощник аудио" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Калибровка усиления микрофона" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Калибровка громкости динамика" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Записать и проиграть" #: ../gtk/main.ui.h:1 -msgid "Callee name" -msgstr "Имя вызываемого абонента" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Отправить" - -#: ../gtk/main.ui.h:3 -#, fuzzy -msgid "End conference" -msgstr "В конференции" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "метка" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "Перевести" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "Вызов" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Продолжительность" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "Уровень качества звонка" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_Настройки" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Включить своё видео" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "_Помощь" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "Показать окно отладки" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "_Домашняя страница" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "Проверить _Обновления" - -#: ../gtk/main.ui.h:24 -msgid "Account assistant" -msgstr "Помощник настройки учётной записи" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "SIP-адрес или номер телефона:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "Совершить новый вызов" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Добавить" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Редактировать" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Поиск" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Добавить контакты из директории" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "Добавить контакт" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "Номеронабиратель" - -#: ../gtk/main.ui.h:49 -msgid "Recent calls" -msgstr "Недавние вызовы" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Мой текущий идентификатор:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Имя пользователя" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Пароль" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Интернет-соединение:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Входить автоматически" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Информация для входа" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Добро пожаловать!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "Все пользователи" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "Пользователи в сети" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" -msgstr "Оптоволокно" +msgstr "Оптоволоконный канал" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "По умолчанию" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" -msgstr "" +msgstr "Удалить" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Опции" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "Установить конфигурацию URI" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Всегда запускать видео" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Показать окно видео" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Помощь" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Показать окно отладки" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Домашняя страница" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Проверить _обновления" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Помощник учётной записи" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIP-адрес или номер телефона:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Начать новый звонок" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Контакты" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Поиск" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Добавить контакты из директории" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Добавить контакт" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Последние звонки" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Мой текущий идентификатор:" #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "Про linphone" +msgid "About Linphone" +msgstr "О Linphone" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Belledonne Communications, 2010\n" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." -msgstr "" -"Видео-телефон для интернета, использующий стандартный протокол SIP (rfc3261)." +msgstr "Интернет видео телефон, использующий стандарт протокола SIP (rfc3261)." #: ../gtk/about.ui.h:5 msgid "" @@ -951,6 +1050,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -963,18 +1063,19 @@ msgstr "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" -msgstr "SIP-адрес" +msgstr "SIP адрес" #: ../gtk/contact.ui.h:3 msgid "Show this contact presence status" -msgstr "Показывать статус присутствия этого контакта" +msgstr "Показывать этому контакту статус присутствия" #: ../gtk/contact.ui.h:4 msgid "Allow this contact to see my presence status" -msgstr "Разрешить этому контакту видеть статус моего присутствия" +msgstr "Разрешить этому контакту видеть мой статус присутствия" #: ../gtk/contact.ui.h:5 msgid "Contact information" @@ -986,19 +1087,19 @@ msgstr "Окно отладки linphone" #: ../gtk/log.ui.h:2 msgid "Scroll to end" -msgstr "Прокрутите до конца" +msgstr "Прокрутка в конец" #: ../gtk/password.ui.h:1 msgid "Linphone - Authentication required" -msgstr "Linphone - Необходима аутентификация" +msgstr "Linphone - необходима регистрация" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" -msgstr "Введите пароль" +msgstr "Введите пароль для домена" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" -msgstr "UserID" +msgstr "Идентификатор пользователя" #: ../gtk/call_logs.ui.h:1 msgid "Call history" @@ -1010,19 +1111,19 @@ msgstr "Очистить всё" #: ../gtk/call_logs.ui.h:3 msgid "Call back" -msgstr "Перезвонить" +msgstr "Позвонить повторно" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Настроить учётную запись SIP" +msgstr "Linphone - настроить учётную запись SIP" #: ../gtk/sip_account.ui.h:2 msgid "Your SIP identity:" -msgstr "Идентификатор SIP:" +msgstr "Ваш идентификатор SIP:" #: ../gtk/sip_account.ui.h:3 msgid "Looks like sip:@" -msgstr "Похоже на sip:@" +msgstr "Выглядит как sip:<имя_пользователя>@<домен>" #: ../gtk/sip_account.ui.h:4 msgid "sip:" @@ -1030,305 +1131,425 @@ msgstr "sip:" #: ../gtk/sip_account.ui.h:5 msgid "SIP Proxy address:" -msgstr "Адрес SIP-прокси:" +msgstr "Адрес SIP прокси:" #: ../gtk/sip_account.ui.h:6 msgid "Looks like sip:" -msgstr "Похоже на sip:" +msgstr "Выглядит как sip:<прокси имя_хоста>" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Маршрут (необязательно):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Продолжительность регистрации (сек):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Параметры контакта (опционально):" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" -msgstr "Зарегистрироваться" +msgid "AVPF regular RTCP interval (sec):" +msgstr "AVPF постоянный интервал RTCP (сек):" #: ../gtk/sip_account.ui.h:10 -msgid "Publish presence information" -msgstr "Опубликовывать статус присутствия" +msgid "Route (optional):" +msgstr "Маршрут (опционально):" #: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Транспорт" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Регистрация" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "Опубликовать статус присутствия" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Разрешить AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Настроить учётную запись SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "аноним" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "звуковая карта по умолчанию" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "звуковая карта" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" -msgstr "камера по умолчаию" +msgstr "камера по умолчанию" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Аудио кодеки" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Видео кодеки" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "По умолчанию" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "много кадров в секунду" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "Пользовательский" + +#: ../gtk/parameters.ui.h:17 msgid "Settings" msgstr "Настройки" -#: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Установить MTU:" - -#: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Отправлять DTFM как SIP Info" - -#: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Использовать IPv6 вместо IPv4" - -#: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Транспорт" - -#: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" -msgstr "Тип шифрования потока" - -#: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "Туннель" - #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "Видео RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "Аудио RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "Протокол и порты" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Прямое подключение к Интернету" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "За NAT / брандмауэром (укажите IP-адрес шлюза ниже)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Внешний IP-адрес:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "За NAT / брандмауэром (использовать STUN)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "За NAT / брандмауэром (использовать STUN)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "Сервер STUN:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT и брандмауэр" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Настройки сети" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Звук звонка:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "Специальное устройство ALSA (необязательно):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Устройство захвата:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Устройство звонка:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Устройство воспроизведения:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Включить подавление эхо" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Звук" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Устройство захвата видео:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Предпочтительное разрешение видео:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Видео" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Настройки мультимедиа" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -"Эта секция устанавливает ваш SIP-адрес, когда вы не используете SIP-аккаунт" +"Эта секция определяет ваш SIP адрес, когда вы не используете учётную запись " +"SIP" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" -msgstr "Отображаемое имя (напр.: Иван Сидоров):" +msgstr "Отображаемое имя (например: Иван Сидоров):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" -msgstr "Имя пользователя:" +msgstr "Ваше имя пользователя:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" -msgstr "Результирующий SIP-адрес:" +msgstr "Ваш результирующий SIP адрес:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Идентификатор по умолчанию" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "Мастер" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Добавить" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Редактировать" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Удалить" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" -msgstr "Учетные записи прокси" +msgstr "Учётные записи" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Стереть все пароли" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" -msgstr "Конфеденциальность" +msgstr "Секретность" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "Автоматический ответ при получении звонка" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "Задержка перед ответом (мс)" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "Автоответ" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Управление учётными записями SIP" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Включить" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Мелодия звонка:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Выключить" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "Специальное устройство ALSA (опционально)" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Кодеки" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Устройство захвата:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Устройство звонка:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Устройство воспроизведения:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Разрешить подавление эха" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Аудио" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Устройство для вывода видео:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "Предпочтительное разрешение видео:" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Метод вывода видео:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Показать предпросмотр с камеры" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "Предустановки видео:" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "Предпочтительная частота кадров:" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 означает \"безлимитный\"" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Видео" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" -msgstr "Ограничение исходящего потока в кбит/сек:" +msgstr "Ограничение исходящего потока КБит/сек:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" -msgstr "Ограничение скорости входящего потока в кбит/сек" +msgstr "Ограничение скорости входящего потока КБит/сек:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" -msgstr "Включить адаптивный контроль скорости" +msgstr "Разрешить адаптивное управление скоростью" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -"Адаптивное управление скоростью - это техника, позволяющая динамически " -"определять доступную пропускную способность сети во время звонка." +"Адаптивное управление скоростью - это технология динамического угадывания " +"доступной пропускной способности во время звонка." + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "Пропускная способность" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Настройки мультимедиа" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Установить MTU (максимально передаваемый блок):" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Отправлять DTFM как SIP-информацию" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "Разрешить IPv6" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Транспорт" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "Порт SIP/UDP" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Случайно" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "Порт SIP/TCP" #: ../gtk/parameters.ui.h:63 -msgid "Bandwidth control" -msgstr "Управление скоростью сети" +msgid "Audio RTP/UDP:" +msgstr "Аудио RTP/UDP:" #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Фиксированный" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "Видео RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Тип медиа-шифрования" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Медиа-шифрование обязательно" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Тунель" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "Поля DSCP" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Сетевые протоколы и порты" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Прямое подключение к интернет" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "За NAT / брандмауэром (указать IP шлюза)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "За NAT / брандмауэром (использовать STUN)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "За NAT / брандмауэром (использовать ICE)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "За NAT / брандмауэром (использовать uPnP)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Выделенный (публичный) IP-адрес:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN сервер:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT и брандмауэр" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Настройки сети" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Разрешить" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Выключить" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "Аудио кодеки" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "Видео кодеки" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Кодеки" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Язык" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" -msgstr "Показывать расширенные настройки" +msgstr "Показать дополнительные настройки" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Уровень" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" -msgstr "Интерфейс пользователя" +msgstr "Пользовательский интерфейс" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Адрес сервера:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Метод аутентификации:" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "Установка учётной записи LDAP" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Готово" #: ../gtk/buddylookup.ui.h:1 msgid "Search contacts in directory" -msgstr "Искать контакты в директории" +msgstr "Поиск контактов в директории" #: ../gtk/buddylookup.ui.h:2 msgid "Add to my list" @@ -1336,221 +1557,340 @@ msgstr "Добавить в мой список" #: ../gtk/buddylookup.ui.h:3 msgid "Search somebody" -msgstr "Найти кого-нибудь" - -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" +msgstr "Поиск кого-нибудь" #: ../gtk/waiting.ui.h:2 msgid "Please wait" -msgstr "Подождите" +msgstr "Пожалуйста, подождите" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Настройки" +msgid "DSCP settings" +msgstr "Настройки DSCP" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "SIP" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "Аудио RTP/UDP:" +msgstr "Аудио поток RTP" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "Видео RTP/UDP:" +msgstr "Видео поток RTP" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "Установить значения DSCP (в шестнадцатеричном формате)" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Звонк %s" +msgstr "Вызов статистики" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "Аудио кодеки" +msgstr "Аудио кодек" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "Видео кодеки" +msgstr "Видео кодек" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Использование пропускной способности аудио IP" #: ../gtk/call_statistics.ui.h:5 -#, fuzzy -msgid "Media connectivity" -msgstr "Тип шифрования потока" +msgid "Audio Media connectivity" +msgstr "Подключение медиа-аудио" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Использование пропускной способности видео IP" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "Подключение медиа-видео" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Округлять время в действии" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Получено разрешение видео" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Разрешение видео отправлено" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "Профиль RTP" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Контактная информация" +msgstr "Вызов статистики и информации" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Настроить учётную запись SIP" +msgstr "Настроить тунель VoIP" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Хост" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" -msgstr "" +msgstr "Порт" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Конфигурировать тунель" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Имя пользователя" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Пароль" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "Конфигурировать http прокси (опционально)" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "отмененный" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "Настройки LDAP" -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "завершённый" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "Использовать соединение TLS" -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "пропущенный" +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Ещё недоступно" -#: ../coreapi/linphonecore.c:243 -#, c-format +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "Соединение" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "Привязать DN" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Имя для аутентификации" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Реалм (рилм)" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "Базовый объект:" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "Фильтр (%s для имени):" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "Атрибут имени:" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "Атрибут SIP-адреса:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "Атрибуты для запроса:" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "Поиск" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "Таймаут для поиска:" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "Максимум результатов:" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "Следовать алиасам" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "Разное" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "АНОНИМ" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "ПРОСТОЙ" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "ДАЙДЖЕСТ-MD5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "NTLM" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "Указание удалённой конфигурации URI" + +#: ../gtk/config-uri.ui.h:2 msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " msgstr "" -"%s в %s\n" -"От: %s\n" -"Кому: %s\n" -"Статус: %s\n" -"Длительность: %i мин %i сек\n" +"Этот диалог позволяет установить HTTP или HTTPS адрес, когда конфигурация " +"будет получена при запуске.\n" +"Пожалуйста, введите или измените настройки URI ниже. После нажатия OK " +"linphone автоматически перезагрузится чтобы получить и учесть новую " +"конфигурацию в учётной записи." -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Исходящий звонок" +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Конфигурирование..." -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "Пожалуйста, подождите пока получается конфигурация с сервера..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Отправить" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Имя вызываемого" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Конец конференции" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Записать этот вызов в аудио файл" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Видео" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Без звука" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Передача" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "Входящий звонок" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Продолжительность" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Вызвать рейтинг качества" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Интернет-соединение:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Входить автоматически" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Информация для входа" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Добро пожаловать!" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Готов" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Поиск адреса для телефонного номера..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Конфигурирование" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Не могу найти этот номер." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Не могу опознать sip адрес. SIP-URL обычно выглядит как sip:" -"username@domainname" - -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Соединение" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "Не удалось позвонить" +msgstr "Невозможно позвонить" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" -msgstr "Извините, мы превысили максимальное количество одновременных вызовов" +msgstr "" +"К сожалению, мы достигли максимального количества одновременных звонков" -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "пытается связаться с вами" +msgstr "контактирует с вами" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." -msgstr " и ответил автоответчик." +msgstr "и спросил автоматический ответ." -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "." - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." -msgstr "Изменение параметров вызова..." +msgstr "Изменение параметров звонка..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Соединён." -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "Вызов отменён" +msgstr "Звонок отменён" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "Не удалось приостановить вызов" +msgstr "Невозможно приостановить звонок" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "Приостановление текущего вызова..." +msgstr "Приостановка текущего звонка..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Ваш компьютер использует звуковой драйвер ALSA.\n" -"Это лучший выбор. Однако, модуль эмуляции PCM OSS\n" -"не найден, а он нужен для linphone.\n" -"Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-pcm-" -"oss', чтобы загрузить его." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Ваш компьютер использует звуковой драйвер ALSA.\n" -"Это лучший выбор. Однако, модуль микшера OSS\n" -"не найден, а он нужен для linphone.\n" -"Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-pcm-" -"oss' чтобы загрузить его." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." -msgstr "Идет поиск Stun..." +msgstr "Идет поиск STUN..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "Сбор локальных кандидатов ICE в прогрессе..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1582,7 +1922,7 @@ msgstr "Не беспокоить" #: ../coreapi/friend.c:54 msgid "Moved" -msgstr "Отошел" +msgstr "Отошёл" #: ../coreapi/friend.c:57 msgid "Using another messaging service" @@ -1597,1089 +1937,212 @@ msgid "Pending" msgstr "В ожидании" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Неизвестная ошибка" +msgid "Vacation" +msgstr "Отдых" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Неизвестный статус" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -"Введеный адрес SIP-прокси является недействительным, он должен выглядеть как " +"Введённый SIP-адрес прокси является недействительным, он должен начинаться с " "\"sip:имя_хоста\"" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -"Неверные параметры идентификации SIP.\n" -"Они должны выглядеть как sip:username@proxydomain, например such as sip:" +"Неверные параметры для sip идентификации\n" +"Должно выглядеть как sip:имя_пользователя@домен_прокси, как например, sip:" "alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Поиск назначения для телефонного номера.." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Не получилось принять решение по этому номеру." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" -msgstr "Невозможно зайти как %s" +msgstr "Невозможно зайти как: %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "получение от %s" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." -msgstr "Абонент вызывается." +msgstr "Дистанционный звонок." -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Абонент вызывается..." +msgstr "Дистанционный звонок..." -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." -msgstr "Гудки." +msgstr "Предответное проключение." -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." -msgstr "Вызов %s приостановлен." +msgstr "Звонок с %s приостановлен." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." -msgstr "Вызов отвечен %s - в ожидании." +msgstr "На звонок ответил %s - на удержании." -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Разговор продолжен." +msgstr "Звонок возобновлён." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." -msgstr "Вызов отвечен %s." +msgstr "На звонок ответил %s." -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." -msgstr "Несовместимо, проверьте кодеки..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "Несовместимость, проверьте кодеки или параметры безопасности..." -#: ../coreapi/callbacks.c:437 -#, fuzzy +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Несовместимость медиа-параметров." + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." -msgstr "Наш вызов продолжен..." +msgstr "Мы возобновили." -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." -msgstr "" +msgstr "Мы приостановлены другой стороной." -#: ../coreapi/callbacks.c:452 -#, fuzzy +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." -msgstr "Вызов обновлён вызываемым абонентом..." +msgstr "Звонок был дистанционно обновлён." -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Звонок прерван." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Пользователь занят." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Пользователь временно недоступен." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." -msgstr "Абонент не хочет отвечать." +msgstr "Пользователь не хочет чтобы его беспокоили." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Звонок отклонён." -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "Нет ответа." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "Таймаут запроса." -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "Ошибка протокола." - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "Переадресован" -#: ../coreapi/callbacks.c:600 -#, fuzzy -msgid "Incompatible media parameters." -msgstr "Несовместимо, проверьте кодеки..." - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Не удалось совершить вызов." +msgstr "Звонок не удался." -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Регистрация на %s прошла успешно." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Отмена регистрации на %s завершена." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "время ожидания истекло" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Регистрация на %s не удалась: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Сервис недоступен, повтор" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 #, c-format msgid "Authentication token is %s" -msgstr "Аутентификационный токен: %s" +msgstr "Маркер проверки подлинности: %s" -#: ../coreapi/linphonecall.c:2124 +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "Параметры звонка были успешно изменены." + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." -msgstr[0] "У вас пропущен %i звонок." -msgstr[1] "У вас пропущено %i звонка." -msgstr[2] "У вас пропущено %i звонков." - -#~ msgid "Chat with %s" -#~ msgstr "Чат с %s" - -#~ msgid "Enable video" -#~ msgstr "Включить видео" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "Введите имя пользователя, номер телефона или полный SIP-адрес" - -#~ msgid "Lookup:" -#~ msgstr "Поиск:" - -#~ msgid "in" -#~ msgstr "в" - -#~ msgid "Contacts" -#~ msgstr "Контакты" - -#~ msgid "edit" -#~ msgstr "редактировать" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Регистрация в \n" -#~ "виртуальной сети FONICS!" - -#~ msgid "We are being paused..." -#~ msgstr "Мы на паузе..." - -#~ msgid "No common codecs" -#~ msgstr "Нет общих кодеков" - -#~ msgid "Authentication failure" -#~ msgstr "Ошибка аутентификации" - -#~ msgid "Please choose a username:" -#~ msgstr "Выберите имя пользователя:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Проверка доступности '%s'..." - -#~ msgid "Please wait..." -#~ msgstr "Ждите..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "Такое имя пользователя уже существует. Попробуйте выбрать другое." - -#~ msgid "Ok !" -#~ msgstr "Ок!" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Проблемы со связью, повторите попытку позже." - -#~ msgid "Choosing a username" -#~ msgstr "Имя пользователя:" - -#~ msgid "Verifying" -#~ msgstr "Проверка" - -#~ msgid "Confirmation" -#~ msgstr "Подтверждение" - -#~ msgid "Creating your account" -#~ msgstr "Создание аккаунта" - -#~ msgid "Now ready !" -#~ msgstr "Готово !" - -#, fuzzy -#~ msgid "Unmute" -#~ msgstr "Безлимитный" - -#~ msgid "Contact list" -#~ msgstr "Список контактов" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Аудио и Видео" - -#~ msgid "Audio only" -#~ msgstr "Только Аудио" - -#~ msgid "Duration:" -#~ msgstr "Продолжительность:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "История звонков" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "gtk-cancel" -#~ msgstr "Отмена" - -#~ msgid "gtk-ok" -#~ msgstr "Ок" - -#~ msgid "Register at startup" -#~ msgstr "Регистрация при запуске" - -#~ msgid "gtk-close" -#~ msgstr "Закрыть" - -#~ msgid "Ports" -#~ msgstr "Порты" - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw кодировщик" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw декодер" - -#~ msgid "Alsa sound source" -#~ msgstr "Источник ALSA" - -#~ msgid "DTMF generator" -#~ msgstr "Генератор DTMF" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "Кодек GSM full-rate" - -#~ msgid "The GSM codec" -#~ msgstr "Кодек GSM" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Фильтр конференций" - -#, fuzzy -#~ msgid "Echo canceller using speex library" -#~ msgstr "Подавление эхо с использование библиотеки speex" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "Фильтр, перенаправляющий входящий поток в несколько потоков вывода." - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "Theora видео декодер с xiph.org" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Theora видео декодер с xiph.org" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw кодировщик" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw декодер" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "H.263 декодер ( использует ffmpeg )" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "MPEG4 декодер ( использует ffmpeg )" - -#, fuzzy -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "MJPEG декодер ( использует ffmpeg )" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "MJPEG декодер ( использует ffmpeg )" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "snow декодер ( использует ffmpeg )" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "H.263 видео-кодировщик ( использует ffmpeg )" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "H.263 видео-кодировщик ( использует ffmpeg ). Совместим с RFC2190" - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "MPEG4 видео-кодировщик ( использует ffmpeg )." - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "snow видео-кодировщик ( использует ffmpeg )." - -#, fuzzy -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "MJPEG декодер ( использует ffmpeg )" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "H.263 видео-кодировщик ( использует ffmpeg ). Совместим с RFC2190" - -#, fuzzy -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "MJPEG декодер ( использует ffmpeg )" - -#, fuzzy -#~ msgid "Inter ticker communication filter." -#~ msgstr "Ошибка связи с сервером" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Ваш компьютер подключен по IPv6. Linphone по умолчанию использует IPv4. " -#~ "Пожалуйста, обновите настройки если хотите использовать IPv6." - -#~ msgid "Incoming call from %s" -#~ msgstr "Входящий звонок от %s" - -#~ msgid "Assistant" -#~ msgstr "Помощник" - -#, fuzzy -#~ msgid "Show debug messages" -#~ msgstr "Показать окно ошибок" - -#~ msgid "Start call" -#~ msgstr "Вызов" - -#~ msgid "_Modes" -#~ msgstr "_Режимы" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "Создан Simon Morlat\n" - -#~ msgid "Accept" -#~ msgstr "Принять" - -#~ msgid "Incoming call from" -#~ msgstr "Входящий вызов от" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone - Входящий вызов" - -#~ msgid "default soundcard\n" -#~ msgstr "звуковая карта по умолчанию\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "Удалённый узел отключился, звонок завершён." - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Одновременные вызовы пока не поддерживается!" - -#~ msgid "gtk-go-down" -#~ msgstr "Вниз" - -#~ msgid "gtk-go-up" -#~ msgstr "Вверх" - -#~ msgid "gtk-media-play" -#~ msgstr "Проиграть" - -#~ msgid "Could not reach destination." -#~ msgstr "Невозможно соединиться." - -#~ msgid "Request Cancelled." -#~ msgstr "Запрос отменён." - -#~ msgid "Bad request" -#~ msgstr "Неверный запрос" - -#~ msgid "User cannot be found at given address." -#~ msgstr "Пользователь не может быть найден." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "" -#~ "Удалённый пользователь не поддерживает ни одного из предложенных кодеков." - -#~ msgid "Timeout." -#~ msgstr "Таймаут." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Удалённый узел был найден, но отказал в соединении." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Пользователь не доступен в данный момент, но\n" -#~ "приглашает Вас пообщаться на альтернативном ресурсе:" - -#~ msgid "Digits" -#~ msgstr "Цифры" - -#~ msgid "Main view" -#~ msgstr "Главное окно" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "NAT/firewall адрес не установлен !" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Неверный NAT адрес '%s' : '%s'" - -#~ msgid "Gone" -#~ msgstr "Ушёл" - -#~ msgid "Waiting for Approval" -#~ msgstr "Ожидание утверждения" - -#~ msgid "Be Right Back" -#~ msgstr "Скоро вернусь" - -#~ msgid "On The Phone" -#~ msgstr "На телефоне" - -#~ msgid "Out To Lunch" -#~ msgstr "На обеде" - -#~ msgid "Closed" -#~ msgstr "Закрыто" - -#~ msgid "Unknown" -#~ msgstr "Неизвестно" - -#~ msgid "gtk-connect" -#~ msgstr "Соединить" - -#~ msgid "gtk-find" -#~ msgstr "Найти" - -#~ msgid "SIP address" -#~ msgstr "SIP-адрес" - -#~ msgid "_View" -#~ msgstr "_Вид" - -#~ msgid "gtk-about" -#~ msgstr "О программе" - -#~ msgid "gtk-help" -#~ msgstr "Помощь" - -#~ msgid "gtk-preferences" -#~ msgstr "Параметры" - -#~ msgid "" -#~ "Show All\n" -#~ "Show Online" -#~ msgstr "" -#~ "Показать все\n" -#~ "Показать Online" - -#~ msgid "Display filters" -#~ msgstr "Показать фильтры" - -#~ msgid "I'm not behing a firewall" -#~ msgstr "Я не за firewall" - -#~ msgid "I'm behind a firewall, use supplied public IP address" -#~ msgstr "Я за firewall, использовать доступный IP адрес" - -#~ msgid "Use the supplied stun server above and do as best as possible" -#~ msgstr "Использовать доступный Stun сервер и делать так хорошо как возможно" - -#~ msgid "Miscelaneous" -#~ msgstr "Разное" - -#~ msgid "Go" -#~ msgstr "Старт" - -#~ msgid "Address book" -#~ msgstr "Адресная книга" - -#~ msgid "Shows calls" -#~ msgstr "Показать звонки" - -#~ msgid "Exit" -#~ msgstr "Выход" - -#~ msgid "Shows the address book" -#~ msgstr "Показать адресную книгу" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "Proxy to use:" -#~ msgstr "Какой узел использовать:" - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Прервать\n" -#~ "или отказать" - -#~ msgid "Or chat !" -#~ msgstr "Или Чат ! " - -#~ msgid "Show more..." -#~ msgstr "Показать больше..." - -#~ msgid "Playback level:" -#~ msgstr "Уровень воспроизведения:" - -#~ msgid "Recording level:" -#~ msgstr "Уровень записи:" - -#~ msgid "Ring level:" -#~ msgstr "Уровень звонка:" - -#~ msgid "Controls" -#~ msgstr "Управление" - -#~ msgid "Reachable" -#~ msgstr "Доступен" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Занят, я вернусь через " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "Другая часть информирует, что Вы вернётесь через X минут" - -#~ msgid "mn" -#~ msgstr "мн" - -#~ msgid "Moved temporarily" -#~ msgstr "Временно переехал" - -#~ msgid "Alternative service" -#~ msgstr "Альтернативный сервис" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Статус" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Введите цифры, чтоб отправить DTMF." - -#~ msgid "" -#~ " 3\n" -#~ "def" -#~ msgstr "" -#~ " 3\n" -#~ "где" - -#~ msgid "" -#~ " 2\n" -#~ "abc" -#~ msgstr "" -#~ " 2\n" -#~ "абв" - -#~ msgid "" -#~ " 4\n" -#~ "ghi" -#~ msgstr "" -#~ " 4\n" -#~ "жзи" - -#~ msgid "" -#~ " 5\n" -#~ "jkl" -#~ msgstr "" -#~ " 5\n" -#~ "клм" - -#~ msgid "" -#~ " 6\n" -#~ "mno" -#~ msgstr "" -#~ " 6\n" -#~ "ноп" - -#~ msgid "" -#~ " 7\n" -#~ "pqrs" -#~ msgstr "" -#~ " 7\n" -#~ "рст" - -#~ msgid "" -#~ " 8\n" -#~ "tuv" -#~ msgstr "" -#~ " 8\n" -#~ "уфх" - -#~ msgid "" -#~ " 9\n" -#~ "wxyz" -#~ msgstr "" -#~ " 9\n" -#~ "шюя" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Мои друзья онлайн:" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "C: 2001\n" -#~ "Сделано в старой Европе" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone - это интернет телефон.\n" -#~ "Он совместим с SIP и RTP протоколами." - -#~ msgid "http://www.linphone.org" -#~ msgstr "http://www.linphone.org/" - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Использовать IPv6 сеть (если доступно)" - -# msgstr "Teilnehmer zur Zeit nicht ansprechbar." -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "Отметьте, если Вы в сети с ipv6 и будите использовать linphone." - -#~ msgid "Global" -#~ msgstr "Основные" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Эта опция используется в частных сетях, за шлюзом. Если вы не в этой " -#~ "ситуации, просто оставьте пустой." - -#~ msgid "No firewall" -#~ msgstr "Нет firewall'a" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "Используйте этот STUN сервер чтоб определить адрес firewall :" - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Определить адрес Firewall вручную:" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "NAT опции (экспериментально)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Число милисекунд для буферизации (компенсация дрожания):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "RTP порт для аудио:" - -#~ msgid "RTP properties" -#~ msgstr "RTP свойства" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "" -#~ "Используйте SIP INFO сообщения вместо RTP rfc2833 для DTMF препровождения" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 рекомендуемый." - -#~ msgid "Other" -#~ msgstr "Другое" - -#~ msgid "micro" -#~ msgstr "Микрофон" - -#~ msgid "Recording source:" -#~ msgstr "Источник записи:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "" -#~ "Включить подавление эхо (подавляет эхо слышимое с удалённого устройства)" - -#~ msgid "Choose file" -#~ msgstr "Выберите файл" - -#~ msgid "Listen" -#~ msgstr "Слушать" - -#~ msgid "Sound properties" -#~ msgstr "Настройки звука" - -#~ msgid "Sound device" -#~ msgstr "Устройство звука" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Запустить \"user agent\" на порту:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Рекомендуется использовать порт 5060." - -#~ msgid "SIP port" -#~ msgstr "SIP порт" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Личность" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Добавить прокси/регистратора" - -#~ msgid "Remote services" -#~ msgstr "Удалённые сервисы" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "Удалить всю информацию аунтефикации (логин, пароль...)" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Список аудио кодеков в приоритетном порядке:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Заметка: Кодеки отмеченные красным не подходят для вашего соединения в " -#~ "Internet." - -#~ msgid "No information availlable" -#~ msgstr "Информация недоступна" - -#~ msgid "Codec information" -#~ msgstr "Информация о кодеке" - -#~ msgid "Address Book" -#~ msgstr "Адресная книга" - -#~ msgid "Select" -#~ msgstr "Выбор" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Пользователь не доступен в данный момент, но приглашает пообщаться на " -#~ "альтернативном ресурсе:" - -#~ msgid "None." -#~ msgstr "Нет." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Прокси/Регистратор конфигуратор" - -#~ msgid "Send registration:" -#~ msgstr "Отправить регистрацию:" - -#~ msgid "Name:" -#~ msgstr "Имя:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Правило подписки:" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Отправить подписку (смотреть статус персоны в сети)" - -#~ msgid "New incoming subscription" -#~ msgstr "Подтверждение новой подписки" - -#~ msgid "You have received a new subscription..." -#~ msgstr "Вы получили новое подтверждение..." - -#~ msgid "Refuse" -#~ msgstr "Отказать" - -#~ msgid "Authentication required for realm" -#~ msgstr "Регистрация для" - -#~ msgid "userid:" -#~ msgstr "ID пользователя:" - -#~ msgid "realm:" -#~ msgstr "Название:" - -#~ msgid "Linphone - Call history" -#~ msgstr "Linphone - История звонков" - -#~ msgid "Text:" -#~ msgstr "Текст" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "" -#~ "Вызывающий абонент спрашивает о резервировании ресурса. Вы согласны ?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "Вызывающий не использует резервирование ресурса. \t\t\t\t\tВы всё равно " -#~ "желаете продолжить?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "Linphone - принял звонок от %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "Вы получили запрос на подключение от %s. Это значит что этот человек " -#~ "хочет знать ваш статус (онлайн, занят, отошёл...).\n" -#~ "Вы согласны ?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Регистрация для %s" - -#~ msgid "Wait" -#~ msgstr "Подождать" - -#~ msgid "Deny" -#~ msgstr "Отказать" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "Неправильный sip адрес, он выглядит как: " - -#~ msgid "Stun lookup done..." -#~ msgstr "Поиск Stun завершён..." - -#~ msgid "enter sip uri here" -#~ msgstr "Sip URI eingeben" - -#~ msgid "User manual" -#~ msgstr "Anwender-Handbuch" - -#~ msgid "Ring sound selection" -#~ msgstr "Klingelton ausw�len" - -#~ msgid "Communication ended." -#~ msgstr "Kommunikation beendet." - -#, fuzzy -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "IP-Adresse des Firewall (in Punktnotation)" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Server-Adresse:" - -#~ msgid "28k modem" -#~ msgstr "28K Modem" - -#~ msgid "56k modem" -#~ msgstr "56K Modem" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64K Modem (ISDN)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL oder Kabel-Modem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet oder �uivalent" - -#~ msgid "Connection type:" -#~ msgstr "Verbindungstyp:" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone kann das Soundger� nicht �fnen. Prfen Sie nach, ob dieSoundkarte " -#~ "vollst�dig konfiguriert und funktionsf�ig ist." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "" -#~ "Geben Sie die Sip-Adresse des Anwenders, den Sie anrufen m�hten, hier ein." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Auflegen oder\n" -#~ "Abweisen" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. In %i Minuten wieder versuchen." - -#~ msgid "Timeout..." -#~ msgstr "Zeitberschreitung..." - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "" -#~ "Bitte ankreuzen, wenn Sie auf einem Sip-Server registriert werden wollen." - -#~ msgid "Address of record:" -#~ msgstr "Adresse des Eintrags:" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "" -#~ "Passwort fr die Registrierung. Bei manchen Servern nicht erforderlich." - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "Verwenden Sie diesen Registrarserver als externen proxy." - -#~ msgid "sip address:" -#~ msgstr "SIP-Adresse:" - -#~ msgid "Modify" -#~ msgstr "�dern" - -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "Sie verwenden zur Zeit den i810_audio Treiber.\n" -#~ "Diese Treiber ist fehlerhaft und funktioniert nicht mit Linphone\n" -#~ "Wir empfehlen, den Treiber entweder durch das ALSA-Treiber-Paket von " -#~ "ihrer Distribution\n" -#~ "zu ersetzen oder die gewnschten ALSA-Treiber von http://www.alsa-project." -#~ "org\n" -#~ "zu beziehen und zu installieren" - -#~ msgid "Unregistration successfull." -#~ msgstr "Abmeldung erfolgreich." - -#~ msgid "Select network interface to use:" -#~ msgstr "Netzwerkschnittstelle w�len:" - -#~ msgid "Network interface properties" -#~ msgstr "Eigenschaften der Netzwerkschnittstelle" - -#~ msgid "RTP" -#~ msgstr "RTP" - -#~ msgid "C: 2001" -#~ msgstr "April 2001" - -#~ msgid "Threads not supported by glib. Upgrade your glib.\n" -#~ msgstr "" -#~ "Threads werden von glib nicht untersttzt. Bitte aktualisieren Sie Ihre " -#~ "glib.\n" - -#~ msgid "Run linphone as a gnome-applet." -#~ msgstr "Linphone als gnome-Applet ausfhren." - -#~ msgid "Run linphone as a daemon (for use without gnome)." -#~ msgstr "Linphone als daemon ausfhren (Verwendung ohne Gnome)." - -#~ msgid "" -#~ "Cannot find network previously used interface %s.\n" -#~ "If your computer is temporary connected to the internet, please connect " -#~ "and then run linphone.\n" -#~ "If you want to change your default network interface, go to the " -#~ "parameters 'box." -#~ msgstr "" -#~ "Linphone konnte die zuvor verwendete Netzwerkschnittstelle %s nicht " -#~ "finden.\n" -#~ "Wenn linphone nur tempor� am Internet angeschlossen ist, stellen Sie eine " -#~ "Verbindung her und rufen Sie linphone erneut auf.\n" -#~ "Wenn Sie die vorgegebene Netzwerkschnittstelle �dern wollen, w�len Sie " -#~ "bitte \"Einstellungen\"." - -#~ msgid "" -#~ "Linphone cannot open the audio device.\n" -#~ "It may be caused by other programs using it.\n" -#~ "Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht �fnen.\n" -#~ "Dies kann durch andere Applikationen verursacht sein.\n" -#~ "M�hten sie diese Programme (esd oder artsd) beenden?" - -#~ msgid "Use it as a:" -#~ msgstr "Verwenden als:" - -#~ msgid "Outbound proxy" -#~ msgstr "Ausgehender Proxy-Server" - -#~ msgid "" -#~ "Toggle this button if the registrar must be used to proxy calls through a " -#~ "firewall." -#~ msgstr "" -#~ "Verwenden Sie diesen Knopf, falls der Registrar zum Tunneln durch einen " -#~ "Firewall verwendet werden mu�" - -#~ msgid "kbit/s" -#~ msgstr "Kbits/s" - -#~ msgid "OSS" -#~ msgstr "OSS" - -#~ msgid "ALSA" -#~ msgstr "ALSA" - -#~ msgid "Automatically kill applications using soundcard when needed" -#~ msgstr "Applikationen die die Soundkarte verwenden, automatisch beenden." - -#~ msgid "" -#~ "Your computer is connected to several networks. Check in the global " -#~ "parameters if Linphone uses the one that you want." -#~ msgstr "" -#~ "Ihr Rechner ist an mehere Netze angeschlossen. Stellen Sie sicher, da�in " -#~ "den Globalen Parametern die richtige Schnittstelle selektiert ist." - -#~ msgid "" -#~ "Linphone failed to open the sound device. See the README file included in " -#~ "the distribution for details." -#~ msgstr "" -#~ "Linphone konnte die Soundschnittstelle nicht �fnen. Weitere Informationen " -#~ "finden Sie in der README-Datei (enthalten in der Distribution)." - -#~ msgid "Interface not found." -#~ msgstr "Schnittstelle nicht gefunden." - -#~ msgid "Warning" -#~ msgstr "Warnung" - -#~ msgid "" -#~ "Linphone cannot open the sound device. It may be caused by other programs " -#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht �fnen. Dies kann durch andere " -#~ "Applikationen verursacht sein. M�hten sie diese Programme (esd oder " -#~ "artsd) beenden?" - -#~ msgid "Linphone shutdowns..." -#~ msgstr "Linphone Ende..." - -#~ msgid "" -#~ "Please, wait a few seconds untils linphone unregisters your sip addess " -#~ "from registrar server..." -#~ msgstr "Bitte einige Sekunden warten, bis Sip-Adresse ausgetragen ist." - -#~ msgid "Bad formuled sip address." -#~ msgstr "SIP-Adresse fehlerhaft." - -#~ msgid "Couldn't create pixmap from file: %s" -#~ msgstr "Konnte Pixmap nicht aus Datei %s erzeugen." - -#~ msgid "" -#~ "Linphone did not detect any valid network interface. If you use a " -#~ "temporary internet connection, please connect and then run linphone again." -#~ msgstr "" -#~ "Linphone konnte keine Netzwerkschnittstelle finden. Wenn Sie nur eine " -#~ "tempor�e Internetverbindung haben, bitte erneut eine Internetverbindung " -#~ "herstellen und linphone nochmals starten." - -#~ msgid "List of network interfaces on your system." -#~ msgstr "Vorhandene Netzwerkschnittstellen ihres Systems" +msgstr[0] "У вас %i пропущенный вызов." +msgstr[1] "У вас %i пропущенных вызова." +msgstr[2] "У вас %i пропущенных вызов." +msgstr[3] "У вас %i пропущенных вызов." + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "прервано" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "завершено" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "пропущено" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "неизвестно" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s в %s\n" +"От: %s\n" +"До: %s\n" +"Статус: %s\n" +"Продолжительность: %i мин %i сек\n" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "Исходящий вызов" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "Невозможно воспроизвести %s." diff --git a/po/sr.po b/po/sr.po new file mode 100644 index 000000000..9026fe636 --- /dev/null +++ b/po/sr.po @@ -0,0 +1,2129 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Мирослав Николић , 2014 +msgid "" +msgstr "" +"Project-Id-Version: linphone-gtk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Serbian (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/sr/)\n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "Позови „%s“" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Пошаљи текст за %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "Недавни позиви (%i)" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "н/д" + +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "Прекинут" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "Пропуштен" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "Одбијен" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "%i минут" +msgstr[1] "%i минута" +msgstr[2] "%i минута" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "%i секунда" +msgstr[1] "%i секунде" +msgstr[2] "%i секунди" + +#: ../gtk/calllogs.c:338 +#, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" +"%s\tКвалитет: %s\n" +"%s\t%s\t" + +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 +msgid "Conference" +msgstr "Конференција" + +#: ../gtk/conference.c:46 +msgid "Me" +msgstr "Ја" + +#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "Не могу да пронађем датотеку сличице: %s" + +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 +msgid "log to stdout some debug information while running." +msgstr "бележи на стандардни излаз неке податке прочишћавања док ради." + +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 +msgid "path to a file to write logs into." +msgstr "путања до датотеке за уписивање дневника." + +#: ../gtk/main.c:141 +msgid "Start linphone with video disabled." +msgstr "Покреће линфон са искљученим видеом." + +#: ../gtk/main.c:142 +msgid "Start only in the system tray, do not show the main interface." +msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." + +#: ../gtk/main.c:143 +msgid "address to call right now" +msgstr "адреса за позивање управо сада" + +#: ../gtk/main.c:144 +msgid "" +"Specifiy a working directory (should be the base of the installation, eg: c:" +"\\Program Files\\Linphone)" +msgstr "" +"Наводи радни директоријум (треба да буде основа инсталације, нпр: „c:" +"\\Program Files\\Linphone“)" + +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Датотека подешавања" + +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Покреће помоћника звука" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "Покреће самоиспробавање и излази 0 ако је успешно" + +#: ../gtk/main.c:1058 +#, c-format +msgid "" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" +"If you answer no, this person will be temporarily blacklisted." +msgstr "" + +#: ../gtk/main.c:1135 +#, c-format +msgid "" +"Please enter your password for username %s\n" +" at realm %s:" +msgstr "" +"Унесите вашу лозинку за корисничко име %s\n" +" на подручју %s:" + +#: ../gtk/main.c:1256 +msgid "Call error" +msgstr "Грешка позива" + +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 +msgid "Call ended" +msgstr "Позив је завршен" + +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 +msgid "Incoming call" +msgstr "Долазни позив" + +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 +msgid "Answer" +msgstr "Јави се" + +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 +msgid "Decline" +msgstr "Одбиј" + +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "Позив је заустављен" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "од %s" + +#: ../gtk/main.c:1342 +#, c-format +msgid "%s proposed to start video. Do you accept ?" +msgstr "%s предлаже да започнете видео. Да ли прихватате ?" + +#: ../gtk/main.c:1508 +msgid "Website link" +msgstr "Веза веб сајта" + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Линфон" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 +#, c-format +msgid "%s (Default)" +msgstr "%s (основно)" + +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 +#, c-format +msgid "We are transferred to %s" +msgstr "Преселили смо се на %s" + +#: ../gtk/main.c:1983 +msgid "" +"No sound cards have been detected on this computer.\n" +"You won't be able to send or receive audio calls." +msgstr "" +"Ниједна звучна картица није откривена на овом рачунару.\n" +"Нећете бити у могућности да шаљете или да примате звучне позиве." + +#: ../gtk/main.c:2127 +msgid "A free SIP video-phone" +msgstr "Слободан СИП телефон са снимком" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "Додајте у адресар" + +#: ../gtk/friendlist.c:692 +msgid "Presence status" +msgstr "Стање присуства" + +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 +msgid "Name" +msgstr "Име" + +#: ../gtk/friendlist.c:722 +msgid "Call" +msgstr "Позови" + +#: ../gtk/friendlist.c:727 +msgid "Chat" +msgstr "Ћаскај" + +#: ../gtk/friendlist.c:757 +#, c-format +msgid "Search in %s directory" +msgstr "Тражи у директоријуму „%s“" + +#: ../gtk/friendlist.c:926 +msgid "Invalid sip contact !" +msgstr "Неисправан сип контакт !" + +#: ../gtk/friendlist.c:978 +#, c-format +msgid "Edit contact '%s'" +msgstr "Уредите контакт „%s“" + +#: ../gtk/friendlist.c:979 +#, c-format +msgid "Delete contact '%s'" +msgstr "Обришите контакт „%s“" + +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Обришите историјат ћаскања за „%s“" + +#: ../gtk/friendlist.c:1031 +#, c-format +msgid "Add new contact from %s directory" +msgstr "Додајте нови контакт из директоријума „%s“" + +#: ../gtk/propertybox.c:597 +msgid "Rate (Hz)" +msgstr "Проток (Hz)" + +#: ../gtk/propertybox.c:603 +msgid "Status" +msgstr "Стање" + +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "Проток бита ИП-а (kbit/s)" + +#: ../gtk/propertybox.c:627 +msgid "Parameters" +msgstr "Параметри" + +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 +msgid "Enabled" +msgstr "Укључено" + +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 +msgid "Disabled" +msgstr "Искључено" + +#: ../gtk/propertybox.c:901 +msgid "Account" +msgstr "Налог" + +#: ../gtk/propertybox.c:1169 +msgid "English" +msgstr "Енглески" + +#: ../gtk/propertybox.c:1170 +msgid "French" +msgstr "Француски" + +#: ../gtk/propertybox.c:1171 +msgid "Swedish" +msgstr "Шведски" + +#: ../gtk/propertybox.c:1172 +msgid "Italian" +msgstr "Италијански" + +#: ../gtk/propertybox.c:1173 +msgid "Spanish" +msgstr "Шпански" + +#: ../gtk/propertybox.c:1174 +msgid "Brazilian Portugese" +msgstr "Бразилски португалски" + +#: ../gtk/propertybox.c:1175 +msgid "Polish" +msgstr "Пољски" + +#: ../gtk/propertybox.c:1176 +msgid "German" +msgstr "Немачки" + +#: ../gtk/propertybox.c:1177 +msgid "Russian" +msgstr "Руски" + +#: ../gtk/propertybox.c:1178 +msgid "Japanese" +msgstr "Јапански" + +#: ../gtk/propertybox.c:1179 +msgid "Dutch" +msgstr "Холандски" + +#: ../gtk/propertybox.c:1180 +msgid "Hungarian" +msgstr "Мађарски" + +#: ../gtk/propertybox.c:1181 +msgid "Czech" +msgstr "Чешки" + +#: ../gtk/propertybox.c:1182 +msgid "Chinese" +msgstr "Кинески" + +#: ../gtk/propertybox.c:1183 +msgid "Traditional Chinese" +msgstr "Традиционални кинески" + +#: ../gtk/propertybox.c:1184 +msgid "Norwegian" +msgstr "Норвешки" + +#: ../gtk/propertybox.c:1185 +msgid "Hebrew" +msgstr "Јеврејски" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Српски" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 +msgid "" +"You need to restart linphone for the new language selection to take effect." +msgstr "" +"Треба поново да покренете линфон да би нови изабрани језик ступио у дејство." + +#: ../gtk/propertybox.c:1325 +msgid "None" +msgstr "Ништа" + +#: ../gtk/propertybox.c:1329 +msgid "SRTP" +msgstr "СРТП" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 +msgid "ZRTP" +msgstr "ЗРТП" + +#: ../gtk/update.c:80 +#, c-format +msgid "" +"A more recent version is availalble from %s.\n" +"Would you like to open a browser to download it ?" +msgstr "" +"Новије издање је доступно са „%s“.\n" +"Да ли желите да отворите прегледник и да га преузмете ?" + +#: ../gtk/update.c:91 +msgid "You are running the lastest version." +msgstr "Радите на најновијем издању." + +#: ../gtk/buddylookup.c:85 +msgid "Firstname, Lastname" +msgstr "Име и презиме" + +#: ../gtk/buddylookup.c:160 +msgid "Error communicating with server." +msgstr "Грешка у коминикацији са сервером." + +#: ../gtk/buddylookup.c:164 +msgid "Connecting..." +msgstr "Повезујем се..." + +#: ../gtk/buddylookup.c:168 +msgid "Connected" +msgstr "Повезан сам" + +#: ../gtk/buddylookup.c:172 +msgid "Receiving data..." +msgstr "Примам податке..." + +#: ../gtk/buddylookup.c:180 +#, c-format +msgid "Found %i contact" +msgid_plural "Found %i contacts" +msgstr[0] "Нашао сам %i контакт" +msgstr[1] "Нашао сам %i контакта" +msgstr[2] "Нашао сам %i контаката" + +#: ../gtk/setupwizard.c:160 +msgid "" +"Welcome!\n" +"This assistant will help you to use a SIP account for your calls." +msgstr "" +"Добро дошли!\n" +"Овај помоћник ће вам помоћи да користите СИП налог за ваше позиве." + +#: ../gtk/setupwizard.c:169 +msgid "Create an account on linphone.org" +msgstr "Направи налог на линфон.орг-у" + +#: ../gtk/setupwizard.c:170 +msgid "I have already a linphone.org account and I just want to use it" +msgstr "Већ имам налог линфон.орг-а и желим да га користим" + +#: ../gtk/setupwizard.c:171 +msgid "I have already a sip account and I just want to use it" +msgstr "Већ имам сип налог и желим да га користим" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "Желим да наведем удаљену путању подешавања" + +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 +msgid "Username*" +msgstr "Корисник*" + +#: ../gtk/setupwizard.c:222 +msgid "Password*" +msgstr "Лозинка*" + +#: ../gtk/setupwizard.c:225 +msgid "Domain*" +msgstr "Домен*" + +#: ../gtk/setupwizard.c:226 +msgid "Proxy" +msgstr "Посредник" + +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "Унесите ваше корисничко име линфон.орг-а" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Корисничко име:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Лозинка:" + +#: ../gtk/setupwizard.c:419 +msgid "(*) Required fields" +msgstr "(*) Обавезна поља" + +#: ../gtk/setupwizard.c:420 +msgid "Username: (*)" +msgstr "Корисник: (*)" + +#: ../gtk/setupwizard.c:422 +msgid "Password: (*)" +msgstr "Лозинка: (*)" + +#: ../gtk/setupwizard.c:424 +msgid "Email: (*)" +msgstr "Ел. пошта: (*)" + +#: ../gtk/setupwizard.c:426 +msgid "Confirm your password: (*)" +msgstr "Потврдите вашу лозинку: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "Обавештавај ме о ажурирањима линфона" + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:494 +msgid "" +"Please validate your account by clicking on the link we just sent you by " +"email.\n" +"Then come back here and press Next button." +msgstr "" +"Потврдите ваш налог притиском на везу коју смо вам управо послали ел. " +"поштом.\n" +"Затим се вратите овде и притисните дугме „Напред“." + +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Грешка, налог није потврђен, корисничко име је већ у употреби или је сервер " +"недоступан.\n" +"Вратите се назад и покушајте опет." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Хвала вам. Ваш налог је сада подешен и спреман за употребу." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "Помоћник подешавања СИП налога" + +#: ../gtk/setupwizard.c:578 +msgid "Welcome to the account setup assistant" +msgstr "Добро дошли у помоћника подешавања налога" + +#: ../gtk/setupwizard.c:583 +msgid "Account setup assistant" +msgstr "Помоћник подешавања налога" + +#: ../gtk/setupwizard.c:588 +msgid "Configure your account (step 1/1)" +msgstr "Подесите ваш налог (корак 1/1)" + +#: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "Унесите ваше корисничко име сип-а (корак 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Унесите податке налога (корак 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Потврђивање (корак 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Грешка" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "Завршавам" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "Позив бр. %i" + +#: ../gtk/incall_view.c:155 +#, c-format +msgid "Transfer to call #%i with %s" +msgstr "Пребаци позив #%i са %s" + +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 +msgid "Not used" +msgstr "Не користи се" + +#: ../gtk/incall_view.c:221 +msgid "ICE not activated" +msgstr "ИЦЕ није покренут" + +#: ../gtk/incall_view.c:223 +msgid "ICE failed" +msgstr "ИЦЕ није успео" + +#: ../gtk/incall_view.c:225 +msgid "ICE in progress" +msgstr "ИЦЕ је у току" + +#: ../gtk/incall_view.c:227 +msgid "Going through one or more NATs" +msgstr "Пролазим кроз један или више НАТ-са" + +#: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "Непосредно" + +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "Преко преносног сервера" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "уПнП није покренут" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "уПнП је у току" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "уПнП није доступан" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "уПнП ради" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "уПнП није успео" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "Непосредно или кроз сервер" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 +#, c-format +msgid "" +"download: %f\n" +"upload: %f (kbit/s)" +msgstr "" +"преузимање: %f\n" +"отпремање: %f (kbit/s)" + +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "%ix%i @ %f к/с" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "%.3f секунде" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "Прекини" + +#: ../gtk/incall_view.c:510 +msgid "Calling..." +msgstr "Позивам..." + +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" + +#: ../gtk/incall_view.c:524 +msgid "Incoming call" +msgstr "Долазни позив" + +#: ../gtk/incall_view.c:561 +msgid "good" +msgstr "добро" + +#: ../gtk/incall_view.c:563 +msgid "average" +msgstr "просечно" + +#: ../gtk/incall_view.c:565 +msgid "poor" +msgstr "оскудно" + +#: ../gtk/incall_view.c:567 +msgid "very poor" +msgstr "јадно" + +#: ../gtk/incall_view.c:569 +msgid "too bad" +msgstr "много лоше" + +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 +msgid "unavailable" +msgstr "недоступно" + +#: ../gtk/incall_view.c:715 +msgid "Secured by SRTP" +msgstr "Осигурано СРТП-ом" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 +#, c-format +msgid "Secured by ZRTP - [auth token: %s]" +msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" + +#: ../gtk/incall_view.c:733 +msgid "Set unverified" +msgstr "Непроверено подешавање" + +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 +msgid "Set verified" +msgstr "Проверено подешавање" + +#: ../gtk/incall_view.c:762 +msgid "In conference" +msgstr "На конференцији" + +#: ../gtk/incall_view.c:762 +msgid "In call" +msgstr "У позиву" + +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "Заустављен позив" + +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "Позив је завршен." + +#: ../gtk/incall_view.c:865 +msgid "Transfer in progress" +msgstr "Пренос је у току" + +#: ../gtk/incall_view.c:868 +msgid "Transfer done." +msgstr "Пренос је обављен." + +#: ../gtk/incall_view.c:871 +msgid "Transfer failed." +msgstr "Пренос није успео." + +#: ../gtk/incall_view.c:904 +msgid "Resume" +msgstr "Настави" + +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 +msgid "Pause" +msgstr "Застани" + +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" +"Снимам у\n" +"%s %s" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Паузирано)" + +#: ../gtk/loginframe.c:75 +#, c-format +msgid "Please enter login information for %s" +msgstr "Унесите податке пријављивања за %s" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "довлачим са „%s“" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Преузимање удаљеног подешавања са „%s“ није успело." + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Глас није откривен" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Сувише низак" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "Добар" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Сувише гласан" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Да ли сте чули три писка ?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Нисам пронашао поставке звука " + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Не могу да покренем управљање звуком система " + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Добро дошли!\n" +"Овај помоћник ће вам помоћи да подесите поставке звука за Линфон" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Уређај за снимање" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "Снимљени волумен" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Нема гласа" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Поставке звука система" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Уређај за пуштање" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Пусти три писка" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Притисните дугме за снимање и реците нешто" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Слушајте ваш снимљени глас" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Сними" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Пусти" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "Хајде сада да покренемо Линфон" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Помоћник звука" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Помоћник звука" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "Дотеривање појачања микрофона" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "Дотеривање јачине звука звучника" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Снимите и пустите" + +#: ../gtk/main.ui.h:1 +msgid "All users" +msgstr "Сви корисници" + +#: ../gtk/main.ui.h:2 +msgid "Online users" +msgstr "Корисници на мрежи" + +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 +msgid "ADSL" +msgstr "АДСЛ" + +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 +msgid "Fiber Channel" +msgstr "Оптички канал" + +#: ../gtk/main.ui.h:5 +msgid "Default" +msgstr "Основно" + +#: ../gtk/main.ui.h:6 +msgid "Delete" +msgstr "Обриши" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Могућности" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "Постави путању подешавања" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "Увек покрени видео" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Укључи самовиђење" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "По_моћ" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Прикажи прозорче прочишћавања" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Матична страница" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Провери _ажурирања" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Помоћник налога" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "СИП адреса или број телефона:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Започните нови позив" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Пријатељи" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Тражи" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Додај пријатеље из директоријума" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Додај пријатеља" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Скорашњи позиви" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Мој тренутни идентитет:" + +#: ../gtk/about.ui.h:1 +msgid "About Linphone" +msgstr "О Линфону" + +#: ../gtk/about.ui.h:2 +msgid "(C) Belledonne Communications, 2010\n" +msgstr "(C) Беледоне комуникације, 2010\n" + +#: ../gtk/about.ui.h:4 +msgid "An internet video phone using the standard SIP (rfc3261) protocol." +msgstr "" +"Интернет телефон са снимком који користи уобичајени СИП протокол (rfc3261)." + +#: ../gtk/about.ui.h:5 +msgid "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" +msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" +"sr: Мирослав Николић \n" + +#: ../gtk/contact.ui.h:2 +msgid "SIP Address" +msgstr "СИП адреса" + +#: ../gtk/contact.ui.h:3 +msgid "Show this contact presence status" +msgstr "Прикажи стање присуства овог пријатеља" + +#: ../gtk/contact.ui.h:4 +msgid "Allow this contact to see my presence status" +msgstr "Дозволи овом пријатељу да види стање мог присуства" + +#: ../gtk/contact.ui.h:5 +msgid "Contact information" +msgstr "Подаци о пријатељу" + +#: ../gtk/log.ui.h:1 +msgid "Linphone debug window" +msgstr "Линфоново прозорче прочишћавања" + +#: ../gtk/log.ui.h:2 +msgid "Scroll to end" +msgstr "Премакни на крај" + +#: ../gtk/password.ui.h:1 +msgid "Linphone - Authentication required" +msgstr "Линфон — Потребно је потврђивање идентитета" + +#: ../gtk/password.ui.h:2 +msgid "Please enter the domain password" +msgstr "Унесите лозинку домена" + +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 +msgid "UserID" +msgstr "ИБ корисника" + +#: ../gtk/call_logs.ui.h:1 +msgid "Call history" +msgstr "Историјат позива" + +#: ../gtk/call_logs.ui.h:2 +msgid "Clear all" +msgstr "Очистите све" + +#: ../gtk/call_logs.ui.h:3 +msgid "Call back" +msgstr "Повратни позив" + +#: ../gtk/sip_account.ui.h:1 +msgid "Linphone - Configure a SIP account" +msgstr "Линфон — Подесите СИП налог" + +#: ../gtk/sip_account.ui.h:2 +msgid "Your SIP identity:" +msgstr "Ваш СИП идентитет:" + +#: ../gtk/sip_account.ui.h:3 +msgid "Looks like sip:@" +msgstr "Изгледа као „sip:<корисничко-име>@<домен>“" + +#: ../gtk/sip_account.ui.h:4 +msgid "sip:" +msgstr "сип:" + +#: ../gtk/sip_account.ui.h:5 +msgid "SIP Proxy address:" +msgstr "Адреса СИП посредника:" + +#: ../gtk/sip_account.ui.h:6 +msgid "Looks like sip:" +msgstr "Изгледа као „sip:<назив посредника>“" + +#: ../gtk/sip_account.ui.h:7 +msgid "Registration duration (sec):" +msgstr "Трајање уписа (сек):" + +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Параметри пријатеља (изборно):" + +#: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "АВПФ редован РТЦП интервал (сек):" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Рута (изборно):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Пренос" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Упиши се" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "Објави податке о присуству" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Укључи АВПФ" + +#: ../gtk/sip_account.ui.h:15 +msgid "Configure a SIP account" +msgstr "Подесите СИП налог" + +#: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "безимено" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "ГССАПИ" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "САСЛ" + +#: ../gtk/parameters.ui.h:4 +msgid "default soundcard" +msgstr "основна звучна картица" + +#: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "звучна картица" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "основна камерица" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "ЦИФ" + +#: ../gtk/parameters.ui.h:8 +msgid "Audio codecs" +msgstr "Кодеци звука" + +#: ../gtk/parameters.ui.h:9 +msgid "Video codecs" +msgstr "Кодеци снимка" + +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "В" + +#: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "СИП (УДП)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "СИП (ТЦП)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "СИП (ТЛС)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "" + +#: ../gtk/parameters.ui.h:17 +msgid "Settings" +msgstr "Подешавања" + +#: ../gtk/parameters.ui.h:18 +msgid "This section defines your SIP address when not using a SIP account" +msgstr "Овај одељак одређује вашу СИП адресу када не користите СИП налог" + +#: ../gtk/parameters.ui.h:19 +msgid "Your display name (eg: John Doe):" +msgstr "Ваше приказано име (нпр: Пера Перић):" + +#: ../gtk/parameters.ui.h:20 +msgid "Your username:" +msgstr "Ваше корисничко име:" + +#: ../gtk/parameters.ui.h:21 +msgid "Your resulting SIP address:" +msgstr "Ваша резултирајућа СИП адреса:" + +#: ../gtk/parameters.ui.h:22 +msgid "Default identity" +msgstr "Основни идентитет" + +#: ../gtk/parameters.ui.h:23 +msgid "Wizard" +msgstr "Чаробњак" + +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Додај" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Уреди" + +#: ../gtk/parameters.ui.h:26 +msgid "Remove" +msgstr "Уклони" + +#: ../gtk/parameters.ui.h:27 +msgid "Proxy accounts" +msgstr "Посреднички налози" + +#: ../gtk/parameters.ui.h:28 +msgid "Erase all passwords" +msgstr "Обриши све лозинке" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "Приватност" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Manage SIP Accounts" +msgstr "СИП налози" + +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Звук звона:" + +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "АЛСА-ин посебни уређај (изборно):" + +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Уређај за снимање:" + +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Уређај за звоно:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Уређај за пуштање:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Укључи поништавање одјека" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Звук" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Улазни уређај снимка:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Начин излаза снимка:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Прикажи претпреглед камерице" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 +msgid "0 stands for \"unlimited\"" +msgstr "0 значи „неограничено“" + +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Снимак" + +#: ../gtk/parameters.ui.h:49 +msgid "Upload speed limit in Kbit/sec:" +msgstr "Ограничи брзину слања на (Kb/s):" + +#: ../gtk/parameters.ui.h:50 +msgid "Download speed limit in Kbit/sec:" +msgstr "Ограничи брзину преузимања на (Kb/s):" + +#: ../gtk/parameters.ui.h:51 +msgid "Enable adaptive rate control" +msgstr "Укључи прилагодљиво управљање протоком" + +#: ../gtk/parameters.ui.h:52 +msgid "" +"Adaptive rate control is a technique to dynamically guess the available " +"bandwidth during a call." +msgstr "" +"Прилагодљиво управљање протоком је техника за променљиво погађање " +"доступног пропусног опсега за време позива." + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "Управљање пропусним опсегом" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Мултимедија" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Подеси јединицу највећег преноса:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Пошаљи ДТМФ као СИП податке" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Пренос" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "СИП/УДП прикључник" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Насумично" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "СИП/ТЦП прикључник" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "РТП/УДП звука:" + +#: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Неизмењиво" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "РТП/УДП снимка:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Врста шифровања медија" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Шифровање медија је обавезно" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Тунел" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "ДСЦП поља" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "Мрежни протокол и прикључници" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Непосредна веза на Интернет" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Иза НАТ-а / мрежне баријере (наведите ИП мрежног пролаза)" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Иза НАТ-а / мрежне баријере (користите СТУН за решавање)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "Иза НАТ-а / мрежне баријере (користите ИЦЕ)" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "Иза НАТ-а / мрежне баријере (користите уПнП)" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Јавна ИП адреса:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Стун сервер:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "НАТ и мрежна баријера" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Мрежа" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Укључи" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Искључи" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "Kодеци" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "Језик" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "Прикажи напредна подешавања" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "Ниво" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "Корисничко сучеље" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Адреса сервера:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Начин потврђивања идентитета:" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "Подешавања ЛДАП налога" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "ЛДАП" + +#: ../gtk/parameters.ui.h:94 +msgid "Done" +msgstr "Готово" + +#: ../gtk/buddylookup.ui.h:1 +msgid "Search contacts in directory" +msgstr "Потражите пријатеље у директоријуму" + +#: ../gtk/buddylookup.ui.h:2 +msgid "Add to my list" +msgstr "Додај на мој списак" + +#: ../gtk/buddylookup.ui.h:3 +msgid "Search somebody" +msgstr "Потражите неког" + +#: ../gtk/waiting.ui.h:2 +msgid "Please wait" +msgstr "Сачекајте мало" + +#: ../gtk/dscp_settings.ui.h:1 +msgid "DSCP settings" +msgstr "ДСЦП подешавања" + +#: ../gtk/dscp_settings.ui.h:2 +msgid "SIP" +msgstr "СИП" + +#: ../gtk/dscp_settings.ui.h:3 +msgid "Audio RTP stream" +msgstr "РТП ток звука" + +#: ../gtk/dscp_settings.ui.h:4 +msgid "Video RTP stream" +msgstr "РТП ток снимка" + +#: ../gtk/dscp_settings.ui.h:5 +msgid "Set DSCP values (in hexadecimal)" +msgstr "Подесите ДСЦП вредности (хексадецимално)" + +#: ../gtk/call_statistics.ui.h:1 +msgid "Call statistics" +msgstr "Статистика позива" + +#: ../gtk/call_statistics.ui.h:2 +msgid "Audio codec" +msgstr "Звучни кодек" + +#: ../gtk/call_statistics.ui.h:3 +msgid "Video codec" +msgstr "Видео кодек" + +#: ../gtk/call_statistics.ui.h:4 +msgid "Audio IP bandwidth usage" +msgstr "Искоришћеност ИП пропусног опсега звука" + +#: ../gtk/call_statistics.ui.h:5 +msgid "Audio Media connectivity" +msgstr "Повезивост медија звука" + +#: ../gtk/call_statistics.ui.h:6 +msgid "Video IP bandwidth usage" +msgstr "Искоришћеност ИП пропусног опсега снимка" + +#: ../gtk/call_statistics.ui.h:7 +msgid "Video Media connectivity" +msgstr "Повезивост медија снимка" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Време повратног путовања" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Примљена резолуција снимка" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Послата резолуција снимка" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "РТП профил" + +#: ../gtk/call_statistics.ui.h:12 +msgid "Call statistics and information" +msgstr "Статистика позива и подаци" + +#: ../gtk/tunnel_config.ui.h:1 +msgid "Configure VoIP tunnel" +msgstr "Подесите ВоИП тунел" + +#: ../gtk/tunnel_config.ui.h:2 +msgid "Host" +msgstr "Домаћин" + +#: ../gtk/tunnel_config.ui.h:3 +msgid "Port" +msgstr "Прикључник" + +#: ../gtk/tunnel_config.ui.h:6 +msgid "Configure tunnel" +msgstr "Подесите тунел" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Корисник" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Лозинка" + +#: ../gtk/tunnel_config.ui.h:9 +msgid "Configure http proxy (optional)" +msgstr "Подесите хттп посредника (изборно)" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "ЛДАП подешавања" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "Користи ТЛС везу" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Још није доступно" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "Веза" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "Свежи назив домена" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "Назив потврђивања" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Подручје" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "САСЛ" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "Предмет основе:" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "Пропусник (%s за име):" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "Особине имена:" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "Особине СИП адресе:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "Особине за пропитивање:" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "Потражите" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "Време за претрагу:" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "Највише резултата:" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "Прати надимке" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "Разно" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "БЕЗИМЕНО" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "ЈЕДНОСТАВНО" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "ДИГЕСТ-МД5" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "НТЛМ" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "Наводим удаљену путању подешавања" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" +"Ово прозорче омогућава подешавање хттп или хттпс адресе када се подешавање " +"добавља на покретању.\n" +"Унесите или измените путању подешавања. Након што притиснете „У реду“, " +"Линфон ће се сам поново покренути како би довукао и унео у налог нова " +"подешавања. " + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Подешавам..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "Сачекајте док довучем подешавања са сервера..." + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Пошаљи" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "Име позивника" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Заврши конференцију" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "Сними овај позив у звучну датотеку" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Видео" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Утишај" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Пренос" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "Долазни позив" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Трајање" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "Оцена квалитета позива" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Интернет веза:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Сам ме пријави" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Подаци пријављивања" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Добро дошли!" + +#: ../coreapi/linphonecore.c:1483 +msgid "Ready" +msgstr "Спреман" + +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Подешавам" + +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 +msgid "Contacting" +msgstr "Ступам у везу" + +#: ../coreapi/linphonecore.c:2805 +msgid "Could not call" +msgstr "Не могу да позовем" + +#: ../coreapi/linphonecore.c:2956 +msgid "Sorry, we have reached the maximum number of simultaneous calls" +msgstr "Извините, достигли смо највећи број истовремених позива" + +#: ../coreapi/linphonecore.c:3114 +msgid "is contacting you" +msgstr "вам се обраћа" + +#: ../coreapi/linphonecore.c:3115 +msgid " and asked autoanswer." +msgstr " и затражени само-одговор." + +#: ../coreapi/linphonecore.c:3241 +msgid "Modifying call parameters..." +msgstr "Мењам параметре позива..." + +#: ../coreapi/linphonecore.c:3625 +msgid "Connected." +msgstr "Повезан сам." + +#: ../coreapi/linphonecore.c:3650 +msgid "Call aborted" +msgstr "Позив је прекинут" + +#: ../coreapi/linphonecore.c:3847 +msgid "Could not pause the call" +msgstr "Не могу да зауставим позив" + +#: ../coreapi/linphonecore.c:3850 +msgid "Pausing the current call..." +msgstr "Заустављам тренутни позив..." + +#: ../coreapi/misc.c:436 +msgid "Stun lookup in progress..." +msgstr "У току је тражење стуна..." + +#: ../coreapi/misc.c:617 +msgid "ICE local candidates gathering in progress..." +msgstr "Прикупљање месних ИЦЕ кандидата је у току..." + +#: ../coreapi/friend.c:33 +msgid "Online" +msgstr "На вези" + +#: ../coreapi/friend.c:36 +msgid "Busy" +msgstr "Заузет" + +#: ../coreapi/friend.c:39 +msgid "Be right back" +msgstr "Одмах се враћам" + +#: ../coreapi/friend.c:42 +msgid "Away" +msgstr "Одсутан" + +#: ../coreapi/friend.c:45 +msgid "On the phone" +msgstr "На телефону" + +#: ../coreapi/friend.c:48 +msgid "Out to lunch" +msgstr "На ручку сам" + +#: ../coreapi/friend.c:51 +msgid "Do not disturb" +msgstr "Не узнемиравај" + +#: ../coreapi/friend.c:54 +msgid "Moved" +msgstr "Премештен" + +#: ../coreapi/friend.c:57 +msgid "Using another messaging service" +msgstr "Користим другу услугу дописивања" + +#: ../coreapi/friend.c:60 +msgid "Offline" +msgstr "Неповезан" + +#: ../coreapi/friend.c:63 +msgid "Pending" +msgstr "На чекању" + +#: ../coreapi/friend.c:66 +msgid "Vacation" +msgstr "На одмору" + +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Непознато стање" + +#: ../coreapi/proxy.c:295 +msgid "" +"The sip proxy address you entered is invalid, it must start with \"sip:\" " +"followed by a hostname." +msgstr "" +"Адреса сип посредника коју сте унели је неисправна, мора почети на „sip:“ за " +"којим следи назив домаћина." + +#: ../coreapi/proxy.c:301 +msgid "" +"The sip identity you entered is invalid.\n" +"It should look like sip:username@proxydomain, such as sip:alice@example.net" +msgstr "" +"Сип идентитет који сте унели није исправан.\n" +"Треба да изгледа као „sip:корисник@домен-посредника, као што је „sip:" +"alice@example.net“" + +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Тражим одредиште телефонског броја..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Не могу да решим овај број." + +#: ../coreapi/proxy.c:1407 +#, c-format +msgid "Could not login as %s" +msgstr "Не могу да се пријавим као %s" + +#: ../coreapi/proxy.c:1494 +#, fuzzy, c-format +msgid "Refreshing on %s..." +msgstr "довлачим са „%s“" + +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "Удаљено звоњење." + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "Удаљено звоњење..." + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "Ранији медиј." + +#: ../coreapi/callbacks.c:548 +#, c-format +msgid "Call with %s is paused." +msgstr "Позив са „%s“ је заустављен." + +#: ../coreapi/callbacks.c:561 +#, c-format +msgid "Call answered by %s - on hold." +msgstr "Позив на који је одговорио „%s“ — на чекању." + +#: ../coreapi/callbacks.c:571 +msgid "Call resumed." +msgstr "Позив је настављен." + +#: ../coreapi/callbacks.c:575 +#, c-format +msgid "Call answered by %s." +msgstr "На позив је одговорио „%s“." + +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "Несагласно, проверите кодеке или безбедносна подешавања..." + +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "Медијски параметри су несагласни." + +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "Наставили смо." + +#. we are being paused +#: ../coreapi/callbacks.c:642 +msgid "We are paused by other party." +msgstr "Друга страна нас је паузирала." + +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 +msgid "Call is updated by remote." +msgstr "Позив је освежен удаљеним." + +#: ../coreapi/callbacks.c:797 +msgid "Call terminated." +msgstr "Позив је завршен." + +#: ../coreapi/callbacks.c:825 +msgid "User is busy." +msgstr "Корисник је заузет." + +#: ../coreapi/callbacks.c:826 +msgid "User is temporarily unavailable." +msgstr "Корисник је привремено недоступан." + +#. char *retrymsg=_("%s. Retry after %i minute(s)."); +#: ../coreapi/callbacks.c:828 +msgid "User does not want to be disturbed." +msgstr "Корисник не жели да буде узнемираван." + +#: ../coreapi/callbacks.c:829 +msgid "Call declined." +msgstr "Позив је одбијен." + +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "Истекло је време захтева." + +#: ../coreapi/callbacks.c:875 +msgid "Redirected" +msgstr "Преусмерен" + +#: ../coreapi/callbacks.c:930 +msgid "Call failed." +msgstr "Позив није успео." + +#: ../coreapi/callbacks.c:1008 +#, c-format +msgid "Registration on %s successful." +msgstr "Уписивање на „%s“ је успело." + +#: ../coreapi/callbacks.c:1009 +#, c-format +msgid "Unregistration on %s done." +msgstr "Исписивање са „%s“ је обављено." + +#: ../coreapi/callbacks.c:1027 +msgid "no response timeout" +msgstr "нема ограничења одговора" + +#: ../coreapi/callbacks.c:1030 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "Уписивање на „%s“ није успело: %s" + +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Услуга није доступна, поново покушавам" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "Симбол потврђивања идентитета је „%s“" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format +msgid "You have missed %i call." +msgid_plural "You have missed %i calls." +msgstr[0] "Пропустили сте %i позив." +msgstr[1] "Пропустили сте %i позива." +msgstr[2] "Пропустили сте %i позива." + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "прекинут" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "завршен" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "пропуштен" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "непознато" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" +"%s на %s\n" +"Позивач: %s\n" +"Позивник: %s\n" +"Стање: %s\n" +"Трајање: %i мин. %i сек.\n" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "Одлазни позив" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "Не могу да пустим „%s“." diff --git a/po/sv.po b/po/sv.po index fed2d6550..455492964 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1,107 +1,123 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Free Software Foundation, Inc. -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2009-02-17 15:22+0100\n" -"Last-Translator: Emmanuel Frécon \n" -"Language-Team: SWEDISH \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Swedish (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/sv/)\n" +"Language: sv\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "Ringer %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "Skicka text till %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "avbrytade" +msgstr "" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "missade" +msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "Avböj" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 -#, fuzzy +#: ../gtk/conference.c:46 msgid "Me" -msgstr "Mikrofon av" +msgstr "" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "skriv loggning information under körning" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "Starta ikonifierat, visa inte huvudfönstret" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "Samtalsmottagare" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "Om på, besvara automatisk alla inkommande samtal" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -109,262 +125,280 @@ msgstr "" "Välj en arbetskatalog som ska vara basen för installationen, såsom C:" "\\Program\\Linphone" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "Samtal med %s" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s skulle vilja lägga till dig till hans/hennes kontaktlista.\n" -"Vill du tillåta honom/henne att se din närvarostatus eller lägga till honom/" -"henne till din kontaktlista?\n" -"Om du svarar nej, personen kommer att vara bannlyst." -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"Mata in ditt lösenord för användaren %s\n" -"vid domänen %s:" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "Samtalshistorik" +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "Avböj" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "avbrytade" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "Webbsajt" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - en video Internet telefon" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "Närvarostatus" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Namn" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "Ringer %s" +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "Sök i %s katalogen" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "ogiltig SIP kontakt!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "Ringer %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "Skicka text till %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "Ändra kontakt '%s'" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "Lägg till kontakt ifrån %s katalogen" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "Min. datahastighet (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "Parametrar" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "Engelska" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "Italiensk" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "Spanska" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "Portugisiska" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "Polska" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "Tyska" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "Ryska" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "Japanska" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "Nederländksa" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "Hungerska" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "Tjekiska" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "Kinesiska" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Du behöver starta om programmet för att det nya språket ska synas." -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -408,534 +442,553 @@ msgid_plural "Found %i contacts" msgstr[0] "Hittat kontakt %i" msgstr[1] "Hittat kontakt %i" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"Välkommen!\n" -"Assistenten kommer att hjälpa dig använda ett SIP konto för dina samtal:" -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "Skapa ett konto genom att välja ett användarnamn" +msgstr "" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "Jag har redan ett konto och vill bara använda det." +msgstr "" -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "Jag har redan ett konto och vill bara använda det." - -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "Användarnamn:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "Lösenord:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "Användarnamn" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "Lösenord" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Användarnamn:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Lösenord:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "Användarnamn:" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "Lösenord:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "Tack. Ditt konto är nu konfigurerad och färdig att användas." +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Tack. Ditt konto är nu konfigurerad och färdig att användas." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "Välkommen till kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "Konfigurera ett SIP konto" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -msgid "Error" +msgid "Configure your account (step 1/1)" msgstr "" #: ../gtk/setupwizard.c:592 -#, fuzzy +msgid "Enter your sip username (step 1/1)" +msgstr "" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "Lägg på" +msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "Ringer %s" +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:219 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "Samtalet avböjdes." - #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "Omdirigerat till %s..." +msgid "Going through one or more NATs" +msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +#, fuzzy +msgid "00:00:00" msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "Inkommande samtal" +msgstr "" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "I samtal med" +msgstr "" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "Lägg på" +msgstr "" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i:%02i:%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "Samtalet slut." -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "Samtalet avböjdes." +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "Mata in ditt lösenord för domänen %s:" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "Samtalet slut." - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "Skicka" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "I samtal" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "Förlopp" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "Själv bild" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone debug fönster" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "_Homepage" -msgstr "Hemsidan" - -#: ../gtk/main.ui.h:23 -#, fuzzy -msgid "Check _Updates" -msgstr "Letar efter uppdateringar" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "Kontoinstallationsassistenten" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "Användarnamn" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "Lägg till" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "Editera" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "Sök" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "Lägg till kontakt ifrån katalogen" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "Hittat kontakt %i" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "I samtal" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "Min nuvarande identitet" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Användarnamn" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Lösenord" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "Internet förbindelse:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "Logga mig automatiskt" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "Login information" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "Välkommen!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:58 -#, fuzzy +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "" -"Alla användare\n" -"Online användare" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:60 -#, fuzzy +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "" -"ADSL\n" -"Fiber" -#: ../gtk/main.ui.h:61 -#, fuzzy +#: ../gtk/main.ui.h:5 msgid "Default" -msgstr "%s (Default)" +msgstr "" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "Själv bild" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "Användarnamn" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Sök" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "Lägg till kontakt ifrån katalogen" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "Min nuvarande identitet" + #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "Apropå linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 @@ -955,6 +1008,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -982,15 +1036,14 @@ msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Linphone - Autentisering krävs" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "Mata in lösenordet för domänen" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "AnvändarID" @@ -1003,9 +1056,8 @@ msgid "Clear all" msgstr "" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "Ringer %s" +msgstr "" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" @@ -1032,297 +1084,409 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (tillval):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registreringsfrekvens (sek.):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "Route (tillval):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publicera närvaro information" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Konfigurera ett SIP konto" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "default ljudkort" -#: ../gtk/parameters.ui.h:2 -#, fuzzy +#: ../gtk/parameters.ui.h:5 msgid "a sound card" -msgstr "ett ljud kort\n" +msgstr "" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "default kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 -#, fuzzy -msgid "Audio codecs" -msgstr "" -"Audio codecs\n" -"Video codecs" - -#: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "" -"Audio codecs\n" -"Video codecs" - #: ../gtk/parameters.ui.h:8 -msgid "SIP (UDP)" +msgid "Audio codecs" msgstr "" #: ../gtk/parameters.ui.h:9 -msgid "SIP (TCP)" +msgid "Video codecs" msgstr "" #: ../gtk/parameters.ui.h:10 -msgid "SIP (TLS)" +msgid "C" msgstr "" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "Inställningar" +msgid "SIP (UDP)" +msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "Välj MTU (Maximum Transmission Unit):" +msgid "SIP (TCP)" +msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "Kicka DTMF koder som SIP info" +msgid "SIP (TLS)" +msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "Använd IPv6 istället av IPv4" +msgid "default" +msgstr "" #: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "Transport" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "Inställningar" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "Direkt förbindelse till Internet" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Bakom en NAT / brandvägg (specificera gatewap IP adress nedan)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "Publik IP adress:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "STUN server:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT och Brandvägg" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "Nätverksinställningar" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "Ring signal:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA speciell enhet (tillval):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "Mikrofon enhet:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "Ringning enhet:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "Uppspelningsenhet:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "Tillåta ekokancellering" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "Audio" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "Video ingångsenhet:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "Video upplösning:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "Video" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "Multimedia inställningar" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "Denna sektion specificerar din SIP adress när du inte använder ett SIP konto" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "Ditt synliga namn, e.g. Kalle Karlsson:" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "Ditt användarnamn:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "Din SIP adress:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "Default identitet" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Lägg till" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Editera" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "Ta bort" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "Proxy konton" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "Glöm alla lösenord" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "Integritet" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "Hantera SIP konton" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Möjliggör" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Ring signal:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Inaktivera" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "ALSA speciell enhet (tillval):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "Codecs" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Mikrofon enhet:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Ringning enhet:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Uppspelningsenhet:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "Tillåta ekokancellering" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Audio" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Video ingångsenhet:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 står för \"utan begränsning\"" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Video" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "Max upstream bandbreddshastighet i kbit/sek:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "Max downstream bandbreddshastighet i kbit/sek:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "Bandbreddskontroll" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Multimedia inställningar" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "Välj MTU (Maximum Transmission Unit):" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "Kicka DTMF koder som SIP info" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "Transport" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "Direkt förbindelse till Internet" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Publik IP adress:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "STUN server:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT och Brandvägg" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Nätverksinställningar" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Möjliggör" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Inaktivera" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "Språk" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "Visa avancerade inställningar" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "Nivå" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "Användarinterface" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "Klar" @@ -1338,18 +1502,13 @@ msgstr "Lägg till min lista" msgid "Search somebody" msgstr "Sök efter kontakter" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "Vänta" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "Inställningar" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1368,30 +1527,23 @@ msgid "Set DSCP values (in hexadecimal)" msgstr "" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "Ringer %s" +msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" msgstr "" -"Audio codecs\n" -"Video codecs" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" msgstr "" -"Audio codecs\n" -"Video codecs" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1399,14 +1551,32 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "Kontakt information" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Konfigurera ett SIP konto" +msgstr "" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" @@ -1420,139 +1590,242 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Användarnamn" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Lösenord" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "avbrytade" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "avslutade" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "missade" - -#: ../coreapi/linphonecore.c:243 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s på %s\n" -"Från: %s\n" -"Till: %s\n" -"Status: %s\n" -"Längd: %i min %i sek\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "Utgående samtal" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Skicka" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "I samtal" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Förlopp" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "Internet förbindelse:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "Logga mig automatiskt" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "Login information" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "Redo" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "Leta efter telefonnummer för destinationen..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "Kan inte nå dett nummer." - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"Kan inte förstå angiven SIP adress. En SIP adress vanligen ser ut som sip:" -"användare@domänen" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "Kontaktar" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "Kunde inte ringa" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 -#, fuzzy +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" -msgstr "kontaktar dig." +msgstr "" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "" - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "Kopplad" -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "avbrytade" +msgstr "" -#: ../coreapi/linphonecore.c:3102 -#, fuzzy +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "Kunde inte ringa" +msgstr "" -#: ../coreapi/linphonecore.c:3107 -#, fuzzy +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." -msgstr "Nuvarande samtal" - -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." msgstr "" -"Din dator verkar använda ALSA drivrutiner för ljud.\n" -"Detta är det bästa valet. Dock PCM OSS emuleringsmodulen\n" -"saknas och linphone behöver ha det. Var god exekvera\n" -"'modprobe snd-pcm-oss' som root för att ladda in den." -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Din dator verkar använda ALSA drivrutiner för ljud.\n" -"Detta är det bästa valet. Dock OSS mixer emuleringsmodulen\n" -"saknas och linphone behöver ha det. Var god exekvera\n" -"'modprobe snd-mixer-oss' som root för att ladda in den." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "STUN uppslagning pågår..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1601,10 +1874,14 @@ msgid "Pending" msgstr "Pågående" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "Okänd bug" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1612,7 +1889,7 @@ msgstr "" "SIP proxy adressen som du matade in är inte rätt, adressen måste starta med " "\"sip:\", följd av ett hostnamn" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1620,530 +1897,181 @@ msgstr "" "SIP adressen som du matade in är inte rätt. Adressen borde se ut som sip:" "namn@domän, såsom sip:peter@exempel.se" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "Leta efter telefonnummer för destinationen..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "Kan inte nå dett nummer." + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "Kunde inte logga in som %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "Ringer hos motparten." +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "Tidig media" -#: ../coreapi/callbacks.c:352 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:548 +#, c-format msgid "Call with %s is paused." -msgstr "Samtal med %s" +msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "Samtalet slut" +msgstr "" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "Samtalet slut." -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "Användare upptagen." -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "Användaren temporärt inte tillgänglig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "Användaren vill inte bli störd." -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:544 -#, fuzzy -msgid "No response." -msgstr "Inget svar inom angiven tid" - -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:564 -#, fuzzy +#: ../coreapi/callbacks.c:875 msgid "Redirected" -msgstr "Omdirigerat till %s..." - -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:606 -#, fuzzy +#: ../coreapi/callbacks.c:930 msgid "Call failed." -msgstr "Samtalet avböjdes." +msgstr "" -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lyckades." -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lyckades." -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislyckades: %s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Linphone - Autentisering krävs" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Du har %i missat samtal" msgstr[1] "Du har %i missade samtal" -#~ msgid "Chat with %s" -#~ msgstr "Chatta med %s" - -#~ msgid "Please choose a username:" -#~ msgstr "Välj ett användarnamn:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "Verifierar om '%s' är tillgänglig..." - -#~ msgid "Please wait..." -#~ msgstr "Var god dröj..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "Användarnamnet finns redan, försök med ett nytt namn." - -#~ msgid "Ok !" -#~ msgstr "Ok !" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "Kommunikationsproblem, prova igen senare." - -#~ msgid "Choosing a username" -#~ msgstr "Välj ditt användarnamn" - -#~ msgid "Verifying" -#~ msgstr "Verifierar" - -#~ msgid "Confirmation" -#~ msgstr "Bekräftelse" - -#~ msgid "Creating your account" -#~ msgstr "Skapar ditt konto" - -#~ msgid "Now ready !" -#~ msgstr "Klar nu!" - -#, fuzzy -#~ msgid "Contacts" -#~ msgstr "Kontaktar" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "På" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "Mata in användarnamn, telefonnummer eller SIP adress" - -#~ msgid "Lookup:" -#~ msgstr "Sök:" - -#~ msgid "in" -#~ msgstr "i" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "Registrera hos FONICS\n" -#~ "virtuella nätverk!" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - Autentisering krävs" - -#~ msgid "Unmute" -#~ msgstr "Mikrofon på" - -#~ msgid "Contact list" -#~ msgstr "Kontaktlista" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "Audio & Video" - -#~ msgid "Audio only" -#~ msgstr "Enbart audio" - -#~ msgid "Duration:" -#~ msgstr "Förlopp:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "Samtalshistorik" - -#~ msgid "_Linphone" -#~ msgstr "_inphone" - -#, fuzzy -#~ msgid "gtk-cancel" -#~ msgstr "Kopplad" - -#~ msgid "Register at startup" -#~ msgstr "Registrera vid start" - -#, fuzzy -#~ msgid "gtk-close" -#~ msgstr "Kopplad" - -#~ msgid "Ports" -#~ msgstr "Portar" - -#~ msgid "Alsa sound source" -#~ msgstr "Alsa ljud ingång" - -#~ msgid "Alsa sound output" -#~ msgstr "Also ljud utgång" - -#~ msgid "DTMF generator" -#~ msgstr "DTMF generare" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "Hög hastighet GSM codec" - -#~ msgid "The GSM codec" -#~ msgstr "GSM codec" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "Fånga ljud med OSS drivrutiner" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "Ljud utgång med OSS drivrutiner" - -#~ msgid "A filter to make conferencing" -#~ msgstr "Ett filter för konferens" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Raw filer och WAV läsare" - -#~ msgid "Wav file recorder" -#~ msgstr "WAV fil inspelare" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "En filter som skickar flera ingångar till en utgång" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "Den fria speex codec" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "Ett filter som kontrollerar och mäter ljudvolym" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "En video4linux kompatibel ingångsfilter för att strömma bilder" - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "En filter för att fånga bilder från Video4Linux-2 capabla kameror" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "En filter med statisk bild" - -#~ msgid "A pixel format converter" -#~ msgstr "En pixel format konverterare" - -#~ msgid "A video size converter" -#~ msgstr "En video storlek konverterare" - -#~ msgid "a small video size converter" -#~ msgstr "En liten video storlek konverterare" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "Echo cancellering med hjälp av speex" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "" -#~ "En filter som läser från sin ingång och kopierar till multipla utgångar" - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "Theora video encoder från xiph.org" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "Theora video codec från xiph.org, öppen källkod och utan royalties" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "Theora video decoder från xiph.org" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "En h.263 decoder via ffmpeg" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "En MPEG4 decoder via ffmpeg" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "En RTP/JPEG decoder via ffmpeg" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "En MJPEG decode via ffmpeg" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "En snow decoder via ffmpeg" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "En video h.263 encoder via ffmpeg" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "" -#~ "En video h.263 encoder via ffmpeg, kompatibel med den gamla RFC2190 " -#~ "specificationen." - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "En video MPEG4 encoder via ffmpeg" - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "En video snow encoder via ffmpeg" - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "En RTP/MJPEG encoder via ffmpeg" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "" -#~ "En video h.263 encoder via ffmpeg, kompatible med den gamla RFC2190 " -#~ "specifikationen." - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "Snow codec:en är öppen källkod och utan royalties.\n" -#~ "Den använder sig av innovativa tekniker som gör den en av de bästa. Codec:" -#~ "en implementeras inom ffmpeg projektet.\n" -#~ "Dock, den är under utveckling och kompatibiliteten mellan versioner kan " -#~ "inte garanteras." - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "En MJPEG encoder via ffmpeg" - -#, fuzzy -#~ msgid "A SDL-based video display" -#~ msgstr "En generisk video utgång" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "En video4windows kompatibel ingångsfilter för att strömma bilder." - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "En video för windows kompatibel ingångsfilter för att fånga bilder." - -#, fuzzy -#~ msgid "A video display based on windows DrawDib api" -#~ msgstr "En video utgångsfönster med SDL" - -#, fuzzy -#~ msgid "A filter that mixes down 16 bit sample audio streams" -#~ msgstr "En filter för att mäta nivåer på 16 bitars PCM audio strömmar" - -#, fuzzy -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "Ett filter som kontrollerar och mäter ljudvolym" - -#, fuzzy -#~ msgid "Inter ticker communication filter." -#~ msgstr "Error med förbindelsen till servern." - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "Fånga ljud med OSS drivrutiner" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "Ljud utgång med OSS drivrutiner" - -#, fuzzy -#~ msgid "A video display using X11+Xv" -#~ msgstr "En video utgångsfönster med SDL" - -#, fuzzy -#~ msgid "Sound capture filter for Android" -#~ msgstr "Fånga ljud med OSS drivrutiner" - -#, fuzzy -#~ msgid "Sound playback filter for Android" -#~ msgstr "Ljud utgång med OSS drivrutiner" - -#, fuzzy -#~ msgid "A filter that captures Android video." -#~ msgstr "Ett filter som kontrollerar och mäter ljudvolym" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "Din dator verkar vara kopplad till ett IPv6 nätverk. Default, använder " -#~ "linphone IPv4. Uppdatera din konfiguration om du vill använda IPv6." - -#~ msgid "Incoming call from %s" -#~ msgstr "Inkommande samtal från %s" - -#~ msgid "Assistant" -#~ msgstr "Assistent" - -#~ msgid "Show debug messages" -#~ msgstr "Visa debugfönstret" - -#~ msgid "Start call" -#~ msgstr "Ring" - -#~ msgid "_Modes" -#~ msgstr "_Media" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "Skapad av Simon Morlat\n" - -#~ msgid "Accept" -#~ msgstr "Godkänn" - -#~ msgid "Incoming call from" -#~ msgstr "Inkommande samtal från" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone - Inkommande samtal" - -#~ msgid "default soundcard\n" -#~ msgstr "default ljudkort\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "" -#~ "Motparten verkar ha avbrutit samtalet, samtalet kommer att avslutas." - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "Förlåt, men linphone stödjer inte flera samtliga samtal än!" - -#~ msgid "Could not reach destination." -#~ msgstr "Kunde inte nå motparten." - -#~ msgid "Request Cancelled." -#~ msgstr "Förfrågan avbruten." - -#~ msgid "Bad request" -#~ msgstr "Fel förfråga." - -#~ msgid "User cannot be found at given address." -#~ msgstr "Användaren kan inte hittas vid den angivna adressen." - -#~ msgid "Remote user cannot support any of proposed codecs." -#~ msgstr "Motparten stödjer ingen av de föreslagna codecs." - -#~ msgid "Timeout." -#~ msgstr "time out." - -#~ msgid "Remote host was found but refused connection." -#~ msgstr "Motparten hittades men ville inte ta emot samtalet." - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you\n" -#~ "to contact him using the following alternate resource:" -#~ msgstr "" -#~ "Användaren kan inte nås för tillfället men han/hon ber digatt kontakta " -#~ "honom/henna vid följande resurs:" - -#~ msgid "Digits" -#~ msgstr "Tangenter" - -#~ msgid "Main view" -#~ msgstr "Huvud vy" - -#~ msgid "No nat/firewall address supplied !" -#~ msgstr "Ingen NAT / brandväggs adress angiven!" - -#~ msgid "Invalid nat address '%s' : %s" -#~ msgstr "Fel NAT adress '%s': %s" - -#~ msgid "Gone" -#~ msgstr "Har gått" - -#~ msgid "Waiting for Approval" -#~ msgstr "Väntar för godkännandet" - -#~ msgid "Be Right Back" -#~ msgstr "Kommer strax tillbaka" - -#~ msgid "On The Phone" -#~ msgstr "På telefon" - -#~ msgid "Out To Lunch" -#~ msgstr "Lunchar" - -#~ msgid "Closed" -#~ msgstr "Stängt" - -#~ msgid "Unknown" -#~ msgstr "Okänd" - -#~ msgid "SIP address" -#~ msgstr "SIP Adress" - -#~ msgid "Bresilian" -#~ msgstr "Brasiliansk" - -#~ msgid "_View" -#~ msgstr "_Vy" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/tr.po b/po/tr.po new file mode 100644 index 000000000..0cf1f6ac7 --- /dev/null +++ b/po/tr.po @@ -0,0 +1,2094 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# faradundamarti , 2015 +msgid "" +msgstr "" +"Project-Id-Version: linphone-gtk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Turkish (http://www.transifex.com/belledonne-communications/" +"linphone-gtk/language/tr/)\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 +msgid "Aborted" +msgstr "İptal edildi" + +#: ../gtk/calllogs.c:321 +msgid "Missed" +msgstr "Yanıtsız" + +#: ../gtk/calllogs.c:324 +msgid "Declined" +msgstr "Reddedildi" + +#: ../gtk/calllogs.c:330 +#, c-format +msgid "%i minute" +msgid_plural "%i minutes" +msgstr[0] "" +msgstr[1] "" + +#: ../gtk/calllogs.c:333 +#, c-format +msgid "%i second" +msgid_plural "%i seconds" +msgstr[0] "" +msgstr[1] "" + +#: ../gtk/calllogs.c:338 +#, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" + +#: ../gtk/calllogs.c:342 +#, c-format +msgid "%s\t%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 +msgid "Conference" +msgstr "Grup görüşme" + +#: ../gtk/conference.c:46 +msgid "Me" +msgstr "" + +#: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 +#, c-format +msgid "Couldn't find pixmap file: %s" +msgstr "" + +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 +msgid "log to stdout some debug information while running." +msgstr "" + +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 +msgid "path to a file to write logs into." +msgstr "Günlükleri içine yazmak için bir dosya yolu" + +#: ../gtk/main.c:141 +msgid "Start linphone with video disabled." +msgstr "Linphonu görüntü olmadan başlat" + +#: ../gtk/main.c:142 +msgid "Start only in the system tray, do not show the main interface." +msgstr "Sadece sistem tepsisinde başlat, ana arayüzü gösterme." + +#: ../gtk/main.c:143 +msgid "address to call right now" +msgstr "adres ara" + +#: ../gtk/main.c:144 +msgid "" +"Specifiy a working directory (should be the base of the installation, eg: c:" +"\\Program Files\\Linphone)" +msgstr "" +"Bir çalışma dizini belirtin (kurulum temelinde olmalı,örneğin: c:\\Program " +"Files\\Linphone)" + +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "Yapılandırma dosyası" + +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "Ses yardımcısını çalıştır" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 +#, c-format +msgid "" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" +"If you answer no, this person will be temporarily blacklisted." +msgstr "" + +#: ../gtk/main.c:1135 +#, c-format +msgid "" +"Please enter your password for username %s\n" +" at realm %s:" +msgstr "" + +#: ../gtk/main.c:1256 +msgid "Call error" +msgstr "Çağrı yanlış" + +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 +msgid "Call ended" +msgstr "Çağrı sonlandırıldı" + +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 +msgid "Incoming call" +msgstr "Gelen çağrı" + +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 +msgid "Answer" +msgstr "Yanıt" + +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 +msgid "Decline" +msgstr "Reddet" + +#: ../gtk/main.c:1272 +msgid "Call paused" +msgstr "Çağrı duraklatıldı" + +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 +#, c-format +msgid "%s proposed to start video. Do you accept ?" +msgstr "" + +#: ../gtk/main.c:1508 +msgid "Website link" +msgstr "İnternet " + +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" + +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "Görüntülü internet telefonu" + +#: ../gtk/main.c:1627 +#, c-format +msgid "%s (Default)" +msgstr "" + +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 +#, c-format +msgid "We are transferred to %s" +msgstr "" + +#: ../gtk/main.c:1983 +msgid "" +"No sound cards have been detected on this computer.\n" +"You won't be able to send or receive audio calls." +msgstr "" + +#: ../gtk/main.c:2127 +msgid "A free SIP video-phone" +msgstr "Özgür bir SİP görüntülü-telefon" + +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "Merhaba\n" + +#: ../gtk/friendlist.c:506 +msgid "Add to addressbook" +msgstr "Adres defterine ekle" + +#: ../gtk/friendlist.c:692 +msgid "Presence status" +msgstr "durum bilgisi" + +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 +msgid "Name" +msgstr "Ad" + +#: ../gtk/friendlist.c:722 +msgid "Call" +msgstr "Çağrı" + +#: ../gtk/friendlist.c:727 +msgid "Chat" +msgstr "Söyleşi" + +#: ../gtk/friendlist.c:757 +#, c-format +msgid "Search in %s directory" +msgstr "" + +#: ../gtk/friendlist.c:926 +msgid "Invalid sip contact !" +msgstr "Geçersiz sip bağlantısı !" + +#: ../gtk/friendlist.c:978 +#, c-format +msgid "Edit contact '%s'" +msgstr "" + +#: ../gtk/friendlist.c:979 +#, c-format +msgid "Delete contact '%s'" +msgstr "" + +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 +#, c-format +msgid "Add new contact from %s directory" +msgstr "" + +#: ../gtk/propertybox.c:597 +msgid "Rate (Hz)" +msgstr "Hız (Hz)" + +#: ../gtk/propertybox.c:603 +msgid "Status" +msgstr "Durum" + +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "İP Bit hızı (kbit/s)" + +#: ../gtk/propertybox.c:627 +msgid "Parameters" +msgstr "Değişkenler" + +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 +msgid "Enabled" +msgstr "Etkin" + +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 +msgid "Disabled" +msgstr "Devre dışı" + +#: ../gtk/propertybox.c:901 +msgid "Account" +msgstr "Hesap" + +#: ../gtk/propertybox.c:1169 +msgid "English" +msgstr "İngilizce" + +#: ../gtk/propertybox.c:1170 +msgid "French" +msgstr "Fransızca" + +#: ../gtk/propertybox.c:1171 +msgid "Swedish" +msgstr "İsveççe" + +#: ../gtk/propertybox.c:1172 +msgid "Italian" +msgstr "İtalyanca" + +#: ../gtk/propertybox.c:1173 +msgid "Spanish" +msgstr "İspanyolca" + +#: ../gtk/propertybox.c:1174 +msgid "Brazilian Portugese" +msgstr "Brezilya Portekizcesi" + +#: ../gtk/propertybox.c:1175 +msgid "Polish" +msgstr "Lehçe" + +#: ../gtk/propertybox.c:1176 +msgid "German" +msgstr "Almanca" + +#: ../gtk/propertybox.c:1177 +msgid "Russian" +msgstr "Rusca" + +#: ../gtk/propertybox.c:1178 +msgid "Japanese" +msgstr "Japonca" + +#: ../gtk/propertybox.c:1179 +msgid "Dutch" +msgstr "Flemenkçe" + +#: ../gtk/propertybox.c:1180 +msgid "Hungarian" +msgstr "Macarca" + +#: ../gtk/propertybox.c:1181 +msgid "Czech" +msgstr "Çekce" + +#: ../gtk/propertybox.c:1182 +msgid "Chinese" +msgstr "Çince" + +#: ../gtk/propertybox.c:1183 +msgid "Traditional Chinese" +msgstr "Geleneksel Çince" + +#: ../gtk/propertybox.c:1184 +msgid "Norwegian" +msgstr "Norveççe" + +#: ../gtk/propertybox.c:1185 +msgid "Hebrew" +msgstr "İbranice" + +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "Sırpça" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 +msgid "" +"You need to restart linphone for the new language selection to take effect." +msgstr "" +"Yeni dil seçiminizin etkili olabilmesi için linfonu yeniden başlatmalısınız." + +#: ../gtk/propertybox.c:1325 +msgid "None" +msgstr "Hiçbiri" + +#: ../gtk/propertybox.c:1329 +msgid "SRTP" +msgstr "SRTP (Güvenli Gerçek Zamanlı Aktarım Protokolü)" + +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "DTLS" + +#: ../gtk/propertybox.c:1342 +msgid "ZRTP" +msgstr "ZRTP" + +#: ../gtk/update.c:80 +#, c-format +msgid "" +"A more recent version is availalble from %s.\n" +"Would you like to open a browser to download it ?" +msgstr "" + +#: ../gtk/update.c:91 +msgid "You are running the lastest version." +msgstr "En son sürümü çalıştırıyorsunuz" + +#: ../gtk/buddylookup.c:85 +msgid "Firstname, Lastname" +msgstr "İlk ad, Son ad" + +#: ../gtk/buddylookup.c:160 +msgid "Error communicating with server." +msgstr "Sunucuya bağlanma hatası" + +#: ../gtk/buddylookup.c:164 +msgid "Connecting..." +msgstr "Bağlanıyor..." + +#: ../gtk/buddylookup.c:168 +msgid "Connected" +msgstr "Bağlandı" + +#: ../gtk/buddylookup.c:172 +msgid "Receiving data..." +msgstr "Veri alınıyor..." + +#: ../gtk/buddylookup.c:180 +#, c-format +msgid "Found %i contact" +msgid_plural "Found %i contacts" +msgstr[0] "" +msgstr[1] "" + +#: ../gtk/setupwizard.c:160 +msgid "" +"Welcome!\n" +"This assistant will help you to use a SIP account for your calls." +msgstr "" +"Hoşgeldiniz!\n" +"Bu yardımcı,çağrılarınız için bir SIP hesabı kullanmanıza yardım edecek." + +#: ../gtk/setupwizard.c:169 +msgid "Create an account on linphone.org" +msgstr "linphone.org'da bir hesap oluştur" + +#: ../gtk/setupwizard.c:170 +msgid "I have already a linphone.org account and I just want to use it" +msgstr "" + +#: ../gtk/setupwizard.c:171 +msgid "I have already a sip account and I just want to use it" +msgstr "" + +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 +msgid "Username*" +msgstr "Kallanıcı adı*" + +#: ../gtk/setupwizard.c:222 +msgid "Password*" +msgstr "Parola*" + +#: ../gtk/setupwizard.c:225 +msgid "Domain*" +msgstr "Alan adı*" + +#: ../gtk/setupwizard.c:226 +msgid "Proxy" +msgstr "Vekil sunucu" + +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "linphone.org kullanıcı adınızı girin" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "Kullanıcı adı:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "Parola:" + +#: ../gtk/setupwizard.c:419 +msgid "(*) Required fields" +msgstr "(*) Zorunlu alanlar" + +#: ../gtk/setupwizard.c:420 +msgid "Username: (*)" +msgstr "Kullanıcı adı: (*)" + +#: ../gtk/setupwizard.c:422 +msgid "Password: (*)" +msgstr "Parola: (*)" + +#: ../gtk/setupwizard.c:424 +msgid "Email: (*)" +msgstr "E-posta: (*)" + +#: ../gtk/setupwizard.c:426 +msgid "Confirm your password: (*)" +msgstr "Parolanızı onaylayın: (*)" + +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" +msgstr "linphone güncellemeleri hakkında beni bilgilendir" + +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:494 +msgid "" +"Please validate your account by clicking on the link we just sent you by " +"email.\n" +"Then come back here and press Next button." +msgstr "" +"Lütfen size e-posta yoluyla gönderdiğimiz bağlantıyı tıklayarak hesabınızı " +"doğrulayın.\n" +"Sonra buraya geri dönün ve İleri düğmesine basın." + +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" +"Hata,hesap geçersiz,kullanıcı adı kullanılıyor veya sunucuya erişilemiyor.\n" +"Lütfen geri dönün ve tekrar deneyin." + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "Teşekkürler. Hesabınız yapılandırıldı ve kullanıma hazır." + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "SİP hesabı yapılandırma yardımcısı" + +#: ../gtk/setupwizard.c:578 +msgid "Welcome to the account setup assistant" +msgstr "Hesap açma yardımcısına hoşgeldiniz" + +#: ../gtk/setupwizard.c:583 +msgid "Account setup assistant" +msgstr "Hesap açma yardımcısı" + +#: ../gtk/setupwizard.c:588 +msgid "Configure your account (step 1/1)" +msgstr "Hesabınızı yapılandırın (adım 1/1)" + +#: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "sip kullanıcı adınızı girin (adım 1/1)" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "Hesap bilgilerini girin (adım 1/2)" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "Doğrulama (adım 2/2)" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "Hata" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 +msgid "Terminating" +msgstr "Sonlandırma" + +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format +msgid "Call #%i" +msgstr "" + +#: ../gtk/incall_view.c:155 +#, c-format +msgid "Transfer to call #%i with %s" +msgstr "" + +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 +msgid "Not used" +msgstr "Kullanılmıyor" + +#: ../gtk/incall_view.c:221 +msgid "ICE not activated" +msgstr "ICE etkin değil" + +#: ../gtk/incall_view.c:223 +msgid "ICE failed" +msgstr "ICE başarısız" + +#: ../gtk/incall_view.c:225 +msgid "ICE in progress" +msgstr "ICE sürüyor" + +#: ../gtk/incall_view.c:227 +msgid "Going through one or more NATs" +msgstr "" + +#: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 +msgid "Through a relay server" +msgstr "" + +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "Evrensel Tak-Çalıştır etkin değil" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "Evrensel Tak-Çalıştır ilerliyor" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "Evrensel Tak-Çalıştır kullanılamaz" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "Evrensel Tak-Çalıştır çalışıyor" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "Evrensel Tak-Çalıştır başarısız" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 +#, c-format +msgid "" +"download: %f\n" +"upload: %f (kbit/s)" +msgstr "" + +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 +msgid "Hang up" +msgstr "Telefonu kapatma" + +#: ../gtk/incall_view.c:510 +msgid "Calling..." +msgstr "" + +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" + +#: ../gtk/incall_view.c:524 +msgid "Incoming call" +msgstr "" + +#: ../gtk/incall_view.c:561 +msgid "good" +msgstr "iyi" + +#: ../gtk/incall_view.c:563 +msgid "average" +msgstr "orta" + +#: ../gtk/incall_view.c:565 +msgid "poor" +msgstr "kötü" + +#: ../gtk/incall_view.c:567 +msgid "very poor" +msgstr "çok kötü" + +#: ../gtk/incall_view.c:569 +msgid "too bad" +msgstr "" + +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 +msgid "unavailable" +msgstr "kullanılamaz" + +#: ../gtk/incall_view.c:715 +msgid "Secured by SRTP" +msgstr "SRTP güvencesi altında" + +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "DLTS güvencesi altında" + +#: ../gtk/incall_view.c:727 +#, c-format +msgid "Secured by ZRTP - [auth token: %s]" +msgstr "" + +#: ../gtk/incall_view.c:733 +msgid "Set unverified" +msgstr "Doğrulanmamış ayar" + +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 +msgid "Set verified" +msgstr "" + +#: ../gtk/incall_view.c:762 +msgid "In conference" +msgstr "" + +#: ../gtk/incall_view.c:762 +msgid "In call" +msgstr "" + +#: ../gtk/incall_view.c:798 +msgid "Paused call" +msgstr "" + +#: ../gtk/incall_view.c:834 +msgid "Call ended." +msgstr "" + +#: ../gtk/incall_view.c:865 +msgid "Transfer in progress" +msgstr "Aktarım sürüyor" + +#: ../gtk/incall_view.c:868 +msgid "Transfer done." +msgstr "Aktarım tamam" + +#: ../gtk/incall_view.c:871 +msgid "Transfer failed." +msgstr "Aktarım başarısız" + +#: ../gtk/incall_view.c:904 +msgid "Resume" +msgstr "Devam et" + +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 +msgid "Pause" +msgstr "Duraklat" + +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "(Duraklatıldı)" + +#: ../gtk/loginframe.c:75 +#, c-format +msgid "Please enter login information for %s" +msgstr "" + +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "Ses olmadığı algılandı" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "Çok düşük" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "İyi" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "Çok yüksek" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "Üç bip sesi duydun mu?" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "Ses tercihleri bulunamadı" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "Ses kontrol sistemi başlatılamıyor" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Hoşgeldiniz!\n" +"Bu yardımcı,Linphone'un ses ayarlarını yapılandırmanıza yardım edecek" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "Görüntü yakalama aygıtı" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "Ses yok" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "Sistem ses tercihleri" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "Oynatma aygıtı" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "Üç bip sesi çal" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "Kayıt tuşuna bas ve bazı kelimeler söyle" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "Kaydettiğin sesi dinle" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "Kayıt" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "Çalma" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "Ses Yardımcısı" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "Ses yardımcısı" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "Kaydet ve Oynat" + +#: ../gtk/main.ui.h:1 +msgid "All users" +msgstr "Tüm kullanıcılar" + +#: ../gtk/main.ui.h:2 +msgid "Online users" +msgstr "Çevrimiçi kullanıcılar" + +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 +msgid "Fiber Channel" +msgstr "" + +#: ../gtk/main.ui.h:5 +msgid "Default" +msgstr "Öntanımlı" + +#: ../gtk/main.ui.h:6 +msgid "Delete" +msgstr "Sil" + +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "_Seçenekler" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "_Yardım" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "Hata düzeltme penceresini göster" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "_Anasayfa" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "Güncellemeleri _Denetle" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "Hesap yardımcısı" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SİP adresi veya telefon numarası:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "Yeni bir arama başlat" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "Bağlantılar" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "Arama" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "Bağlantı ekle" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "Son çağrılar" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "" + +#: ../gtk/about.ui.h:1 +msgid "About Linphone" +msgstr "Linphone Hakkında" + +#: ../gtk/about.ui.h:2 +msgid "(C) Belledonne Communications, 2010\n" +msgstr "" +"(C) Belledonne Communications, 2010\n" +"\n" + +#: ../gtk/about.ui.h:4 +msgid "An internet video phone using the standard SIP (rfc3261) protocol." +msgstr "Standart SİP (rfc3261) protokolü kullanan görüntülü internet telefonu." + +#: ../gtk/about.ui.h:5 +msgid "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" +msgstr "" +"fr: Simon Morlat\n" +"en: Simon Morlat and Delphine Perreau\n" +"it: Alberto Zanoni \n" +"de: Jean-Jacques Sarton \n" +"sv: Daniel Nylander \n" +"es: Jesus Benitez \n" +"ja: YAMAGUCHI YOSHIYA \n" +"pt_BR: Rafael Caesar Lenzi \n" +"pl: Robert Nasiadek \n" +"cs: Petr Pisar \n" +"hu: anonymous\n" +"he: Eli Zaretskii \n" + +#: ../gtk/contact.ui.h:2 +msgid "SIP Address" +msgstr "SİP Adresi" + +#: ../gtk/contact.ui.h:3 +msgid "Show this contact presence status" +msgstr "" + +#: ../gtk/contact.ui.h:4 +msgid "Allow this contact to see my presence status" +msgstr "" + +#: ../gtk/contact.ui.h:5 +msgid "Contact information" +msgstr "Bağlantı bilgisi" + +#: ../gtk/log.ui.h:1 +msgid "Linphone debug window" +msgstr "Linphone hata giderme penceresi" + +#: ../gtk/log.ui.h:2 +msgid "Scroll to end" +msgstr "Sonuna kadar ilerleyin" + +#: ../gtk/password.ui.h:1 +msgid "Linphone - Authentication required" +msgstr "Linphone - Kimlik doğrulaması gerekli" + +#: ../gtk/password.ui.h:2 +msgid "Please enter the domain password" +msgstr "Lütfen alan adı parolası girin" + +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 +msgid "UserID" +msgstr "Kullanıcı kimliği" + +#: ../gtk/call_logs.ui.h:1 +msgid "Call history" +msgstr "Çağrı geçmişi" + +#: ../gtk/call_logs.ui.h:2 +msgid "Clear all" +msgstr "Hepsini temizle" + +#: ../gtk/call_logs.ui.h:3 +msgid "Call back" +msgstr "Geri arama" + +#: ../gtk/sip_account.ui.h:1 +msgid "Linphone - Configure a SIP account" +msgstr "Linphone - Bir SİP hesabı yapılandır" + +#: ../gtk/sip_account.ui.h:2 +msgid "Your SIP identity:" +msgstr "SİP kimliğiniz:" + +#: ../gtk/sip_account.ui.h:3 +msgid "Looks like sip:@" +msgstr "" + +#: ../gtk/sip_account.ui.h:4 +msgid "sip:" +msgstr "sip:" + +#: ../gtk/sip_account.ui.h:5 +msgid "SIP Proxy address:" +msgstr "SİP Vekil sunucu adresi:" + +#: ../gtk/sip_account.ui.h:6 +msgid "Looks like sip:" +msgstr "" + +#: ../gtk/sip_account.ui.h:7 +msgid "Registration duration (sec):" +msgstr "Kayıt süresi (saniye)" + +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + +#: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "Taşıma" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "Kayıt" + +#: ../gtk/sip_account.ui.h:13 +msgid "Publish presence information" +msgstr "" + +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "AVPF'yi etkinleştir" + +#: ../gtk/sip_account.ui.h:15 +msgid "Configure a SIP account" +msgstr "Bir SİP hesabı yapılandır" + +#: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "kimliği belirsiz" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "GSSAPI" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "SASL" + +#: ../gtk/parameters.ui.h:4 +msgid "default soundcard" +msgstr "öntanımlı ses kartı" + +#: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "Ses kartı" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "öntanımlı kamera" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "CIF" + +#: ../gtk/parameters.ui.h:8 +msgid "Audio codecs" +msgstr "Ses kodekleri" + +#: ../gtk/parameters.ui.h:9 +msgid "Video codecs" +msgstr "Görüntü kodekleri" + +#: ../gtk/parameters.ui.h:10 +msgid "C" +msgstr "C" + +#: ../gtk/parameters.ui.h:11 +msgid "SIP (UDP)" +msgstr "SIP (UDP)" + +#: ../gtk/parameters.ui.h:12 +msgid "SIP (TCP)" +msgstr "SIP (TCP)" + +#: ../gtk/parameters.ui.h:13 +msgid "SIP (TLS)" +msgstr "SIP (TLS)" + +#: ../gtk/parameters.ui.h:14 +msgid "default" +msgstr "" + +#: ../gtk/parameters.ui.h:15 +msgid "high-fps" +msgstr "" + +#: ../gtk/parameters.ui.h:16 +msgid "custom" +msgstr "" + +#: ../gtk/parameters.ui.h:17 +msgid "Settings" +msgstr "Ayarlar" + +#: ../gtk/parameters.ui.h:18 +msgid "This section defines your SIP address when not using a SIP account" +msgstr "" + +#: ../gtk/parameters.ui.h:19 +msgid "Your display name (eg: John Doe):" +msgstr "Görünecek adınız (örneğin: Faradunda Marti)" + +#: ../gtk/parameters.ui.h:20 +msgid "Your username:" +msgstr "Kullanıcı adınız:" + +#: ../gtk/parameters.ui.h:21 +msgid "Your resulting SIP address:" +msgstr "" + +#: ../gtk/parameters.ui.h:22 +msgid "Default identity" +msgstr "Öntanımlı kimlik" + +#: ../gtk/parameters.ui.h:23 +msgid "Wizard" +msgstr "Yardımcı" + +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "Ekle" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "Düzenle" + +#: ../gtk/parameters.ui.h:26 +msgid "Remove" +msgstr "Kaldır" + +#: ../gtk/parameters.ui.h:27 +msgid "Proxy accounts" +msgstr "" + +#: ../gtk/parameters.ui.h:28 +msgid "Erase all passwords" +msgstr "Bütün parolaları sil" + +#: ../gtk/parameters.ui.h:29 +msgid "Privacy" +msgstr "Gizlilik" + +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "Otomatik yanıt" + +#: ../gtk/parameters.ui.h:33 +msgid "Manage SIP Accounts" +msgstr "SİP Hesaplarını Yönet" + +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "Zil sesi:" + +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "ALSA özel aygıt (seçmeli)" + +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "Görüntü yakalama aygıtı" + +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "Ses çalma aygıtı:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "Oynatma aygıtı:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "Ses" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "Görüntü aygıtı:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "Görüntü çıkış yöntemi:" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "Kamera önizlemesi göster" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 +msgid "0 stands for \"unlimited\"" +msgstr "" + +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "Görüntü" + +#: ../gtk/parameters.ui.h:49 +msgid "Upload speed limit in Kbit/sec:" +msgstr "Gönderim hız sınırı Kbit/saniye:" + +#: ../gtk/parameters.ui.h:50 +msgid "Download speed limit in Kbit/sec:" +msgstr "İndirme hız sınırı Kbit/saniye:" + +#: ../gtk/parameters.ui.h:51 +msgid "Enable adaptive rate control" +msgstr "" + +#: ../gtk/parameters.ui.h:52 +msgid "" +"Adaptive rate control is a technique to dynamically guess the available " +"bandwidth during a call." +msgstr "" + +#: ../gtk/parameters.ui.h:53 +msgid "Bandwidth control" +msgstr "Bantgenişliği denetimi" + +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "Çokluortam ayarları" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "SIP/UDP bağlantı noktası" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "Rastgele" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "SIP/TCP bağlantı noktası" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "" + +#: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "Sabitlenmiş" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "Ortam şifreleme türü" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "Ortam şifrelemesi zorunludur" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "Tünel" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "İnternete doğrudan bağlantı" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "Ortak İP adresi:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Stun sunucusu:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "Ağ ayarları" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Etkinleştirme" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Devre dışı" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 +msgid "Codecs" +msgstr "Çözücüler" + +#: ../gtk/parameters.ui.h:85 +msgid "Language" +msgstr "Dil" + +#: ../gtk/parameters.ui.h:86 +msgid "Show advanced settings" +msgstr "Gelişmiş ayarları göster" + +#: ../gtk/parameters.ui.h:87 +msgid "Level" +msgstr "Aşama" + +#: ../gtk/parameters.ui.h:88 +msgid "User interface" +msgstr "Kullanıcı arayüzü" + +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Sunucu adresi:" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Kimlik doğrulama yöntemi:" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "LDAP Hesap ayarı" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "LDAP" + +#: ../gtk/parameters.ui.h:94 +msgid "Done" +msgstr "Tamam" + +#: ../gtk/buddylookup.ui.h:1 +msgid "Search contacts in directory" +msgstr "" + +#: ../gtk/buddylookup.ui.h:2 +msgid "Add to my list" +msgstr "Listeme ekle" + +#: ../gtk/buddylookup.ui.h:3 +msgid "Search somebody" +msgstr "" + +#: ../gtk/waiting.ui.h:2 +msgid "Please wait" +msgstr "Lütfen bekleyin" + +#: ../gtk/dscp_settings.ui.h:1 +msgid "DSCP settings" +msgstr "DSCP ayarları" + +#: ../gtk/dscp_settings.ui.h:2 +msgid "SIP" +msgstr "SİP" + +#: ../gtk/dscp_settings.ui.h:3 +msgid "Audio RTP stream" +msgstr "" + +#: ../gtk/dscp_settings.ui.h:4 +msgid "Video RTP stream" +msgstr "" + +#: ../gtk/dscp_settings.ui.h:5 +msgid "Set DSCP values (in hexadecimal)" +msgstr "" + +#: ../gtk/call_statistics.ui.h:1 +msgid "Call statistics" +msgstr "Çağrı istatistikleri" + +#: ../gtk/call_statistics.ui.h:2 +msgid "Audio codec" +msgstr "Ses çözücü" + +#: ../gtk/call_statistics.ui.h:3 +msgid "Video codec" +msgstr "Görüntü çözücü" + +#: ../gtk/call_statistics.ui.h:4 +msgid "Audio IP bandwidth usage" +msgstr "" + +#: ../gtk/call_statistics.ui.h:5 +msgid "Audio Media connectivity" +msgstr "Ses Ortamı bağlanırlığı" + +#: ../gtk/call_statistics.ui.h:6 +msgid "Video IP bandwidth usage" +msgstr "" + +#: ../gtk/call_statistics.ui.h:7 +msgid "Video Media connectivity" +msgstr "Görüntü Ortamı bağlanırlığı" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "Sinyal gidiş-dönüş süresi" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Alınan görüntü çözünürlüğü" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Giden görüntü çözünürlüğü" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 +msgid "Call statistics and information" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:1 +msgid "Configure VoIP tunnel" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:2 +msgid "Host" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:3 +msgid "Port" +msgstr "Bağlantı noktası" + +#: ../gtk/tunnel_config.ui.h:6 +msgid "Configure tunnel" +msgstr "" + +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "Kallanıcı adı" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "Parola" + +#: ../gtk/tunnel_config.ui.h:9 +msgid "Configure http proxy (optional)" +msgstr "" + +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" +msgstr "LDAP Ayarları" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "TLS Bağlantısı Kullan" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "Henüz kullanılabilir değil" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "Ülke" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Yapılandırılıyor..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "Gönder" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "Grup görüşme son" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "Görüntü" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "Sessiz" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "Aktarım" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "Süre" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "İnternet bağlantısı:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "Hoşgeldiniz!" + +#: ../coreapi/linphonecore.c:1483 +msgid "Ready" +msgstr "Hazır" + +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "Yapılandırılıyor" + +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 +msgid "Contacting" +msgstr "Bağlanıyor" + +#: ../coreapi/linphonecore.c:2805 +msgid "Could not call" +msgstr "" + +#: ../coreapi/linphonecore.c:2956 +msgid "Sorry, we have reached the maximum number of simultaneous calls" +msgstr "" + +#: ../coreapi/linphonecore.c:3114 +msgid "is contacting you" +msgstr "" + +#: ../coreapi/linphonecore.c:3115 +msgid " and asked autoanswer." +msgstr "" + +#: ../coreapi/linphonecore.c:3241 +msgid "Modifying call parameters..." +msgstr "" + +#: ../coreapi/linphonecore.c:3625 +msgid "Connected." +msgstr "Bağlandı." + +#: ../coreapi/linphonecore.c:3650 +msgid "Call aborted" +msgstr "Çağrı iptal edildi" + +#: ../coreapi/linphonecore.c:3847 +msgid "Could not pause the call" +msgstr "" + +#: ../coreapi/linphonecore.c:3850 +msgid "Pausing the current call..." +msgstr "" + +#: ../coreapi/misc.c:436 +msgid "Stun lookup in progress..." +msgstr "" + +#: ../coreapi/misc.c:617 +msgid "ICE local candidates gathering in progress..." +msgstr "" + +#: ../coreapi/friend.c:33 +msgid "Online" +msgstr "Çevrimiçi" + +#: ../coreapi/friend.c:36 +msgid "Busy" +msgstr "Meşgul" + +#: ../coreapi/friend.c:39 +msgid "Be right back" +msgstr "Hemen döneceğim" + +#: ../coreapi/friend.c:42 +msgid "Away" +msgstr "Uzakta" + +#: ../coreapi/friend.c:45 +msgid "On the phone" +msgstr "Telefondayım" + +#: ../coreapi/friend.c:48 +msgid "Out to lunch" +msgstr "Yemekteyim" + +#: ../coreapi/friend.c:51 +msgid "Do not disturb" +msgstr "Rahatsız etmeyin" + +#: ../coreapi/friend.c:54 +msgid "Moved" +msgstr "Taşındı" + +#: ../coreapi/friend.c:57 +msgid "Using another messaging service" +msgstr "Diğer mesaj servisi kullanılıyor" + +#: ../coreapi/friend.c:60 +msgid "Offline" +msgstr "Çevrimdışı" + +#: ../coreapi/friend.c:63 +msgid "Pending" +msgstr "Bekliyor" + +#: ../coreapi/friend.c:66 +msgid "Vacation" +msgstr "Tatil" + +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "Bilinmeyen durum" + +#: ../coreapi/proxy.c:295 +msgid "" +"The sip proxy address you entered is invalid, it must start with \"sip:\" " +"followed by a hostname." +msgstr "" + +#: ../coreapi/proxy.c:301 +msgid "" +"The sip identity you entered is invalid.\n" +"It should look like sip:username@proxydomain, such as sip:alice@example.net" +msgstr "" + +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "" + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "" + +#: ../coreapi/proxy.c:1407 +#, c-format +msgid "Could not login as %s" +msgstr "" + +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 +msgid "Remote ringing." +msgstr "" + +#: ../coreapi/callbacks.c:454 +msgid "Remote ringing..." +msgstr "" + +#: ../coreapi/callbacks.c:475 +msgid "Early media." +msgstr "" + +#: ../coreapi/callbacks.c:548 +#, c-format +msgid "Call with %s is paused." +msgstr "" + +#: ../coreapi/callbacks.c:561 +#, c-format +msgid "Call answered by %s - on hold." +msgstr "" + +#: ../coreapi/callbacks.c:571 +msgid "Call resumed." +msgstr "" + +#: ../coreapi/callbacks.c:575 +#, c-format +msgid "Call answered by %s." +msgstr "" + +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." +msgstr "" + +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "" + +#. we are being paused +#: ../coreapi/callbacks.c:642 +msgid "We are paused by other party." +msgstr "" + +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 +msgid "Call is updated by remote." +msgstr "" + +#: ../coreapi/callbacks.c:797 +msgid "Call terminated." +msgstr "Çağrı sonlandırıldı" + +#: ../coreapi/callbacks.c:825 +msgid "User is busy." +msgstr "Kullanıcı meşgul" + +#: ../coreapi/callbacks.c:826 +msgid "User is temporarily unavailable." +msgstr "" + +#. char *retrymsg=_("%s. Retry after %i minute(s)."); +#: ../coreapi/callbacks.c:828 +msgid "User does not want to be disturbed." +msgstr "Kullanıcı rahatsız edilmek istemiyor." + +#: ../coreapi/callbacks.c:829 +msgid "Call declined." +msgstr "Çağrı reddedildi." + +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "İstek zamanaşımına uğradı." + +#: ../coreapi/callbacks.c:875 +msgid "Redirected" +msgstr "Yeniden yönlendirildi" + +#: ../coreapi/callbacks.c:930 +msgid "Call failed." +msgstr "Arama başarısız" + +#: ../coreapi/callbacks.c:1008 +#, c-format +msgid "Registration on %s successful." +msgstr "" + +#: ../coreapi/callbacks.c:1009 +#, c-format +msgid "Unregistration on %s done." +msgstr "" + +#: ../coreapi/callbacks.c:1027 +msgid "no response timeout" +msgstr "" + +#: ../coreapi/callbacks.c:1030 +#, c-format +msgid "Registration on %s failed: %s" +msgstr "" + +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "Servis kullanımdışı, tekrar deneyin" + +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 +#, c-format +msgid "You have missed %i call." +msgid_plural "You have missed %i calls." +msgstr[0] "" +msgstr[1] "" + +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "iptal edildi" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "tamamlandı" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "Yanıtsız" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "bilinmeyen" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 85fa75c47..1b9b07725 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,191 +1,211 @@ -# SIP Telephony Application. -# Copyright (C) 2001, 2002, 2011 Free Software Foundation, Inc. -# Simon Morlat , 2001. -# Jiang Honglei, 2002. -# Aron Xu , 2011. -# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: linphone 3.3.2\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2011-01-08 23:51+0800\n" -"Last-Translator: Aron Xu \n" -"Language-Team: Chinese (simplified) \n" -"Language: zh\n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Chinese (China) (http://www.transifex.com/belledonne-" +"communications/linphone-gtk/language/zh_CN/)\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "呼叫 %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "发送消息给 %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "中断" +msgstr "" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "丢失" +msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "拒绝" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 -#, fuzzy +#: ../gtk/conference.c:46 msgid "Me" -msgstr "静音" +msgstr "" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "运行时向标准输出记录调试信息。" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "启动到系统托盘,不显示主界面。" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "现在呼叫的地址" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "是否设置呼叫自动应答" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "指定工作目录(应为安装目录例如 C:\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "与 %s 通话" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s 想加您为联系人。\n" -"您是否允许他看到您的在线状态或者将它加为您的联系人允许?\n" -"如果您回答否,则会将该人临时性的放入黑名单" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" -msgstr "请输入 %s@%s 的密码:" +" at realm %s:" +msgstr "" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "呼叫历史" +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "呼入" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "拒绝" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "中断" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "网站" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - 互联网视频电话" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (默认)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -193,175 +213,190 @@ msgstr "" "未在此计算机上检测到声卡。\n" "您无法发送或接收音频呼叫。" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "免费的 SIP 视频电话" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "在线状态" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名称" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "呼叫 %s" +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "在 %s 目录中查找 " -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "无效的 SIP 联系人!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "呼叫 %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "发送消息给 %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "编辑联系人 %s" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "从 %s 目录增加联系人 " -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "采样率(Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "状态" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "最小比特率(kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "参数" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "启用" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "禁用" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "帐户" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "英语" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "法语" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "瑞典语" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "意大利语" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "西班牙语" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "巴西葡萄牙语" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "波兰语" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "德语" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "俄语" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "日语" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "荷兰语" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "匈牙利语" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "捷克语" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重启 linphone 以使语言选择生效。" -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -404,534 +439,552 @@ msgid "Found %i contact" msgid_plural "Found %i contacts" msgstr[0] "找到 %i 联系方式" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"欢迎使用 Linphone!\n" -"设置向导将帮助您配置打网络电话的 SIP 帐户。" -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "通过选择一个用户名创建一个新的帐户" +msgstr "" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "我已经有一个帐户,并想使用原来的帐户" +msgstr "" -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "我已经有一个帐户,并想使用原来的帐户" - -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "用户名:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "密码:" - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "用户名" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "密码" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "用户名:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "密码:" + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "用户名:" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "密码:" +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "谢谢,您的帐户已经配置完毕,可以使用。" +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "谢谢,您的帐户已经配置完毕,可以使用。" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "欢迎使用帐户设置向导" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "帐户设置向导" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "配置 SIP 帐户" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -msgid "Error" +msgid "Configure your account (step 1/1)" msgstr "" #: ../gtk/setupwizard.c:592 -#, fuzzy +msgid "Enter your sip username (step 1/1)" +msgstr "" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" -msgstr "终止呼叫" +msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "呼叫 %s" +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "未找到" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" msgstr "" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "ICE 过滤器" +msgid "ICE not activated" +msgstr "" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "已重定向" +msgid "Going through one or more NATs" +msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "正在呼叫..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 -#, fuzzy +#: ../gtk/incall_view.c:524 msgid "Incoming call" -msgstr "呼入" +msgstr "" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 -#, fuzzy +#: ../gtk/incall_view.c:762 msgid "In call" -msgstr "正在呼叫" +msgstr "" -#: ../gtk/incall_view.c:669 -#, fuzzy +#: ../gtk/incall_view.c:798 msgid "Paused call" -msgstr "正在呼叫" +msgstr "" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i::%02i::%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "通话结束。" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 +#: ../gtk/incall_view.c:868 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "呼叫失败。" +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "请输入 %s 的登录信息" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "通话结束。" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "发送" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "标签" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "呼入" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "通话时间" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "启用自视" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:21 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone 调试窗口" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "_Homepage" -msgstr "主页" - -#: ../gtk/main.ui.h:23 -#, fuzzy -msgid "Check _Updates" -msgstr "检查更新" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "帐户设置向导" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "SIP 地址或电话号码:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "添加" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "编辑" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "搜索" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "从目录增加联系人" - -#: ../gtk/main.ui.h:47 -#, fuzzy -msgid "Add contact" -msgstr "找到 %i 联系方式" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "数字键盘" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "呼入" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "当前地址:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "用户名" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "密码" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "网络连接:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "自动登录" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "登录信息" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "欢迎!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:58 -#, fuzzy +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "" -"全部用户\n" -"在线用户" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:60 -#, fuzzy +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "" -"ADSL\n" -"光纤" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "默认" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "启用自视" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIP 地址或电话号码:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "联系人" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "搜索" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "从目录增加联系人" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "当前地址:" + #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "关于 Linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" msgstr "" #: ../gtk/about.ui.h:4 @@ -951,19 +1004,8 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -"zh_CN: Jiang Honglei 和 Aron Xu \n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -990,15 +1032,14 @@ msgid "Scroll to end" msgstr "" #: ../gtk/password.ui.h:1 -#, fuzzy msgid "Linphone - Authentication required" -msgstr "Linphone - 需要认证" +msgstr "" #: ../gtk/password.ui.h:2 msgid "Please enter the domain password" msgstr "请输入密码" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "用户 ID" @@ -1011,9 +1052,8 @@ msgid "Clear all" msgstr "" #: ../gtk/call_logs.ui.h:3 -#, fuzzy msgid "Call back" -msgstr "呼叫 %s" +msgstr "" #: ../gtk/sip_account.ui.h:1 msgid "Linphone - Configure a SIP account" @@ -1040,299 +1080,408 @@ msgid "Looks like sip:" msgstr "类似于 sip:<代理主机名>" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "路由(可选):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "注册间隔(秒):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "路由(可选):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "发布在线状态" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "配置 SIP 帐户" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "默认声卡" -#: ../gtk/parameters.ui.h:2 -#, fuzzy +#: ../gtk/parameters.ui.h:5 msgid "a sound card" -msgstr "声卡\n" +msgstr "" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "默认摄像头" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 -#, fuzzy +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "" -"音频编解码器\n" -"视频编解码器" - -#: ../gtk/parameters.ui.h:6 -#, fuzzy -msgid "Video codecs" -msgstr "" -"音频编解码器\n" -"视频编解码器" - -#: ../gtk/parameters.ui.h:8 -#, fuzzy -msgid "SIP (UDP)" -msgstr "SIP (UDP):" #: ../gtk/parameters.ui.h:9 -#, fuzzy -msgid "SIP (TCP)" -msgstr "SIP (UDP):" +msgid "Video codecs" +msgstr "" #: ../gtk/parameters.ui.h:10 -#, fuzzy -msgid "SIP (TLS)" -msgstr "SIP (UDP):" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "设置" +msgid "SIP (UDP)" +msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "设置最大传输单元(MTU):" +msgid "SIP (TCP)" +msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "以 SIP 消息发送 DTMF" +msgid "SIP (TLS)" +msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "使用 IPv6 而非 IPv4" +msgid "default" +msgstr "" #: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "传输协议" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "设置" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "视频 RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "音频 RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "直接连接到互联网" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "在 NAT 或防火墙后(填写网关 IP)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "公网 IP 地址:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "在 NAT 或防火墙后(使用 STUN 解决)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "在 NAT 或防火墙后(使用 STUN 解决)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "Stun 服务器:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT 及防火墙" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "网络设置" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "铃声文件:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA 特殊设备(可选):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "录音设备:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "响铃设备:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "回放设备:" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "启用回声抑制" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "音频" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "视频输入设备:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "视频分辨率:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "视频" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "音视频设置" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "该段在您不使用SIP帐户时的SIP地址" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "您的显示名:" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "您的用户名:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "您的 SIP 地址结果:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "默认帐户" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "添加" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "编辑" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "移除" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "代理帐户" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "清除所有密码" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "隐私" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "SIP 帐户管理" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "启用" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "铃声文件:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "禁用" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "ALSA 特殊设备(可选):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "编解码器" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "录音设备:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "响铃设备:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "回放设备:" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "启用回声抑制" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "音频" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "视频输入设备:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 表示 “没有限制”" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "视频" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "上传速率限制 kbit/s:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "下载速率限制 kbit/s:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "带宽控制" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "音视频设置" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "设置最大传输单元(MTU):" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "以 SIP 消息发送 DTMF" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "传输协议" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "音频 RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "视频 RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "直接连接到互联网" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "在 NAT 或防火墙后(使用 STUN 解决)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "公网 IP 地址:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Stun 服务器:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT 及防火墙" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "网络设置" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "启用" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "禁用" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "编解码器" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "语言" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "显示高级设置" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "级别" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "用户界面" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "完成" @@ -1348,62 +1497,48 @@ msgstr "添加为联系人" msgid "Search somebody" msgstr "找人" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "请稍候" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "设置" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "音频重采样" +msgstr "" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "视频 RTP/UDP:" +msgstr "" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" msgstr "" #: ../gtk/call_statistics.ui.h:1 -#, fuzzy msgid "Call statistics" -msgstr "呼叫详情" +msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" msgstr "" -"音频编解码器\n" -"视频编解码器" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" msgstr "" -"音频编解码器\n" -"视频编解码器" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1411,14 +1546,32 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "联系人信息" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "配置 SIP 帐户" +msgstr "" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" @@ -1432,135 +1585,242 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "用户名" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "密码" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "中断" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "完成" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "丢失" - -#: ../coreapi/linphonecore.c:243 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s @ %s\n" -"主叫:%s\n" -"被叫: %s\n" -"状态:%s\n" -"状态:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "呼出" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "发送" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "呼入" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "通话时间" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "网络连接:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "自动登录" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "登录信息" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "就绪" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "查询电话号码目的地..." - -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "该号码无法解析。" - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" msgstr "" -"无法解析给定的 SIP 地址,SIP 地址应有如下格式:\n" -"sip:用户名@域名" -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "联系中" -#: ../coreapi/linphonecore.c:2319 -#, fuzzy +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" -msgstr "无法呼叫" +msgstr "" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "正在联系您" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr " 并询问了自动回答。" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "." - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "已连接。" -#: ../coreapi/linphonecore.c:2931 -#, fuzzy +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" -msgstr "中断" +msgstr "" -#: ../coreapi/linphonecore.c:3102 -#, fuzzy +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" -msgstr "无法呼叫" +msgstr "" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"您的计算机正使用 ALSA 声音驱动。\n" -"ALSA 是最佳选择,然而 Linphone 必须的 PCM OSS 模拟模块缺失。\n" -"请以 root 用户运行 modprobe snd-pcm-oss 载入它。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"您的计算机正使用 ALSA 声音驱动。\n" -"ALSA 是最佳选择,然而 Linphone 必须的 Mixer OSS 模拟模块缺失。\n" -"请以 root 用户运行 modprobe snd-mixer-oss 载入它。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "正在进行 Stun 查找..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1609,16 +1869,20 @@ msgid "Pending" msgstr "挂起" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "未知错误" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "您输入的 SIP 代理地址无效,它必须是以“sip:”开头,并紧随一个主机名。" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1626,446 +1890,180 @@ msgstr "" "您输入的地址无效。\n" "它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "查询电话号码目的地..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "该号码无法解析。" + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "无法登录为 %s" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "响铃。" -#: ../coreapi/callbacks.c:296 -#, fuzzy +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." -msgstr "响铃。" +msgstr "" -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:352 -#, fuzzy, c-format +#: ../coreapi/callbacks.c:548 +#, c-format msgid "Call with %s is paused." -msgstr "与 %s 通话" +msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:376 -#, fuzzy +#: ../coreapi/callbacks.c:571 msgid "Call resumed." -msgstr "呼叫结束" +msgstr "" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" + +#: ../coreapi/callbacks.c:633 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:446 +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "通话结束。" -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "被叫正忙。" -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "您呼叫的用户暂时无法接通。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "用户已开启免打扰功能。" -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "呼叫被拒绝。" -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "没有响应。" +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "协议错误。" - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "已重定向" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "呼叫失败。" -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "成功注册到 %s" -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "已在 %s 解除注册。" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "没有响应,超时" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "注册到 %s 失败: %s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "Linphone - 需要认证" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您错过了 %i 个呼叫。" -#~ msgid "Chat with %s" -#~ msgstr "与 %s 通话" - -#~ msgid "Please choose a username:" -#~ msgstr "请选择用户名:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "检查 %s 是否可用..." - -#~ msgid "Please wait..." -#~ msgstr "请稍候..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "对不起,该用户已经存在,请换一个尝试。" - -#~ msgid "Ok !" -#~ msgstr "成功!" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "连接错误,请稍后重试。" - -#~ msgid "Choosing a username" -#~ msgstr "选择用户名:" - -#~ msgid "Verifying" -#~ msgstr "验证中" - -#~ msgid "Confirmation" -#~ msgstr "确认" - -#~ msgid "Creating your account" -#~ msgstr "正在创建您的帐户" - -#~ msgid "Now ready !" -#~ msgstr "就绪!" - -#~ msgid "Contacts" -#~ msgstr "联系人" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "启用" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "请输入用户名、电话号码或完整的 SIP 地址" - -#~ msgid "Lookup:" -#~ msgstr "查找:" - -#~ msgid "in" -#~ msgstr "于" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "注册到 FONICS\n" -#~ "虚拟网络!" - -#~ msgid "No common codecs" -#~ msgstr "未找到常用编解码器" - -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - 需要认证" - -#~ msgid "Unmute" -#~ msgstr "取消静音" - -#~ msgid "Contact list" -#~ msgstr "联系人列表" - -#, fuzzy -#~ msgid "Audio & video" -#~ msgstr "音频和视频" - -#~ msgid "Audio only" -#~ msgstr "音频" - -#~ msgid "Duration:" -#~ msgstr "通话计时:" - -#, fuzzy -#~ msgid "_Call history" -#~ msgstr "呼叫历史" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "Register at startup" -#~ msgstr "在启动时注册" - -#~ msgid "Ports" -#~ msgstr "端口" - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw 编码器" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw 解码器" - -#~ msgid "Alsa sound source" -#~ msgstr "Alsa 音频源" - -#~ msgid "Alsa sound output" -#~ msgstr "Alsa 音频输出" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "MacOS X 音频队列服务音频输入过滤器" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "MacOS X 音频队列服务音频回放过滤器" - -#~ msgid "DTMF generator" -#~ msgstr "DTMF 生成器" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "GSM 全速编解码器" - -#~ msgid "The GSM codec" -#~ msgstr "GSM 编解码器" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit" -#~ msgstr "MacOS X 音频队列服务音频输入过滤器" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit" -#~ msgstr "MacOS X 音频队列服务音频回放过滤器" - -#~ msgid "Raw files and wav reader" -#~ msgstr "原始文件和 Wav 读取器" - -#~ msgid "Wav file recorder" -#~ msgstr "Wav 文件记录器" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "将多个输入发送至单个输出。" - -#~ msgid "RTP output filter" -#~ msgstr "RTP 输出过滤器" - -#~ msgid "RTP input filter" -#~ msgstr "RTP 输入过滤器" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "优秀的自由软件编解码器 Speex" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "控制和调节音量的过滤器" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "用于图像流的 video4linux 兼容源过滤器" - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "用于从 Video4Linux2 驱动的摄像头获取图像的过滤器" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "输出静态图像的过滤器" - -#~ msgid "A pixel format converter" -#~ msgstr "像素格式转换器" - -#~ msgid "A video size converter" -#~ msgstr "视频尺寸转换器" - -#~ msgid "a small video size converter" -#~ msgstr "小的视频尺寸转换器" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "使用 Speex 库的回声抑制器" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "用于读取输入并复制到多个输出的过滤器" - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "来自 xiph.org 的 Theora 视频编码器" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "来自 xiph.org 的开源的自由软件编解码器 Theora" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "来自 xiph.org 的 Theora 视频解码器" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw 编码器" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw 解码器" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 库的 H.263 解码器" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 库的 MPEG4 解码器" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 库的 RTP/JPEG 解码器" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 库的 MJPEG 解码器" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 库的 snow 解码器" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 库的 H.263 编码器" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "使用 ffmpeg 库的 H.263 视频编码器,符合旧的 RFC2190" - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 库的 MPEG4 视频编码器" - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 库的 snow 编码器" - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 库的 RTP/MJPEG 编码器" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "使用 ffmpeg 库的 H.263 编码器,符合旧的 RFC2190" - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "Snow 编解码器是开源的自由软件。\n" -#~ "创新科技使 Snow 成为当今最有希望的视频编解码器。它在 ffmpeg 项目内实现。\n" -#~ "然而它仍处于开发中,稳定性和与其他版本的兼容性尚无法保证。" - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 库的 MJPEG 编码器" - -#, fuzzy -#~ msgid "A SDL-based video display" -#~ msgstr "通用视频显示" - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "使用 DirectShow 的摄像头抓取器" - -#, fuzzy -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "MacOS X 音频队列服务音频输入过滤器" - -#, fuzzy -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "MacOS X 音频队列服务音频回放过滤器" - -#, fuzzy -#~ msgid "Sound capture filter for Android" -#~ msgstr "OSS 驱动的音频输入过滤器" - -#, fuzzy -#~ msgid "Sound playback filter for Android" -#~ msgstr "OSS 驱动的音频回放过滤器" - -#, fuzzy -#~ msgid "A filter that captures Android video." -#~ msgstr "控制和调节音量的过滤器" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "您的机器有 IPv6 网络连接。Linphone 默认使用IPv4,如果您希望使用 IPv6 请更" -#~ "该配置。" - -#~ msgid "Sound capture filter for MacOS X Core Audio drivers" -#~ msgstr "MacOS X 核心声音驱动音频输入过滤器" - -#~ msgid "Sound playback filter for MacOS X Core Audio drivers" -#~ msgstr "MacOS X 核心声音驱动音频回放过滤器" - -#~ msgid "Incoming call from %s" -#~ msgstr "来自 %s 的呼叫" - -#~ msgid "Assistant" -#~ msgstr "配置向导" - -#~ msgid "Show debug messages" -#~ msgstr "显示调试信息" - -#~ msgid "Start call" -#~ msgstr "开始呼叫" - -#~ msgid "_Modes" -#~ msgstr "模式(_M)" - -#~ msgid "Created by Simon Morlat\n" -#~ msgstr "由 Simon Morlat 创建\n" - -#~ msgid "Accept" -#~ msgstr "接受" - -#~ msgid "Incoming call from" -#~ msgstr "来自" - -#~ msgid "Linphone - Incoming call" -#~ msgstr "Linphone - 呼入" - -#~ msgid "default soundcard\n" -#~ msgstr "默认声卡\n" - -#~ msgid "" -#~ "Remote end seems to have disconnected, the call is going to be closed." -#~ msgstr "对方断开连接,通话终止。" - -#~ msgid "Sorry, having multiple simultaneous calls is not supported yet !" -#~ msgstr "抱歉, 还不支持并发多路呼叫!" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/po/zh_TW.po b/po/zh_TW.po index dbc09613d..86a3b8f5e 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,193 +1,212 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. # +# Translators: msgid "" msgstr "" -"Project-Id-Version: linphone 3.4\n" +"Project-Id-Version: linphone-gtk\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-08 10:35+0100\n" -"PO-Revision-Date: 2011-04-06 21:24+0800\n" -"Last-Translator: Chao-Hsiung Liao \n" -"Language-Team: \n" -"Language: \n" +"POT-Creation-Date: 2015-08-24 11:11+0200\n" +"PO-Revision-Date: 2015-07-17 07:34+0000\n" +"Last-Translator: Belledonne Communications \n" +"Language-Team: Chinese (Taiwan) (http://www.transifex.com/belledonne-" +"communications/linphone-gtk/language/zh_TW/)\n" +"Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 -#, fuzzy +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:976 +#, c-format +msgid "Call %s" +msgstr "播打給 %s" + +#: ../gtk/calllogs.c:150 ../gtk/friendlist.c:977 +#, c-format +msgid "Send text to %s" +msgstr "傳送文字給 %s" + +#: ../gtk/calllogs.c:233 +#, c-format +msgid "Recent calls (%i)" +msgstr "" + +#: ../gtk/calllogs.c:315 +msgid "n/a" +msgstr "" + +#: ../gtk/calllogs.c:318 msgid "Aborted" -msgstr "已放棄" +msgstr "" -#: ../gtk/calllogs.c:85 -#, fuzzy +#: ../gtk/calllogs.c:321 msgid "Missed" -msgstr "未接" +msgstr "" -#: ../gtk/calllogs.c:88 -#, fuzzy +#: ../gtk/calllogs.c:324 msgid "Declined" -msgstr "拒接" +msgstr "" -#: ../gtk/calllogs.c:94 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:333 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:338 #, c-format msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:102 -msgid "n/a" -msgstr "" - -#: ../gtk/calllogs.c:105 +#: ../gtk/calllogs.c:342 #, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +msgid "%s\t%s" msgstr "" -#: ../gtk/conference.c:33 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/in_call_frame.ui.h:11 msgid "Conference" msgstr "" -#: ../gtk/conference.c:41 -#, fuzzy +#: ../gtk/conference.c:46 msgid "Me" -msgstr "靜音" +msgstr "" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/main.c:89 +#: ../gtk/chat.c:493 +msgid "Copy" +msgstr "" + +#: ../gtk/main.c:138 msgid "log to stdout some debug information while running." msgstr "執行時將一些除錯資訊記錄到標準輸出。" -#: ../gtk/main.c:96 +#: ../gtk/main.c:139 +msgid "display version and exit." +msgstr "" + +#: ../gtk/main.c:140 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:103 +#: ../gtk/main.c:141 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:110 +#: ../gtk/main.c:142 msgid "Start only in the system tray, do not show the main interface." msgstr "只在系統匣啟動,不要顯示主要介面。" -#: ../gtk/main.c:117 +#: ../gtk/main.c:143 msgid "address to call right now" msgstr "現在要打電話的位址" -#: ../gtk/main.c:124 -msgid "if set automatically answer incoming calls" -msgstr "如啟用此項,將會自動接聽來電" - -#: ../gtk/main.c:131 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" "指定一個工作目錄(應該為安裝的根目錄,例如:c:\\Program Files\\Linphone)" -#: ../gtk/main.c:498 -#, c-format -msgid "Call with %s" -msgstr "和 %s 通話" +#: ../gtk/main.c:145 +msgid "Configuration file" +msgstr "" -#: ../gtk/main.c:871 +#: ../gtk/main.c:146 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:147 +msgid "Run self test and exit 0 if succeed" +msgstr "" + +#: ../gtk/main.c:1058 #, c-format msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" +"%s would like to add you to his/her contact list.\n" +"Would you add him/her to your contact list and allow him/her to see your " +"presence status?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" -"%s 想要加您加入他的連絡人清單。\n" -"您是否要允許他看見您的上線狀態或將他加入您的連絡人清單?\n" -"如果您回答否,這個人會被暫時列入黑名單。" -#: ../gtk/main.c:948 +#: ../gtk/main.c:1135 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -"請輸入您使用者名稱 %s\n" -"於網域 %s 的密碼:" -#: ../gtk/main.c:1051 -#, fuzzy +#: ../gtk/main.c:1256 msgid "Call error" -msgstr "通話紀錄" +msgstr "" -#: ../gtk/main.c:1054 ../coreapi/linphonecore.c:2949 +#: ../gtk/main.c:1259 ../coreapi/linphonecore.c:3669 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1057 ../coreapi/linphonecore.c:244 +#: ../gtk/main.c:1262 ../coreapi/call_log.c:221 msgid "Incoming call" msgstr "來電" -#: ../gtk/main.c:1059 ../gtk/incall_view.c:451 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1264 ../gtk/incall_view.c:531 ../gtk/in_call_frame.ui.h:3 msgid "Answer" msgstr "接聽" -#: ../gtk/main.c:1061 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1266 ../gtk/in_call_frame.ui.h:4 msgid "Decline" msgstr "拒接" -#: ../gtk/main.c:1067 -#, fuzzy +#: ../gtk/main.c:1272 msgid "Call paused" -msgstr "通話已放棄" - -#: ../gtk/main.c:1067 -#, c-format -msgid "by %s" msgstr "" -#: ../gtk/main.c:1116 +#: ../gtk/main.c:1272 +#, c-format +msgid "by %s" +msgstr "" + +#: ../gtk/main.c:1342 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1278 +#: ../gtk/main.c:1508 msgid "Website link" msgstr "網站連結" -#: ../gtk/main.c:1318 -msgid "Linphone - a video internet phone" -msgstr "Linphone - 網路視訊電話" +#: ../gtk/main.c:1567 ../gtk/waiting.ui.h:1 +msgid "Linphone" +msgstr "Linphone" -#: ../gtk/main.c:1410 +#: ../gtk/main.c:1568 +msgid "A video internet phone" +msgstr "" + +#: ../gtk/main.c:1627 #, c-format msgid "%s (Default)" msgstr "%s (預設值)" -#: ../gtk/main.c:1714 ../coreapi/callbacks.c:774 +#: ../gtk/main.c:1973 ../coreapi/callbacks.c:1078 #, c-format msgid "We are transferred to %s" msgstr "我們被轉接到 %s" -#: ../gtk/main.c:1724 +#: ../gtk/main.c:1983 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -195,175 +214,190 @@ msgstr "" "在這臺電腦中偵測不到音效卡。\n" "您將無法傳送或接收語音電話。" -#: ../gtk/main.c:1833 +#: ../gtk/main.c:2127 msgid "A free SIP video-phone" msgstr "自由的 SIP 視訊電話" -#: ../gtk/friendlist.c:335 +#: ../gtk/main.c:2236 +#, c-format +msgid "Hello\n" +msgstr "" + +#: ../gtk/friendlist.c:506 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:509 +#: ../gtk/friendlist.c:692 msgid "Presence status" msgstr "上線狀態" -#: ../gtk/friendlist.c:526 ../gtk/propertybox.c:362 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:710 ../gtk/propertybox.c:591 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名稱" -#: ../gtk/friendlist.c:538 -#, fuzzy +#: ../gtk/friendlist.c:722 msgid "Call" -msgstr "播打給 %s" +msgstr "" -#: ../gtk/friendlist.c:543 +#: ../gtk/friendlist.c:727 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:573 +#: ../gtk/friendlist.c:757 #, c-format msgid "Search in %s directory" msgstr "在 %s 目錄中搜尋" -#: ../gtk/friendlist.c:730 +#: ../gtk/friendlist.c:926 msgid "Invalid sip contact !" msgstr "無效的 sip 連絡人!" -#: ../gtk/friendlist.c:775 -#, c-format -msgid "Call %s" -msgstr "播打給 %s" - -#: ../gtk/friendlist.c:776 -#, c-format -msgid "Send text to %s" -msgstr "傳送文字給 %s" - -#: ../gtk/friendlist.c:777 +#: ../gtk/friendlist.c:978 #, c-format msgid "Edit contact '%s'" msgstr "編輯連絡人「%s」" -#: ../gtk/friendlist.c:778 +#: ../gtk/friendlist.c:979 #, c-format msgid "Delete contact '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:820 +#: ../gtk/friendlist.c:980 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:1031 #, c-format msgid "Add new contact from %s directory" msgstr "從 %s 目錄加入新的連絡人" -#: ../gtk/propertybox.c:368 +#: ../gtk/propertybox.c:597 msgid "Rate (Hz)" msgstr "頻率 (Hz)" -#: ../gtk/propertybox.c:374 +#: ../gtk/propertybox.c:603 msgid "Status" msgstr "狀態" -#: ../gtk/propertybox.c:380 -msgid "Min bitrate (kbit/s)" -msgstr "最小頻寬 (kbit/s)" +#: ../gtk/propertybox.c:616 +msgid "IP Bitrate (kbit/s)" +msgstr "" -#: ../gtk/propertybox.c:387 +#: ../gtk/propertybox.c:627 msgid "Parameters" msgstr "參數" -#: ../gtk/propertybox.c:430 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:669 ../gtk/propertybox.c:823 msgid "Enabled" msgstr "已啟用" -#: ../gtk/propertybox.c:432 ../gtk/propertybox.c:573 +#: ../gtk/propertybox.c:671 ../gtk/propertybox.c:823 ../gtk/parameters.ui.h:60 msgid "Disabled" msgstr "已停用" -#: ../gtk/propertybox.c:619 +#: ../gtk/propertybox.c:901 msgid "Account" msgstr "帳號" -#: ../gtk/propertybox.c:759 +#: ../gtk/propertybox.c:1169 msgid "English" msgstr "英語" -#: ../gtk/propertybox.c:760 +#: ../gtk/propertybox.c:1170 msgid "French" msgstr "法語" -#: ../gtk/propertybox.c:761 +#: ../gtk/propertybox.c:1171 msgid "Swedish" msgstr "瑞典語" -#: ../gtk/propertybox.c:762 +#: ../gtk/propertybox.c:1172 msgid "Italian" msgstr "義大利語" -#: ../gtk/propertybox.c:763 +#: ../gtk/propertybox.c:1173 msgid "Spanish" msgstr "西班牙語" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1174 msgid "Brazilian Portugese" msgstr "巴西葡萄牙語" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1175 msgid "Polish" msgstr "波蘭語" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1176 msgid "German" msgstr "德語" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1177 msgid "Russian" msgstr "俄語" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1178 msgid "Japanese" msgstr "日語" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1179 msgid "Dutch" msgstr "荷蘭語" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1180 msgid "Hungarian" msgstr "匈牙利語" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1181 msgid "Czech" msgstr "捷克語" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1182 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1183 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1184 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1185 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:842 +#: ../gtk/propertybox.c:1186 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:1187 +msgid "Arabic" +msgstr "" + +#: ../gtk/propertybox.c:1188 +msgid "Turkish" +msgstr "" + +#: ../gtk/propertybox.c:1245 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" -#: ../gtk/propertybox.c:912 +#: ../gtk/propertybox.c:1325 msgid "None" msgstr "" -#: ../gtk/propertybox.c:916 +#: ../gtk/propertybox.c:1329 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:922 +#: ../gtk/propertybox.c:1335 +msgid "DTLS" +msgstr "" + +#: ../gtk/propertybox.c:1342 msgid "ZRTP" msgstr "" @@ -406,522 +440,553 @@ msgid "Found %i contact" msgid_plural "Found %i contacts" msgstr[0] "找不到 %i 個連絡人" -#: ../gtk/setupwizard.c:33 +#: ../gtk/setupwizard.c:160 msgid "" -"Welcome !\n" +"Welcome!\n" "This assistant will help you to use a SIP account for your calls." msgstr "" -"歡迎!\n" -"這個助理會協助您使用電話的 SIP 帳號。" -#: ../gtk/setupwizard.c:42 -#, fuzzy +#: ../gtk/setupwizard.c:169 msgid "Create an account on linphone.org" -msgstr "以選擇的使用者名稱建立一個帳號" +msgstr "" -#: ../gtk/setupwizard.c:43 -#, fuzzy +#: ../gtk/setupwizard.c:170 msgid "I have already a linphone.org account and I just want to use it" -msgstr "我已經有帳號,並且要使用這個帳號" +msgstr "" -#: ../gtk/setupwizard.c:44 -#, fuzzy +#: ../gtk/setupwizard.c:171 msgid "I have already a sip account and I just want to use it" -msgstr "我已經有帳號,並且要使用這個帳號" - -#: ../gtk/setupwizard.c:84 -msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:91 -msgid "Username:" -msgstr "使用者名稱:" - -#: ../gtk/setupwizard.c:93 ../gtk/password.ui.h:4 -msgid "Password:" -msgstr "密碼: " - -#: ../gtk/setupwizard.c:113 -msgid "Enter your account informations" +#: ../gtk/setupwizard.c:172 +msgid "I want to specify a remote configuration URI" msgstr "" -#: ../gtk/setupwizard.c:120 -#, fuzzy +#: ../gtk/setupwizard.c:206 +msgid "Enter your account information" +msgstr "" + +#: ../gtk/setupwizard.c:221 msgid "Username*" -msgstr "使用者名稱" +msgstr "" -#: ../gtk/setupwizard.c:121 -#, fuzzy +#: ../gtk/setupwizard.c:222 msgid "Password*" -msgstr "密碼" +msgstr "" -#: ../gtk/setupwizard.c:124 +#: ../gtk/setupwizard.c:225 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:226 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:297 +#: ../gtk/setupwizard.c:263 +msgid "Enter your linphone.org username" +msgstr "" + +#: ../gtk/setupwizard.c:275 ../gtk/parameters.ui.h:91 ../gtk/ldap.ui.h:4 +msgid "Username:" +msgstr "使用者名稱:" + +#: ../gtk/setupwizard.c:277 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 +msgid "Password:" +msgstr "密碼: " + +#: ../gtk/setupwizard.c:419 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:298 -#, fuzzy +#: ../gtk/setupwizard.c:420 msgid "Username: (*)" -msgstr "使用者名稱:" +msgstr "" -#: ../gtk/setupwizard.c:300 -#, fuzzy +#: ../gtk/setupwizard.c:422 msgid "Password: (*)" -msgstr "密碼: " +msgstr "" -#: ../gtk/setupwizard.c:302 +#: ../gtk/setupwizard.c:424 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:304 +#: ../gtk/setupwizard.c:426 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:368 -msgid "" -"Error, account not validated, username already used or server unreachable.\n" -"Please go back and try again." +#: ../gtk/setupwizard.c:441 +msgid "Keep me informed with linphone updates" msgstr "" -#: ../gtk/setupwizard.c:379 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "謝謝您。您的帳號已設定完成並且可以使用。" +#: ../gtk/setupwizard.c:486 +msgid "Your account is being created, please wait." +msgstr "" -#: ../gtk/setupwizard.c:387 +#: ../gtk/setupwizard.c:494 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:554 +#: ../gtk/setupwizard.c:504 +msgid "Checking if your account is been validated, please wait." +msgstr "" + +#: ../gtk/setupwizard.c:512 +msgid "" +"Error, account not validated, username already used or server unreachable.\n" +"Please go back and try again." +msgstr "" + +#: ../gtk/setupwizard.c:521 +msgid "Thank you. Your account is now configured and ready for use." +msgstr "謝謝您。您的帳號已設定完成並且可以使用。" + +#: ../gtk/setupwizard.c:557 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:578 msgid "Welcome to the account setup assistant" msgstr "歡迎使用帳號設定助理" -#: ../gtk/setupwizard.c:559 +#: ../gtk/setupwizard.c:583 msgid "Account setup assistant" msgstr "帳號設定助理" -#: ../gtk/setupwizard.c:565 -#, fuzzy -msgid "Configure your account (step 1/1)" -msgstr "設定 SIP 帳號" - -#: ../gtk/setupwizard.c:570 -msgid "Enter your sip username (step 1/1)" -msgstr "" - -#: ../gtk/setupwizard.c:574 -msgid "Enter account information (step 1/2)" -msgstr "" - -#: ../gtk/setupwizard.c:583 -msgid "Validation (step 2/2)" -msgstr "" - #: ../gtk/setupwizard.c:588 -msgid "Error" +msgid "Configure your account (step 1/1)" msgstr "" #: ../gtk/setupwizard.c:592 +msgid "Enter your sip username (step 1/1)" +msgstr "" + +#: ../gtk/setupwizard.c:596 +msgid "Enter account information (step 1/2)" +msgstr "" + +#: ../gtk/setupwizard.c:601 +msgid "Account creation in progress" +msgstr "" + +#: ../gtk/setupwizard.c:605 +msgid "Validation (step 2/2)" +msgstr "" + +#: ../gtk/setupwizard.c:610 +msgid "Account validation check in progress" +msgstr "" + +#: ../gtk/setupwizard.c:614 +msgid "Error" +msgstr "" + +#: ../gtk/setupwizard.c:618 ../gtk/audio_assistant.c:541 msgid "Terminating" msgstr "" -#: ../gtk/incall_view.c:69 ../gtk/incall_view.c:90 -#, fuzzy, c-format +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#, c-format msgid "Call #%i" -msgstr "播打給 %s" +msgstr "" -#: ../gtk/incall_view.c:150 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:209 ../gtk/incall_view.c:212 -#, fuzzy +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" -msgstr "找不到" - -#: ../gtk/incall_view.c:219 -msgid "ICE not activated" msgstr "" #: ../gtk/incall_view.c:221 -#, fuzzy -msgid "ICE failed" -msgstr "ICE 過濾器" +msgid "ICE not activated" +msgstr "" #: ../gtk/incall_view.c:223 -msgid "ICE in progress" +msgid "ICE failed" msgstr "" #: ../gtk/incall_view.c:225 -msgid "Going through one or more NATs" +msgid "ICE in progress" msgstr "" #: ../gtk/incall_view.c:227 -#, fuzzy -msgid "Direct" -msgstr "已重新導向" +msgid "Going through one or more NATs" +msgstr "" #: ../gtk/incall_view.c:229 +msgid "Direct" +msgstr "" + +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:239 +msgid "uPnP not activated" +msgstr "" + +#: ../gtk/incall_view.c:241 +msgid "uPnP in progress" +msgstr "" + +#: ../gtk/incall_view.c:243 +msgid "uPnp not available" +msgstr "" + +#: ../gtk/incall_view.c:245 +msgid "uPnP is running" +msgstr "" + +#: ../gtk/incall_view.c:247 +msgid "uPnP failed" +msgstr "" + +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 +msgid "Direct or through server" +msgstr "" + +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:279 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:341 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:272 ../gtk/incall_view.c:274 +#, c-format +msgid "%ix%i @ %f fps" +msgstr "" + +#: ../gtk/incall_view.c:304 +#, c-format +msgid "%.3f seconds" +msgstr "" + +#: ../gtk/incall_view.c:406 ../gtk/in_call_frame.ui.h:10 +#: ../gtk/videowindow.c:235 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:430 +#: ../gtk/incall_view.c:510 msgid "Calling..." msgstr "播打..." -#: ../gtk/incall_view.c:433 ../gtk/incall_view.c:646 -msgid "00::00::00" -msgstr "00::00::00" +#: ../gtk/incall_view.c:513 ../gtk/incall_view.c:767 +msgid "00:00:00" +msgstr "00:00:00" -#: ../gtk/incall_view.c:444 +#: ../gtk/incall_view.c:524 msgid "Incoming call" msgstr "來電" -#: ../gtk/incall_view.c:481 +#: ../gtk/incall_view.c:561 msgid "good" msgstr "" -#: ../gtk/incall_view.c:483 +#: ../gtk/incall_view.c:563 msgid "average" msgstr "" -#: ../gtk/incall_view.c:485 +#: ../gtk/incall_view.c:565 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:567 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:489 +#: ../gtk/incall_view.c:569 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:506 +#: ../gtk/incall_view.c:570 ../gtk/incall_view.c:586 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:605 +#: ../gtk/incall_view.c:715 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:611 +#: ../gtk/incall_view.c:721 +msgid "Secured by DTLS" +msgstr "" + +#: ../gtk/incall_view.c:727 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:617 +#: ../gtk/incall_view.c:733 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:617 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:733 ../gtk/in_call_frame.ui.h:1 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:641 +#: ../gtk/incall_view.c:762 msgid "In call" msgstr "通話中" -#: ../gtk/incall_view.c:669 +#: ../gtk/incall_view.c:798 msgid "Paused call" msgstr "暫停通話" -#: ../gtk/incall_view.c:682 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "%02i::%02i::%02i" - -#: ../gtk/incall_view.c:699 +#: ../gtk/incall_view.c:834 msgid "Call ended." msgstr "通話結束。" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:865 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:734 -#, fuzzy +#: ../gtk/incall_view.c:868 msgid "Transfer done." -msgstr "轉接" +msgstr "" -#: ../gtk/incall_view.c:737 -#, fuzzy +#: ../gtk/incall_view.c:871 msgid "Transfer failed." -msgstr "轉接" +msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:904 msgid "Resume" msgstr "繼續" -#: ../gtk/incall_view.c:788 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:911 ../gtk/in_call_frame.ui.h:7 msgid "Pause" msgstr "暫停" -#: ../gtk/loginframe.c:93 +#: ../gtk/incall_view.c:977 +#, c-format +msgid "" +"Recording into\n" +"%s %s" +msgstr "" + +#: ../gtk/incall_view.c:977 +msgid "(Paused)" +msgstr "" + +#: ../gtk/loginframe.c:75 #, c-format msgid "Please enter login information for %s" msgstr "請輸入 %s 的 登入資訊" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + +#: ../gtk/audio_assistant.c:103 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:104 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:105 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:106 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:188 +msgid "Did you hear three beeps ?" +msgstr "" + +#: ../gtk/audio_assistant.c:299 ../gtk/audio_assistant.c:304 +msgid "Sound preferences not found " +msgstr "" + +#: ../gtk/audio_assistant.c:313 +msgid "Cannot launch system sound control " +msgstr "" + +#: ../gtk/audio_assistant.c:325 +msgid "" +"Welcome!\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:335 +msgid "Capture device" +msgstr "" + +#: ../gtk/audio_assistant.c:336 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:340 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:341 ../gtk/audio_assistant.c:380 +msgid "System sound preferences" +msgstr "" + +#: ../gtk/audio_assistant.c:376 +msgid "Playback device" +msgstr "" + +#: ../gtk/audio_assistant.c:377 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:410 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:411 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:412 +msgid "Record" +msgstr "" + +#: ../gtk/audio_assistant.c:413 +msgid "Play" +msgstr "" + +#: ../gtk/audio_assistant.c:440 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:510 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:520 ../gtk/main.ui.h:16 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:525 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:531 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:536 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 -#, fuzzy -msgid "Callee name" -msgstr "通話結束。" - -#: ../gtk/main.ui.h:2 -msgid "Send" -msgstr "傳送" - -#: ../gtk/main.ui.h:3 -msgid "End conference" -msgstr "" - -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "標籤" - -#: ../gtk/main.ui.h:8 -msgid "Video" -msgstr "" - -#: ../gtk/main.ui.h:10 -msgid "Mute" -msgstr "" - -#: ../gtk/main.ui.h:11 -msgid "Transfer" -msgstr "轉接" - -#: ../gtk/main.ui.h:14 -msgid "In call" -msgstr "通話中" - -#: ../gtk/main.ui.h:15 -msgid "Duration" -msgstr "時間長度" - -#: ../gtk/main.ui.h:16 -msgid "Call quality rating" -msgstr "" - -#: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "選項(_O)" - -#: ../gtk/main.ui.h:18 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:19 -msgid "Enable self-view" -msgstr "啟用自拍檢視" - -#: ../gtk/main.ui.h:20 -msgid "_Help" -msgstr "求助(_H)" - -#: ../gtk/main.ui.h:21 -msgid "Show debug window" -msgstr "顯示除錯視窗" - -#: ../gtk/main.ui.h:22 -msgid "_Homepage" -msgstr "官方網頁(_H)" - -#: ../gtk/main.ui.h:23 -msgid "Check _Updates" -msgstr "檢查更新(_U)" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Account assistant" -msgstr "帳號設定助理" - -#: ../gtk/main.ui.h:25 -msgid "SIP address or phone number:" -msgstr "SIP 位址或電話號碼:" - -#: ../gtk/main.ui.h:26 -msgid "Initiate a new call" -msgstr "打出新電話" - -#: ../gtk/main.ui.h:27 ../gtk/parameters.ui.h:48 -msgid "Add" -msgstr "加入" - -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:49 -msgid "Edit" -msgstr "編輯" - -#: ../gtk/main.ui.h:29 -msgid "D" -msgstr "D" - -#: ../gtk/main.ui.h:30 -msgid "#" -msgstr "#" - -#: ../gtk/main.ui.h:31 -msgid "0" -msgstr "0" - -#: ../gtk/main.ui.h:32 -msgid "*" -msgstr "*" - -#: ../gtk/main.ui.h:33 ../gtk/parameters.ui.h:7 -msgid "C" -msgstr "C" - -#: ../gtk/main.ui.h:34 -msgid "9" -msgstr "9" - -#: ../gtk/main.ui.h:35 -msgid "8" -msgstr "8" - -#: ../gtk/main.ui.h:36 -msgid "7" -msgstr "7" - -#: ../gtk/main.ui.h:37 -msgid "B" -msgstr "B" - -#: ../gtk/main.ui.h:38 -msgid "6" -msgstr "6" - -#: ../gtk/main.ui.h:39 -msgid "5" -msgstr "5" - -#: ../gtk/main.ui.h:40 -msgid "4" -msgstr "4" - -#: ../gtk/main.ui.h:41 -msgid "A" -msgstr "A" - -#: ../gtk/main.ui.h:42 -msgid "3" -msgstr "3" - -#: ../gtk/main.ui.h:43 -msgid "2" -msgstr "2" - -#: ../gtk/main.ui.h:44 -msgid "1" -msgstr "1" - -#: ../gtk/main.ui.h:45 -msgid "Search" -msgstr "搜尋" - -#: ../gtk/main.ui.h:46 -msgid "Add contacts from directory" -msgstr "從目錄加入連絡人" - -#: ../gtk/main.ui.h:47 -msgid "Add contact" -msgstr "加入聯絡人" - -#: ../gtk/main.ui.h:48 -msgid "Keypad" -msgstr "撥號盤" - -#: ../gtk/main.ui.h:49 -#, fuzzy -msgid "Recent calls" -msgstr "通話中" - -#: ../gtk/main.ui.h:50 -msgid "My current identity:" -msgstr "我目前的使用者識別:" - -#: ../gtk/main.ui.h:51 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "使用者名稱" - -#: ../gtk/main.ui.h:52 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "密碼" - -#: ../gtk/main.ui.h:53 -msgid "Internet connection:" -msgstr "網路連線:" - -#: ../gtk/main.ui.h:54 -msgid "Automatically log me in" -msgstr "將我自動登入" - -#: ../gtk/main.ui.h:55 -msgid "Login information" -msgstr "登入資訊" - -#: ../gtk/main.ui.h:56 -msgid "Welcome !" -msgstr "歡迎使用!" - -#: ../gtk/main.ui.h:57 msgid "All users" msgstr "所有使用者" -#: ../gtk/main.ui.h:58 +#: ../gtk/main.ui.h:2 msgid "Online users" msgstr "線上使用者" -#: ../gtk/main.ui.h:59 +#: ../gtk/main.ui.h:3 ../gtk/login_frame.ui.h:8 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:60 +#: ../gtk/main.ui.h:4 ../gtk/login_frame.ui.h:9 msgid "Fiber Channel" msgstr "光纖通道" -#: ../gtk/main.ui.h:61 +#: ../gtk/main.ui.h:5 msgid "Default" msgstr "預設值" -#: ../gtk/main.ui.h:62 +#: ../gtk/main.ui.h:6 msgid "Delete" msgstr "" +#: ../gtk/main.ui.h:7 +msgid "_Options" +msgstr "選項(_O)" + +#: ../gtk/main.ui.h:8 +msgid "Set configuration URI" +msgstr "" + +#: ../gtk/main.ui.h:9 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:10 +msgid "Enable self-view" +msgstr "啟用自拍檢視" + +#: ../gtk/main.ui.h:11 +msgid "_Help" +msgstr "求助(_H)" + +#: ../gtk/main.ui.h:12 +msgid "Show debug window" +msgstr "顯示除錯視窗" + +#: ../gtk/main.ui.h:13 +msgid "_Homepage" +msgstr "官方網頁(_H)" + +#: ../gtk/main.ui.h:14 +msgid "Check _Updates" +msgstr "檢查更新(_U)" + +#: ../gtk/main.ui.h:15 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:17 +msgid "SIP address or phone number:" +msgstr "SIP 位址或電話號碼:" + +#: ../gtk/main.ui.h:18 +msgid "Initiate a new call" +msgstr "打出新電話" + +#: ../gtk/main.ui.h:19 +msgid "Contacts" +msgstr "連絡人" + +#: ../gtk/main.ui.h:20 +msgid "Search" +msgstr "搜尋" + +#: ../gtk/main.ui.h:21 +msgid "Add contacts from directory" +msgstr "從目錄加入連絡人" + +#: ../gtk/main.ui.h:22 +msgid "Add contact" +msgstr "加入聯絡人" + +#: ../gtk/main.ui.h:23 +msgid "Recent calls" +msgstr "" + +#: ../gtk/main.ui.h:24 +msgid "My current identity:" +msgstr "我目前的使用者識別:" + #: ../gtk/about.ui.h:1 -msgid "About linphone" -msgstr "關於 linphone" +msgid "About Linphone" +msgstr "" #: ../gtk/about.ui.h:2 -msgid "(C) Belledonne Communications,2010\n" -msgstr "(C) Belledonne Communications,2010\n" +msgid "(C) Belledonne Communications, 2010\n" +msgstr "" #: ../gtk/about.ui.h:4 msgid "An internet video phone using the standard SIP (rfc3261) protocol." @@ -940,18 +1005,8 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" #: ../gtk/contact.ui.h:2 msgid "SIP Address" @@ -985,7 +1040,7 @@ msgstr "Linphone - 需要驗證" msgid "Please enter the domain password" msgstr "請輸入這個網域的密碼" -#: ../gtk/password.ui.h:3 +#: ../gtk/password.ui.h:3 ../gtk/login_frame.ui.h:5 msgid "UserID" msgstr "使用者ID" @@ -1026,292 +1081,408 @@ msgid "Looks like sip:" msgstr "看起來像 sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "路由 (選擇性):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "註冊時間 (秒):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "路由 (選擇性):" + +#: ../gtk/sip_account.ui.h:11 +msgid "Transport" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "發布上線資訊" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "設定 SIP 帳號" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "預設的音效卡" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "音效卡" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "預設的攝影機" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "音訊編碼解碼器" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "視訊編碼解碼器" -#: ../gtk/parameters.ui.h:8 -#, fuzzy -msgid "SIP (UDP)" -msgstr "SIP (UDP):" - -#: ../gtk/parameters.ui.h:9 -#, fuzzy -msgid "SIP (TCP)" -msgstr "SIP (TCP):" - #: ../gtk/parameters.ui.h:10 -#, fuzzy -msgid "SIP (TLS)" -msgstr "SIP (TCP):" +msgid "C" +msgstr "C" #: ../gtk/parameters.ui.h:11 -msgid "Settings" -msgstr "設定值" +msgid "SIP (UDP)" +msgstr "" #: ../gtk/parameters.ui.h:12 -msgid "Set Maximum Transmission Unit:" -msgstr "設定最大傳輸單位:" +msgid "SIP (TCP)" +msgstr "" #: ../gtk/parameters.ui.h:13 -msgid "Send DTMFs as SIP info" -msgstr "傳送 DTMFs 為 SIP 資訊" +msgid "SIP (TLS)" +msgstr "" #: ../gtk/parameters.ui.h:14 -msgid "Use IPv6 instead of IPv4" -msgstr "使用 IPv6 代替 IPv4" +msgid "default" +msgstr "" #: ../gtk/parameters.ui.h:15 -msgid "Transport" -msgstr "傳輸" +msgid "high-fps" +msgstr "" #: ../gtk/parameters.ui.h:16 -msgid "Media encryption type" +msgid "custom" msgstr "" #: ../gtk/parameters.ui.h:17 -msgid "Tunnel" -msgstr "" +msgid "Settings" +msgstr "設定值" #: ../gtk/parameters.ui.h:18 -msgid "Video RTP/UDP:" -msgstr "視訊 RTP/UDP:" - -#: ../gtk/parameters.ui.h:19 -msgid "Audio RTP/UDP:" -msgstr "音效 RTP/UDP:" - -#: ../gtk/parameters.ui.h:20 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:22 -msgid "Network protocol and ports" -msgstr "" - -#: ../gtk/parameters.ui.h:23 -msgid "Direct connection to the Internet" -msgstr "直接連線到網際網路" - -#: ../gtk/parameters.ui.h:24 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "在 NAT / 防火牆之後 (在下面指定閘道器 IP)" - -#: ../gtk/parameters.ui.h:25 -msgid "Public IP address:" -msgstr "公共 IP 地址:" - -#: ../gtk/parameters.ui.h:26 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" - -#: ../gtk/parameters.ui.h:27 -#, fuzzy -msgid "Behind NAT / Firewall (use ICE)" -msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" - -#: ../gtk/parameters.ui.h:28 -msgid "Stun server:" -msgstr "Stun 伺服器:" - -#: ../gtk/parameters.ui.h:29 -msgid "NAT and Firewall" -msgstr "NAT 與防火牆" - -#: ../gtk/parameters.ui.h:30 -msgid "Network settings" -msgstr "網路設定值" - -#: ../gtk/parameters.ui.h:31 -msgid "Ring sound:" -msgstr "鈴聲音效:" - -#: ../gtk/parameters.ui.h:32 -msgid "ALSA special device (optional):" -msgstr "ALSA 特殊裝置 (選擇性):" - -#: ../gtk/parameters.ui.h:33 -msgid "Capture device:" -msgstr "捕捉裝置:" - -#: ../gtk/parameters.ui.h:34 -msgid "Ring device:" -msgstr "響鈴裝置:" - -#: ../gtk/parameters.ui.h:35 -msgid "Playback device:" -msgstr "播放裝置" - -#: ../gtk/parameters.ui.h:36 -msgid "Enable echo cancellation" -msgstr "啟用回音消除" - -#: ../gtk/parameters.ui.h:37 -msgid "Audio" -msgstr "音效" - -#: ../gtk/parameters.ui.h:38 -msgid "Video input device:" -msgstr "視訊輸入裝置:" - -#: ../gtk/parameters.ui.h:39 -msgid "Prefered video resolution:" -msgstr "偏好的視訊解析度:" - -#: ../gtk/parameters.ui.h:40 -msgid "Video" -msgstr "視訊" - -#: ../gtk/parameters.ui.h:41 -msgid "Multimedia settings" -msgstr "多媒體設定值" - -#: ../gtk/parameters.ui.h:42 msgid "This section defines your SIP address when not using a SIP account" msgstr "這一區在不使用 SIP 帳號時定義您的 SIP 位址" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:19 msgid "Your display name (eg: John Doe):" msgstr "您的顯示名稱 (例如: John Doe):" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:20 msgid "Your username:" msgstr "您的使用者名稱:" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:21 msgid "Your resulting SIP address:" msgstr "您組成的 SIP 位址:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:22 msgid "Default identity" msgstr "預設身分識別" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:23 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:50 +#: ../gtk/parameters.ui.h:24 +msgid "Add" +msgstr "加入" + +#: ../gtk/parameters.ui.h:25 +msgid "Edit" +msgstr "編輯" + +#: ../gtk/parameters.ui.h:26 msgid "Remove" msgstr "移除" -#: ../gtk/parameters.ui.h:51 +#: ../gtk/parameters.ui.h:27 msgid "Proxy accounts" msgstr "代理伺服器帳號" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:28 msgid "Erase all passwords" msgstr "消除所有的密碼" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:29 msgid "Privacy" msgstr "隱私" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:30 +msgid "Automatically answer when a call is received" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Delay before answering (ms)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Auto-answer" +msgstr "" + +#: ../gtk/parameters.ui.h:33 msgid "Manage SIP Accounts" msgstr "管理 SIP 帳號" -#: ../gtk/parameters.ui.h:55 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "啟用" +#: ../gtk/parameters.ui.h:34 +msgid "Ring sound:" +msgstr "鈴聲音效:" -#: ../gtk/parameters.ui.h:56 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "停用" +#: ../gtk/parameters.ui.h:35 +msgid "ALSA special device (optional):" +msgstr "ALSA 特殊裝置 (選擇性):" -#: ../gtk/parameters.ui.h:57 -msgid "Codecs" -msgstr "編碼解碼器" +#: ../gtk/parameters.ui.h:36 +msgid "Capture device:" +msgstr "捕捉裝置:" -#: ../gtk/parameters.ui.h:58 +#: ../gtk/parameters.ui.h:37 +msgid "Ring device:" +msgstr "響鈴裝置:" + +#: ../gtk/parameters.ui.h:38 +msgid "Playback device:" +msgstr "播放裝置" + +#: ../gtk/parameters.ui.h:39 +msgid "Enable echo cancellation" +msgstr "啟用回音消除" + +#: ../gtk/parameters.ui.h:40 +msgid "Audio" +msgstr "音效" + +#: ../gtk/parameters.ui.h:41 +msgid "Video input device:" +msgstr "視訊輸入裝置:" + +#: ../gtk/parameters.ui.h:42 +msgid "Preferred video resolution:" +msgstr "" + +#: ../gtk/parameters.ui.h:43 +msgid "Video output method:" +msgstr "" + +#: ../gtk/parameters.ui.h:44 +msgid "Show camera preview" +msgstr "" + +#: ../gtk/parameters.ui.h:45 +msgid "Video preset:" +msgstr "" + +#: ../gtk/parameters.ui.h:46 +msgid "Preferred video framerate:" +msgstr "" + +#: ../gtk/parameters.ui.h:47 msgid "0 stands for \"unlimited\"" msgstr "0 表示「不限制」" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:48 +msgid "Video" +msgstr "視訊" + +#: ../gtk/parameters.ui.h:49 msgid "Upload speed limit in Kbit/sec:" msgstr "上傳速度限制於 Kbit/sec:" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:50 msgid "Download speed limit in Kbit/sec:" msgstr "下載速度限制於 Kbit/sec:" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:51 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:52 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:53 msgid "Bandwidth control" msgstr "頻寬控制" +#: ../gtk/parameters.ui.h:54 +msgid "Multimedia settings" +msgstr "多媒體設定值" + +#: ../gtk/parameters.ui.h:55 +msgid "Set Maximum Transmission Unit:" +msgstr "設定最大傳輸單位:" + +#: ../gtk/parameters.ui.h:56 +msgid "Send DTMFs as SIP info" +msgstr "傳送 DTMFs 為 SIP 資訊" + +#: ../gtk/parameters.ui.h:57 +msgid "Allow IPv6" +msgstr "" + +#: ../gtk/parameters.ui.h:58 +msgid "Transport" +msgstr "傳輸" + +#: ../gtk/parameters.ui.h:59 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:61 +msgid "Random" +msgstr "" + +#: ../gtk/parameters.ui.h:62 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:63 +msgid "Audio RTP/UDP:" +msgstr "音效 RTP/UDP:" + #: ../gtk/parameters.ui.h:64 +msgid "Fixed" +msgstr "" + +#: ../gtk/parameters.ui.h:65 +msgid "Video RTP/UDP:" +msgstr "視訊 RTP/UDP:" + +#: ../gtk/parameters.ui.h:66 +msgid "Media encryption type" +msgstr "" + +#: ../gtk/parameters.ui.h:67 +msgid "Media encryption is mandatory" +msgstr "" + +#: ../gtk/parameters.ui.h:68 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:69 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:70 +msgid "Network protocol and ports" +msgstr "" + +#: ../gtk/parameters.ui.h:71 +msgid "Direct connection to the Internet" +msgstr "直接連線到網際網路" + +#: ../gtk/parameters.ui.h:72 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:73 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" + +#: ../gtk/parameters.ui.h:74 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:75 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:76 +msgid "Public IP address:" +msgstr "公共 IP 地址:" + +#: ../gtk/parameters.ui.h:77 +msgid "Stun server:" +msgstr "Stun 伺服器:" + +#: ../gtk/parameters.ui.h:78 +msgid "NAT and Firewall" +msgstr "NAT 與防火牆" + +#: ../gtk/parameters.ui.h:79 +msgid "Network settings" +msgstr "網路設定值" + +#: ../gtk/parameters.ui.h:80 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "啟用" + +#: ../gtk/parameters.ui.h:81 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "停用" + +#: ../gtk/parameters.ui.h:82 +msgid "Audio codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:83 +msgid "Video codecs" +msgstr "" + +#: ../gtk/parameters.ui.h:84 msgid "Codecs" msgstr "編碼解碼器" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:85 msgid "Language" msgstr "語言" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:86 msgid "Show advanced settings" msgstr "顯示進階設定值" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:87 msgid "Level" msgstr "級數" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:88 msgid "User interface" msgstr "使用者介面" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:89 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "" + +#: ../gtk/parameters.ui.h:90 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "" + +#: ../gtk/parameters.ui.h:92 +msgid "LDAP Account setup" +msgstr "" + +#: ../gtk/parameters.ui.h:93 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:94 msgid "Done" msgstr "完成" @@ -1327,32 +1498,25 @@ msgstr "加入我的清單" msgid "Search somebody" msgstr "搜尋某人" -#: ../gtk/waiting.ui.h:1 -msgid "Linphone" -msgstr "Linphone" - #: ../gtk/waiting.ui.h:2 msgid "Please wait" msgstr "請稍候" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy -msgid "Dscp settings" -msgstr "設定值" +msgid "DSCP settings" +msgstr "" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" msgstr "" #: ../gtk/dscp_settings.ui.h:3 -#, fuzzy msgid "Audio RTP stream" -msgstr "音效重取樣器" +msgstr "" #: ../gtk/dscp_settings.ui.h:4 -#, fuzzy msgid "Video RTP stream" -msgstr "視訊 RTP/UDP:" +msgstr "" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" @@ -1363,21 +1527,19 @@ msgid "Call statistics" msgstr "" #: ../gtk/call_statistics.ui.h:2 -#, fuzzy msgid "Audio codec" -msgstr "音訊編碼解碼器" +msgstr "" #: ../gtk/call_statistics.ui.h:3 -#, fuzzy msgid "Video codec" -msgstr "視訊編碼解碼器" +msgstr "" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:5 -msgid "Media connectivity" +msgid "Audio Media connectivity" msgstr "" #: ../gtk/call_statistics.ui.h:6 @@ -1385,14 +1547,32 @@ msgid "Video IP bandwidth usage" msgstr "" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy +msgid "Video Media connectivity" +msgstr "" + +#: ../gtk/call_statistics.ui.h:8 +msgid "Round trip time" +msgstr "" + +#: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" -msgstr "連絡人資訊" +msgstr "" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "設定 SIP 帳號" +msgstr "" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" @@ -1406,132 +1586,242 @@ msgstr "" msgid "Configure tunnel" msgstr "" +#: ../gtk/tunnel_config.ui.h:7 ../gtk/login_frame.ui.h:1 +msgid "Username" +msgstr "使用者名稱" + +#: ../gtk/tunnel_config.ui.h:8 ../gtk/login_frame.ui.h:2 +msgid "Password" +msgstr "密碼" + #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" msgstr "" -#: ../coreapi/linphonecore.c:232 -msgid "aborted" -msgstr "已放棄" - -#: ../coreapi/linphonecore.c:235 -msgid "completed" -msgstr "已完成" - -#: ../coreapi/linphonecore.c:238 -msgid "missed" -msgstr "未接" - -#: ../coreapi/linphonecore.c:243 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" +#: ../gtk/ldap.ui.h:1 +msgid "LDAP Settings" msgstr "" -"%s 於 %s\n" -"從:%s\n" -"到:%s\n" -"狀態:%s\n" -"持續時間:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:244 -msgid "Outgoing call" -msgstr "去電" +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" -#: ../coreapi/linphonecore.c:1226 +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +msgid "Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +msgid "SASL" +msgstr "" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +msgid "SIP address attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +msgid "Search" +msgstr "" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +msgid "Miscellaneous" +msgstr "" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../gtk/chatroom_frame.ui.h:1 +msgid "Send" +msgstr "傳送" + +#: ../gtk/callee_frame.ui.h:1 +msgid "Callee name" +msgstr "" + +#: ../gtk/conf_frame.ui.h:1 +msgid "End conference" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:2 +msgid "Click here to set the speakers volume" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:5 +msgid "Record this call to an audio file" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:6 +msgid "Video" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:8 +msgid "Mute" +msgstr "" + +#: ../gtk/in_call_frame.ui.h:9 +msgid "Transfer" +msgstr "轉接" + +#: ../gtk/in_call_frame.ui.h:12 +msgid "In call" +msgstr "通話中" + +#: ../gtk/in_call_frame.ui.h:13 +msgid "Duration" +msgstr "時間長度" + +#: ../gtk/in_call_frame.ui.h:14 +msgid "Call quality rating" +msgstr "" + +#: ../gtk/login_frame.ui.h:3 +msgid "Internet connection:" +msgstr "網路連線:" + +#: ../gtk/login_frame.ui.h:4 +msgid "Automatically log me in" +msgstr "將我自動登入" + +#: ../gtk/login_frame.ui.h:6 +msgid "Login information" +msgstr "登入資訊" + +#: ../gtk/login_frame.ui.h:7 +msgid "Welcome!" +msgstr "" + +#: ../coreapi/linphonecore.c:1483 msgid "Ready" msgstr "準備就緒" -#: ../coreapi/linphonecore.c:2074 -msgid "Looking for telephone number destination..." -msgstr "尋找電話號碼目的端..." +#: ../coreapi/linphonecore.c:2415 +msgid "Configuring" +msgstr "" -#: ../coreapi/linphonecore.c:2077 -msgid "Could not resolve this number." -msgstr "無法解析這個號碼。" - -#: ../coreapi/linphonecore.c:2121 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "無法解析指定的 sip 位址。sip 網址通常看起來像 sip:user@domain" - -#: ../coreapi/linphonecore.c:2312 +#. must be known at that time +#: ../coreapi/linphonecore.c:2800 msgid "Contacting" msgstr "正在連絡" -#: ../coreapi/linphonecore.c:2319 +#: ../coreapi/linphonecore.c:2805 msgid "Could not call" msgstr "無法通話" -#: ../coreapi/linphonecore.c:2429 +#: ../coreapi/linphonecore.c:2956 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "抱歉,我們已達瀏同步通話的最大數目" -#: ../coreapi/linphonecore.c:2573 +#: ../coreapi/linphonecore.c:3114 msgid "is contacting you" msgstr "正在連絡您" -#: ../coreapi/linphonecore.c:2574 +#: ../coreapi/linphonecore.c:3115 msgid " and asked autoanswer." msgstr "並要求自動接聽。" -#: ../coreapi/linphonecore.c:2574 -msgid "." -msgstr "." - -#: ../coreapi/linphonecore.c:2636 +#: ../coreapi/linphonecore.c:3241 msgid "Modifying call parameters..." msgstr "修改通話參數..." -#: ../coreapi/linphonecore.c:2908 +#: ../coreapi/linphonecore.c:3625 msgid "Connected." msgstr "已連線。" -#: ../coreapi/linphonecore.c:2931 +#: ../coreapi/linphonecore.c:3650 msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3102 +#: ../coreapi/linphonecore.c:3847 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3107 +#: ../coreapi/linphonecore.c:3850 msgid "Pausing the current call..." msgstr "暫停目前的通話..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"您的電腦似乎是使用 ALSA 音效驅動程式。\n" -"這是最好的選擇。然而缺少了 pcm oss 模擬模組\n" -"而 linphone 需要它。請以 root 執行\n" -"'modprobe snd-pcm-oss' 載入它。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"您的電腦似乎是使用 ALSA 音效驅動程式。\n" -"這是最好的選擇。然而缺少了 mixer oss 模擬模組\n" -"而 linphone 需要它。請以 root 執行\n" -"'modprobe snd-mixer-oss' 載入它。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:436 msgid "Stun lookup in progress..." msgstr "正在進行 Stun 搜尋..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:617 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1580,17 +1870,21 @@ msgid "Pending" msgstr "等待中" #: ../coreapi/friend.c:66 -msgid "Unknown-bug" -msgstr "不明錯誤" +msgid "Vacation" +msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/friend.c:68 +msgid "Unknown status" +msgstr "" + +#: ../coreapi/proxy.c:295 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" "您輸入的 sip 代理位址是無效的,它必須要以「sip:」開頭,後面接主機名稱。" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:301 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1598,447 +1892,180 @@ msgstr "" "您輸入的 sip 身分是無效的。\n" "它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" -#: ../coreapi/proxy.c:1053 +#: ../coreapi/proxy.c:1010 +msgid "Looking for telephone number destination..." +msgstr "尋找電話號碼目的端..." + +#: ../coreapi/proxy.c:1014 +msgid "Could not resolve this number." +msgstr "無法解析這個號碼。" + +#: ../coreapi/proxy.c:1407 #, c-format msgid "Could not login as %s" msgstr "無法以 %s 登入" -#: ../coreapi/callbacks.c:276 +#: ../coreapi/proxy.c:1494 +#, c-format +msgid "Refreshing on %s..." +msgstr "" + +#: ../coreapi/callbacks.c:442 msgid "Remote ringing." msgstr "遠端響鈴。" -#: ../coreapi/callbacks.c:296 +#: ../coreapi/callbacks.c:454 msgid "Remote ringing..." msgstr "遠端響鈴..." -#: ../coreapi/callbacks.c:307 +#: ../coreapi/callbacks.c:475 msgid "Early media." msgstr "早期媒體。" -#: ../coreapi/callbacks.c:352 +#: ../coreapi/callbacks.c:548 #, c-format msgid "Call with %s is paused." msgstr "和 %s 的通話已暫停。" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:561 #, c-format msgid "Call answered by %s - on hold." msgstr "通話由 %s 接聽 - 保留中。" -#: ../coreapi/callbacks.c:376 +#: ../coreapi/callbacks.c:571 msgid "Call resumed." msgstr "通話已繼續。" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:575 #, c-format msgid "Call answered by %s." msgstr "通話由 %s 接聽。" -#: ../coreapi/callbacks.c:396 -msgid "Incompatible, check codecs..." +#: ../coreapi/callbacks.c:598 +msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:437 -#, fuzzy -msgid "We have been resumed." -msgstr "我們要繼續了..." +#: ../coreapi/callbacks.c:603 ../coreapi/callbacks.c:921 +msgid "Incompatible media parameters." +msgstr "" -#: ../coreapi/callbacks.c:446 +#: ../coreapi/callbacks.c:633 +msgid "We have been resumed." +msgstr "" + +#. we are being paused +#: ../coreapi/callbacks.c:642 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:452 +#. reINVITE and in-dialogs UPDATE go here +#: ../coreapi/callbacks.c:680 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:521 +#: ../coreapi/callbacks.c:797 msgid "Call terminated." msgstr "通話已終止。" -#: ../coreapi/callbacks.c:528 +#: ../coreapi/callbacks.c:825 msgid "User is busy." msgstr "使用者現正忙碌。" -#: ../coreapi/callbacks.c:529 +#: ../coreapi/callbacks.c:826 msgid "User is temporarily unavailable." msgstr "使用者暫時無法聯繫。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:531 +#: ../coreapi/callbacks.c:828 msgid "User does not want to be disturbed." msgstr "使用者不想要被打擾。" -#: ../coreapi/callbacks.c:532 +#: ../coreapi/callbacks.c:829 msgid "Call declined." msgstr "通話被拒接。" -#: ../coreapi/callbacks.c:544 -msgid "No response." -msgstr "沒有回應。" +#: ../coreapi/callbacks.c:844 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:548 -msgid "Protocol error." -msgstr "通訊協定錯誤。" - -#: ../coreapi/callbacks.c:564 +#: ../coreapi/callbacks.c:875 msgid "Redirected" msgstr "已重新導向" -#: ../coreapi/callbacks.c:600 -msgid "Incompatible media parameters." -msgstr "" - -#: ../coreapi/callbacks.c:606 +#: ../coreapi/callbacks.c:930 msgid "Call failed." msgstr "通話失敗。" -#: ../coreapi/callbacks.c:701 +#: ../coreapi/callbacks.c:1008 #, c-format msgid "Registration on %s successful." msgstr "在 %s 註冊成功。" -#: ../coreapi/callbacks.c:702 +#: ../coreapi/callbacks.c:1009 #, c-format msgid "Unregistration on %s done." msgstr "在 %s 取消註冊完成。" -#: ../coreapi/callbacks.c:722 +#: ../coreapi/callbacks.c:1027 msgid "no response timeout" msgstr "沒有回應逾時" -#: ../coreapi/callbacks.c:725 +#: ../coreapi/callbacks.c:1030 #, c-format msgid "Registration on %s failed: %s" msgstr "在 %s 註冊失敗:%s" -#: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format -msgid "Authentication token is %s" -msgstr "驗證失敗" +#: ../coreapi/callbacks.c:1037 +msgid "Service unavailable, retrying" +msgstr "" -#: ../coreapi/linphonecall.c:2124 +#. if encryption is DTLS, no status to be displayed +#: ../coreapi/linphonecall.c:181 +#, c-format +msgid "Authentication token is %s" +msgstr "" + +#: ../coreapi/linphonecall.c:1314 +msgid "Call parameters were successfully modified." +msgstr "" + +#: ../coreapi/linphonecall.c:3904 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您有 %i 通未接來電。" -#~ msgid "Chat with %s" -#~ msgstr "和 %s 聊天" - -#~ msgid "Please choose a username:" -#~ msgstr "請選擇一個使用者名稱:" - -#~ msgid "Checking if '%s' is available..." -#~ msgstr "檢查「%s」是否可用…" - -#~ msgid "Please wait..." -#~ msgstr "請稍候..." - -#~ msgid "Sorry this username already exists. Please try a new one." -#~ msgstr "很抱歉這個使用者名稱已經存在。請嘗試新的名稱。" - -#~ msgid "Ok !" -#~ msgstr "確定!" - -#~ msgid "Communication problem, please try again later." -#~ msgstr "連線問題,請稍後再試一次。" - -#~ msgid "Choosing a username" -#~ msgstr "選擇使用者名稱" - -#~ msgid "Verifying" -#~ msgstr "檢驗中" - -#~ msgid "Confirmation" -#~ msgstr "確認" - -#~ msgid "Creating your account" -#~ msgstr "正在建立您的帳號" - -#~ msgid "Now ready !" -#~ msgstr "現在已就緒!" - -#~ msgid "Contacts" -#~ msgstr "連絡人" - -#, fuzzy -#~ msgid "Enable video" -#~ msgstr "已啟用" - -#~ msgid "Enter username, phone number, or full sip address" -#~ msgstr "輸入使用者名稱、電話號碼或完整的 sip 位址" - -#~ msgid "Lookup:" -#~ msgstr "查詢:" - -#~ msgid "in" -#~ msgstr "於" - -#~ msgid "" -#~ "Register to FONICS\n" -#~ "virtual network !" -#~ msgstr "" -#~ "註冊到 FONICS\n" -#~ "虛擬網路!" - -#~ msgid "We are being paused..." -#~ msgstr "我們被暫停了..." - -#~ msgid "No common codecs" -#~ msgstr "沒有通用的編碼解碼器" - -#~ msgid "Authentication failure" -#~ msgstr "驗證失敗" - -#~ msgid "Windows" -#~ msgstr "視窗" - -#~ msgid "" -#~ "Pause all calls\n" -#~ "and answer" -#~ msgstr "" -#~ "暫停所有播打\n" -#~ "與接聽" - -#~ msgid "Unmute" -#~ msgstr "取消靜音" - -#~ msgid "Contact list" -#~ msgstr "連絡人清單 " - -#~ msgid "Audio & video" -#~ msgstr "語音 & 視訊" - -#~ msgid "Audio only" -#~ msgstr "只有語音" - -#~ msgid "Duration:" -#~ msgstr "時間長度:" - -#~ msgid "_Call history" -#~ msgstr "通話紀錄(_C)" - -#~ msgid "_Linphone" -#~ msgstr "_Linphone" - -#~ msgid "gtk-cancel" -#~ msgstr "gtk-cancel" - -#~ msgid "gtk-ok" -#~ msgstr "gtk-ok" - -#~ msgid "Register at startup" -#~ msgstr "啟動時註冊" - -#~ msgid "gtk-close" -#~ msgstr "gtk-close" - -#~ msgid "Ports" -#~ msgstr "連接埠" - -#~ msgid "Sorry, you have to pause or stop the current call first !" -#~ msgstr "抱歉,您必須先暫停或停止目前的通話!" - -#~ msgid "There is already a call in process, pause or stop it first." -#~ msgstr "已經有通話在進行中,請先暫停或停止它。" - -#~ msgid "" -#~ "Your machine appears to be connected to an IPv6 network. By default " -#~ "linphone always uses IPv4. Please update your configuration if you want " -#~ "to use IPv6" -#~ msgstr "" -#~ "您的電腦似乎連接到 IPv6 網路。linphone 預設會先使用 IPv4。如果您想要使用 " -#~ "IPv6 請更新您的組態" - -#~ msgid "ITU-G.711 alaw encoder" -#~ msgstr "ITU-G.711 alaw 編碼器" - -#~ msgid "ITU-G.711 alaw decoder" -#~ msgstr "ITU-G.711 alaw 解碼器" - -#~ msgid "Alsa sound output" -#~ msgstr "Alsa 音效輸出" - -#~ msgid "Sound capture filter for MacOS X Audio Queue Service" -#~ msgstr "MacOS X 音效佇列服務的音效擷取過濾器" - -#~ msgid "Sound playback filter for MacOS X Audio Queue Service" -#~ msgstr "MacOS X 音效佇列服務的音效播放過濾器" - -#~ msgid "DTMF generator" -#~ msgstr "DTMF 產生器" - -#~ msgid "The GSM full-rate codec" -#~ msgstr "GSM 全頻率編解碼器" - -#~ msgid "The GSM codec" -#~ msgstr "GSM 編解碼器" - -#~ msgid "Sound capture filter for MacOS X Core Audio drivers" -#~ msgstr "MacOS X 核心音效驅動程式的音效擷取過濾器" - -#~ msgid "Sound playback filter for MacOS X Core Audio drivers" -#~ msgstr "MacOS X 核心音效驅動程式的音效播放過濾器" - -#~ msgid "A filter to make conferencing" -#~ msgstr "進行會議的過濾器" - -#~ msgid "Raw files and wav reader" -#~ msgstr "Raw 檔案與 wav 讀取器" - -#~ msgid "Wav file recorder" -#~ msgstr "Wav 檔案錄製器" - -#~ msgid "A filter that send several inputs to one output." -#~ msgstr "傳送多個輸入到一個輸出的過濾器。" - -#~ msgid "RTP output filter" -#~ msgstr "RTP 輸出過濾隱器" - -#~ msgid "RTP input filter" -#~ msgstr "RTP 輸入過濾隱器" - -#~ msgid "The free and wonderful speex codec" -#~ msgstr "免費好用的 speex 編解碼器" - -#~ msgid "A filter that controls and measure sound volume" -#~ msgstr "控制並測量音量的過濾器" - -#~ msgid "A video4linux compatible source filter to stream pictures." -#~ msgstr "video4linux 相容來源過濾器至串流圖片。" - -#~ msgid "A filter to grab pictures from Video4Linux2-powered cameras" -#~ msgstr "從 Video4Linux2 攝影機擷取圖片的過濾器" - -#~ msgid "A filter that outputs a static image." -#~ msgstr "輸出靜態圖片的過濾器。" - -#~ msgid "A pixel format converter" -#~ msgstr "像素格式轉換器" - -#~ msgid "A video size converter" -#~ msgstr "視訊大小轉換器" - -#~ msgid "a small video size converter" -#~ msgstr "一個小型的視訊大小轉換器" - -#~ msgid "Echo canceller using speex library" -#~ msgstr "使用 speex 程式庫的回音消除器" - -#~ msgid "A filter that reads from input and copy to its multiple outputs." -#~ msgstr "從輸入讀取並將它複製到多個輸出的過濾器。" - -#~ msgid "The theora video encoder from xiph.org" -#~ msgstr "來自 xiph.org 的 theora 視訊編碼器" - -#~ msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -#~ msgstr "來自 xiph.org 的開放原始碼且沒有版稅的「theora」視訊編解碼器" - -#~ msgid "The theora video decoder from xiph.org" -#~ msgstr "來自 xiph.org 的 theora 視訊解碼器" - -#~ msgid "ITU-G.711 ulaw encoder" -#~ msgstr "ITU-G.711 ulaw 編碼器" - -#~ msgid "ITU-G.711 ulaw decoder" -#~ msgstr "ITU-G.711 ulaw 解碼器" - -#~ msgid "A H.263 decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 程式庫的 H.263 解碼器" - -#~ msgid "A MPEG4 decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 程式庫的 MPEG4 解碼器" - -#~ msgid "A RTP/JPEG decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 程式庫的 RTP/JPEG 解碼器" - -#~ msgid "A MJPEG decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 程式庫的 MJPEG 解碼器" - -#~ msgid "A snow decoder using ffmpeg library" -#~ msgstr "使用 ffmpeg 程式庫的 snow 解碼器" - -#~ msgid "A video H.263 encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 程式庫的視訊 H.263 編碼器。" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library. It is compliant with old " -#~ "RFC2190 spec." -#~ msgstr "使用 ffmpeg 程式庫的視訊 H.263 編碼器。它符合舊的 RFC2190 規格。" - -#~ msgid "A video MPEG4 encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 程式庫的視訊 MPEG4 編碼器。" - -#~ msgid "A video snow encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 程式庫的視訊 snow 編碼器。" - -#~ msgid "A RTP/MJPEG encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 程式庫的 RTP/MJPEG 編碼器。" - -#~ msgid "" -#~ "A video H.263 encoder using ffmpeg library, compliant with old RFC2190 " -#~ "spec." -#~ msgstr "使用 ffmpeg 程式庫的視訊 H.263 編碼器,它符合舊的 RFC2190 規格。" - -#~ msgid "" -#~ "The snow codec is royalty-free and is open-source. \n" -#~ "It uses innovative techniques that makes it one of most promising video " -#~ "codec. It is implemented within the ffmpeg project.\n" -#~ "However it is under development, quite unstable and compatibility with " -#~ "other versions cannot be guaranteed." -#~ msgstr "" -#~ "snow 編解碼器是免版稅的,而且是開放源始碼。 \n" -#~ "它採用創新技術,使一種最前瞻的視訊編解碼器。它在 ffmpeg 專案中實作。\n" -#~ "然而,它正在開發中,相當不穩定且不能保證與其他版本的相容性。" - -#~ msgid "A MJPEG encoder using ffmpeg library." -#~ msgstr "使用 ffmpeg 程式庫的 MJPEG 編碼器。" - -#~ msgid "A SDL-based video display" -#~ msgstr "基於 SDL 的視訊顯示" - -#~ msgid "A video4windows compatible source filter to stream pictures." -#~ msgstr "video4windows 相容來源過濾器至串流圖片。" - -#~ msgid "A video for windows (vfw.h) based source filter to grab pictures." -#~ msgstr "windows (vfw.h) 視訊為基礎的來源過濾器以擷取圖片。" - -#~ msgid "" -#~ "A filter that trashes its input (useful for terminating some graphs)." -#~ msgstr "將輸入丟棄的過濾器(可用來中止某些圖形)。" - -#~ msgid "Parametric sound equalizer." -#~ msgstr "參數化音效等化器。" - -#~ msgid "A webcam grabber based on directshow." -#~ msgstr "基於 directshow 的網路攝影機擷取器。" - -#~ msgid "A video display based on windows DrawDib api" -#~ msgstr "基於 windows DrawDib api 的視訊顯示" - -#~ msgid "A filter that mixes down 16 bit sample audio streams" -#~ msgstr "混合 16 位元取樣音效串流的過濾器" - -#~ msgid "A filter that converts from mono to stereo and vice versa." -#~ msgstr "將單聲道與雙聲道互相轉換的過濾器。" - -#~ msgid "A display filter sending the buffers to draw to the upper layer" -#~ msgstr "傳送緩衝區以繪製到上層圖層的顯示過濾器" - -#~ msgid "Sound capture filter for MacOS X Audio Unit Service" -#~ msgstr "MacOS X 音效單元服務的音效擷取過濾器" - -#~ msgid "Sound playback filter for MacOS X Audio Unit Service" -#~ msgstr "MacOS X 音效單元服務的音效播放過濾器" - -#~ msgid "A video display using X11+Xv" -#~ msgstr "使用 X11+Xv 的視訊顯示" - -#~ msgid "Sound capture filter for Android" -#~ msgstr "Android 音效擷取過濾器" - -#~ msgid "Sound playback filter for Android" -#~ msgstr "Android 音效播放過濾器" - -#~ msgid "A filter that captures Android video." -#~ msgstr "擷取 Android 視訊的過濾器。" +#: ../coreapi/call_log.c:209 +msgid "aborted" +msgstr "" + +#: ../coreapi/call_log.c:212 +msgid "completed" +msgstr "" + +#: ../coreapi/call_log.c:215 +msgid "missed" +msgstr "" + +#: ../coreapi/call_log.c:218 +msgid "unknown" +msgstr "" + +#: ../coreapi/call_log.c:220 +#, c-format +msgid "" +"%s at %s\n" +"From: %s\n" +"To: %s\n" +"Status: %s\n" +"Duration: %i mn %i sec\n" +msgstr "" + +#: ../coreapi/call_log.c:221 +msgid "Outgoing call" +msgstr "" + +#: ../gtk/videowindow.c:66 +#, c-format +msgid "Cannot play %s." +msgstr "" diff --git a/scripts/mk-ca-bundle.pl b/scripts/mk-ca-bundle.pl new file mode 100755 index 000000000..283ebd13c --- /dev/null +++ b/scripts/mk-ca-bundle.pl @@ -0,0 +1,242 @@ +#!/usr/bin/perl -w +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at http://curl.haxx.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# *************************************************************************** +# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. +# It downloads certdata.txt from Mozilla's source tree (see URL below), +# then parses certdata.txt and extracts CA Root Certificates into PEM format. +# These are then processed with the OpenSSL commandline tool to produce the +# final ca-bundle.crt file. +# The script is based on the parse-certs script written by Roland Krikava. +# This Perl script works on almost any platform since its only external +# dependency is the OpenSSL commandline tool for optional text listing. +# Hacked by Guenter Knauf. +# +use Getopt::Std; +use MIME::Base64; +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 = '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'; + +my $version = '1.18'; + +$opt_w = 76; # default base64 encoded lines length + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bfhilnqtuvw:'); + +if ($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n"; + print "LWP.pm Version : ${LWP::VERSION}\n"; + print ("=" x 78 . "\n"); +} + +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-f] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [-w] []\n"; + print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-n\tno download of certdata.txt (to use existing)\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-u\tunlink (remove) certdata.txt after processing\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; +} + +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +HELP_MESSAGE() if ($opt_h); + +my $crt = $ARGV[0] || 'ca-bundle.crt'; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; + +unless ($opt_n and -e $txt) { + print STDERR "Downloading '$txt' ...\n" if (!$opt_q); + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if ($resp && $resp->code eq '304') { + print STDERR "Not modified\n" unless $opt_q; + exit 0 if -e $crt && !$opt_f; + } else { + $fetched = 1; + } + if( !$resp || $resp->code !~ /^(?:200|304)$/ ) { + print STDERR "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed") . "\n" + unless $opt_q; + exit 1 if -e $crt || ! -r $txt; + } +} + +my $currentdate = scalar gmtime($fetched ? $resp->last_modified : (stat($txt))[9]); + +my $format = $opt_t ? "plain text and " : ""; +if( $stdout ) { + open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; +} +print CRT <) { + if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if ($opt_l); + while () { + print CRT; + print if ($opt_l); + last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + } + next if /^#|^\s*$/; + chomp; + if (/^CVS_ID\s+\"(.*)\"/) { + print CRT "# $1\n"; + } + + # this is a match for the start of a certificate + if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + $start_of_cert = 1 + } + if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { + $caname = $1; + } + my $untrusted = 0; + if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { + my $data; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + $data .= chr(oct); + } + } + # scan forwards until the trust part + while () { + last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); + chomp; + } + # now scan the trust part for untrusted certs + while () { + last if (/^#/); + if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_NOT_TRUSTED$/ + or /^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUST_UNKNOWN$/) { + $untrusted = 1; + } + } + if ($untrusted) { + $skipnum ++; + } else { + my $encoded = MIME::Base64::encode_base64($data, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + print CRT ("=" x length($caname) . "\n"); + if (!$opt_t) { + print CRT $pem; + } else { + my $pipe = "|$openssl x509 -md5 -fingerprint -text -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + print STDERR "Parsing: $caname\n" if ($opt_v); + $certnum ++; + $start_of_cert = 0; + } + } +} +close(TXT) or die "Couldn't close $txt: $!\n"; +close(CRT) or die "Couldn't close $crt.~: $!\n"; +unless( $stdout ) { + if ($opt_b && -e $crt) { + my $bk = 1; + while (-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif( -e $crt ) { + unlink( $crt ) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} +unlink $txt if ($opt_u); +print STDERR "Done ($certnum CA certs processed, $skipnum untrusted skipped).\n" if (!$opt_q); + +exit; + + diff --git a/share/.gitignore b/share/.gitignore index 3d11e0206..3470e9d61 100644 --- a/share/.gitignore +++ b/share/.gitignore @@ -2,3 +2,4 @@ Makefile Makefile.in *.raw linphone.pc +rootca.pem 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/CMakeLists.txt b/share/CMakeLists.txt new file mode 100644 index 000000000..b12eb85ef --- /dev/null +++ b/share/CMakeLists.txt @@ -0,0 +1,71 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +if(APPLE) + find_program(OPENSSL_PROGRAM openssl) + execute_process( + COMMAND ${OPENSSL_PROGRAM} version -d + OUTPUT_VARIABLE OPENSSL_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REGEX REPLACE "OPENSSLDIR: \"(.*)\"" "\\1" HTTPS_CA_DIR "${OPENSSL_VERSION}") +endif() + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/rootca.pem PROPERTIES GENERATED TRUE) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootca.pem + COMMAND ${CMAKE_COMMAND} -DHTTPS_CA_DIR=${HTTPS_CA_DIR} -DWORK_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/rootca.cmake) +add_custom_target(rootca ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/rootca.pem) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rootca.pem + DESTINATION ${PACKAGE_DATA_DIR}/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +set(SOUND_FILES + hello16000.wav + hello8000.wav + incoming_chat.wav + ringback.wav +) + +install(FILES ${SOUND_FILES} + DESTINATION ${PACKAGE_SOUND_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +if(ENABLE_GTK_UI) + set(prefix "${CMAKE_INSTALL_PREFIX}") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/audio-assistant.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/audio-assistant.desktop) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/linphone.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/linphone.desktop) + + set(FREEDESKTOP_FILES + ${CMAKE_CURRENT_BINARY_DIR}/audio-assistant.desktop + ${CMAKE_CURRENT_BINARY_DIR}/linphone.desktop + ) + + install(FILES ${FREEDESKTOP_FILES} + DESTINATION ${PACKAGE_FREEDESKTOP_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) +endif() + +add_subdirectory(rings) diff --git a/share/Makefile.am b/share/Makefile.am index 83c3a934e..0b3fb0119 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS=C fr it ja cs xml -LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav +LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav incoming_chat.wav LINPHONE_RINGS=rings/orig.wav \ rings/oldphone.wav \ rings/oldphone-mono.wav \ @@ -23,7 +23,7 @@ ring_DATA=$(LINPHONE_RINGS) #to be compliant with freedesktop.org: linphone_fddir= $(datadir)/applications -linphone_fd_DATA= linphone.desktop +linphone_fd_DATA= linphone.desktop audio-assistant.desktop pkgconfigdir=$(libdir)/pkgconfig @@ -32,10 +32,28 @@ pkgconfig_DATA=linphone.pc linphonedir=$(datadir)/linphone linphone_DATA=rootca.pem -EXTRA_DIST = $(LINPHONE_SOUNDS) \ - $(LINPHONE_RINGS) \ - linphone.desktop.in \ - linphone.pc.in \ - Makefile.inc \ - rootca.pem +appdatadir=$(datadir)/appdata +appdata_DATA=linphone.appdata.xml + +#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 \ + audio-assistant.desktop.in \ + linphone.pc.in \ + Makefile.inc \ + archived-rootca.pem \ + $(appdata_DATA) + +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/share/audio-assistant.desktop.in b/share/audio-assistant.desktop.in new file mode 100644 index 000000000..7f107545d --- /dev/null +++ b/share/audio-assistant.desktop.in @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=Audio assistant +GenericName=Audio assistant +Name[ru]=Помощник аудио +Comment=Linphone audio assistant +Comment[fr]=Assistant audio de Linphone. +Comment[ru]=Помощник аудио Linphone +Type=Application +Exec=linphone --run-audio-assistant +Icon=linphone +Terminal=false +Categories=Network;Telephony; diff --git a/share/incoming_chat.wav b/share/incoming_chat.wav new file mode 100644 index 000000000..99a2e7dfc Binary files /dev/null and b/share/incoming_chat.wav differ diff --git a/share/linphone.appdata.xml b/share/linphone.appdata.xml new file mode 100644 index 000000000..db660b614 --- /dev/null +++ b/share/linphone.appdata.xml @@ -0,0 +1,36 @@ + + + + linphone.desktop + CC0-1.0 + GPL-2.0 + Linphone + SIP video soft-phone + +
      +
    • Make audio and video calls in HD
    • +
    • Create audio conferences
    • +
    • Record and store calls
    • +
    • View real-time presence status
    • +
    • Manage your address book
    • +
    • Communicate securely
    • +
    • Free subscription
    • +
    +
    + + + http://www.linphone.org/uploads/images/desktop_main_window.png + Main window + + + http://www.linphone.org/uploads/images/desktop_call_view.png + Call view + + + http://www.linphone.org/uploads/images/desktop_chat_view.png + Chat view + + + http://www.linphone.org + contact@belledonne-communications.com +
    diff --git a/share/linphone.desktop.in b/share/linphone.desktop.in index d8ab62a5b..656897a48 100644 --- a/share/linphone.desktop.in +++ b/share/linphone.desktop.in @@ -1,10 +1,26 @@ [Desktop Entry] Name=Linphone +GenericName=Web-phone Comment=Linphone is a web-phone -Comment[fr]=Linphone est un web-phone. -Comment[de]=Linphone ist ein web-phone. Type=Application Exec=linphone -Icon=@prefix@/share/pixmaps/linphone/linphone.png +Icon=linphone Terminal=false Categories=Network;Telephony; + + +# Translations +Name[de]=Linphone +Name[he]=Linphone +Name[ar]=لِنْفُونْ +Name[hu]=Linphone +Name[ru]=Linphone +Name[nb_NO]=Linphone +Name[it]=Linphone +Name[ja]=Linphone +Name[cs]=Linphone +Name[sr]=Линфон +Name[sv]=Linphone +Name[zh_CN]=Linphone +Name[fr]=Linphone +Name[zh_TW]=Linphone diff --git a/share/rings/CMakeLists.txt b/share/rings/CMakeLists.txt new file mode 100644 index 000000000..6ec2182e2 --- /dev/null +++ b/share/rings/CMakeLists.txt @@ -0,0 +1,39 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +set(RING_FILES + bigben.wav + oldphone-mono-30s.caf + oldphone-mono.wav + oldphone.wav + orig.wav + rock.wav + sweet.wav + synth.wav + tapping.wav + toy-mono.wav +) + +install(FILES ${RING_FILES} + DESTINATION ${PACKAGE_RING_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) diff --git a/share/rootca.cmake b/share/rootca.cmake new file mode 100644 index 000000000..d988b778e --- /dev/null +++ b/share/rootca.cmake @@ -0,0 +1,40 @@ +############################################################################ +# rootca.cmake +# Copyright (C) 2014 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. +# +############################################################################ + +if(HTTPS_CA_DIR) + set(ENV{HTTPS_CA_DIR} "${HTTPS_CA_DIR}") +endif() + +execute_process( + COMMAND ${CMAKE_COMMAND} -E remove "fresh-rootca.pem" + WORKING_DIRECTORY ${OUTPUT_DIR} +) +execute_process( + COMMAND "../scripts/mk-ca-bundle.pl" "${OUTPUT_DIR}/fresh-rootca.pem" + WORKING_DIRECTORY ${WORK_DIR} +) +if(EXISTS "${OUTPUT_DIR}/fresh-rootca.pem") + file(RENAME "${OUTPUT_DIR}/fresh-rootca.pem" "${OUTPUT_DIR}/rootca.pem") +else() + file(COPY "${WORK_DIR}/archived-rootca.pem" DESTINATION "${OUTPUT_DIR}") + file(RENAME "${OUTPUT_DIR}/archived-rootca.pem" "${OUTPUT_DIR}/rootca.pem") +endif() diff --git a/share/rootca.pem b/share/rootca.pem deleted file mode 100644 index cb25772cd..000000000 --- a/share/rootca.pem +++ /dev/null @@ -1,3965 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE -AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x -CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW -MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF -RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC -AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7 -09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7 -XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P -Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK -t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb -X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28 -MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU -fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI -2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH -K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae -ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP -BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ -MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw -RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv -bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm -fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3 -gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe -I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i -5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi -ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn -MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ -o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6 -zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN -GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt -r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK -Z05phkOTOPu220+DkdRgfks+KzgHVZhepA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx -CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp -ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa -QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw -NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft -ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu -QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG -qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL -fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ -Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 -Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ -54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b -MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j -ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej -YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt -A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF -rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ -pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB -lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy -YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 -7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs -YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 -xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc -unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ -Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp -ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 -gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 -jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ -XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD -W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ -RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r -MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk -BYn8eNZcLCZDqQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw -MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD -VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul -CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n -tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl -dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch -PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC -+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O -BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl -MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk -ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X -7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz -43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY -eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl -pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA -WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx -MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB -ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV -BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV -6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX -GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP -dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH -1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF -62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW -BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL -MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU -cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv -b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 -IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ -iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao -GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh -4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm -XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 -MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK -EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh -BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq -xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G -87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i -2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U -WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 -0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G -A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr -pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL -ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm -aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv -hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm -hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X -dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 -P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y -iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no -xqE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP -bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 -MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft -ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk -hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym -1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW -OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb -2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko -O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU -AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF -Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb -LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir -oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C -MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds -sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP -bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 -MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft -ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC -206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci -KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 -JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 -BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e -Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B -PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 -Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq -Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ -o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 -+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj -FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn -xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 -LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc -obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 -CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe -IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA -DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F -AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX -Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb -AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl -Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw -RY8mkaKO/qk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx -HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh -IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 -MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg -SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M -IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U -0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI -TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf -RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF -zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh -BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA -AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY -PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ -BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn -9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT -Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF -Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX -n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW -H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx -HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh -IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz -NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg -SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M -IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ -7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb -m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY -xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ -YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq -JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx -I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz -kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh -EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S -Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM -gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu -rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO -1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu -h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP -yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q -7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT -RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ -ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB -M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ -my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO -AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT -9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H -hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 -fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc -MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp -b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT -AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs -aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H -j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K -f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 -IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw -FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht -QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm -/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ -k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ -MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC -seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ -hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ -eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U -DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj -B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL -rosot4LKGAfmt1t06SAZf7IbiVQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy -MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD -VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv -ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl -AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF -661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 -am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 -ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 -PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS -3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k -SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF -3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM -ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g -StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz -Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB -jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx -EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h -bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy -YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp -Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy -MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG -A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt -YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD -VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA -isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj -Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 -QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt -bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR -yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID -AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 -cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f -BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj -cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 -U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl -YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos -SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ -t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u -mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb -K+9A46sd33oqK8n8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg -Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL -MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD -VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 -ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX -l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB -HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B -5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 -WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD -AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP -gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ -DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu -BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs -h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk -LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg -Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL -MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD -VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg -isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z -NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI -+MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R -hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ -mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD -AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP -Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s -EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 -mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC -e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow -dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO -BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi -MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ -ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ -8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 -zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y -fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 -w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc -G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k -epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q -laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ -QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU -fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 -YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w -ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY -gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe -MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 -IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy -dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw -czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 -dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl -aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC -AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg -b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB -ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc -nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg -18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c -gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl -Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY -sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T -SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF -CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum -GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk -zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW -omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS -BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v -cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9 -4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB -Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J -0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ -FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx -bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q -SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb -6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV -m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g -eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG -kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7 -6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG -CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc -aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB -gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w -aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6 -tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0 -nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M -77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV -Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L -ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM -zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU -rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF -YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT -oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu -FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB -0m6lG5kngOcLqagA ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET -MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE -AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw -CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg -YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE -Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX -mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD -XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW -S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp -FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD -AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu -ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z -ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv -Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw -DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 -yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq -EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ -CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB -EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN -PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn -MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL -ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg -b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa -MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB -ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw -IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B -AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb -unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d -BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq -7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 -0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX -roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG -A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j -aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p -26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA -BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud -EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN -BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz -aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB -AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd -p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi -1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc -XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 -eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu -tGWaIZDgqtCYvDi1czyL+Nw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn -MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL -ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo -YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 -MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy -NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G -A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA -A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 -Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s -QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV -eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 -B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh -z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T -AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i -ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w -TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH -MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD -VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE -VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh -bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B -AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM -bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi -ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG -VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c -ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ -AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIESzCCAzOgAwIBAgIJAJigUTEEXRQpMA0GCSqGSIb3DQEBBQUAMHYxCzAJBgNV -BAYTAkRFMQ8wDQYDVQQIEwZIZXNzZW4xDjAMBgNVBAcTBUZ1bGRhMRAwDgYDVQQK -EwdEZWJjb25mMRMwEQYDVQQDEwpEZWJjb25mIENBMR8wHQYJKoZIhvcNAQkBFhBq -b2VyZ0BkZWJpYW4ub3JnMB4XDTA1MTEwNTE3NTUxNFoXDTE1MTEwMzE3NTUxNFow -djELMAkGA1UEBhMCREUxDzANBgNVBAgTBkhlc3NlbjEOMAwGA1UEBxMFRnVsZGEx -EDAOBgNVBAoTB0RlYmNvbmYxEzARBgNVBAMTCkRlYmNvbmYgQ0ExHzAdBgkqhkiG -9w0BCQEWEGpvZXJnQGRlYmlhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCvbOo0SrIwI5IMlsshH8WF3dHB9r9JlSKhMPaybawa1EyvZspMQ3wa -F5qxNf3Sj+NElEmjseEqvCZiIIzqwerHu0Qw62cDYCdCd2+Wb5m0bPYB5CGHiyU1 -eNP0je42O0YeXG2BvUujN8AviocVo39X2YwNQ0ryy4OaqYgm2pRlbtT2ESbF+SfV -Y2iqQj/f8ymF+lHo/pz8tbAqxWcqaSiHFAVQJrdqtFhtoodoNiE3q76zJoUkZTXB -k60Yc3MJSnatZCpnsSBr/D7zpntl0THrUjjtdRWCjQVhqfhM1yZJV+ApbLdheFh0 -ZWlSxdnp25p0q0XYw/7G92ELyFDfBUUNAgMBAAGjgdswgdgwHQYDVR0OBBYEFMuV -dFNb4mCWUFbcP5LOtxFLrEVTMIGoBgNVHSMEgaAwgZ2AFMuVdFNb4mCWUFbcP5LO -txFLrEVToXqkeDB2MQswCQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMQ4wDAYD -VQQHEwVGdWxkYTEQMA4GA1UEChMHRGViY29uZjETMBEGA1UEAxMKRGViY29uZiBD -QTEfMB0GCSqGSIb3DQEJARYQam9lcmdAZGViaWFuLm9yZ4IJAJigUTEEXRQpMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGZXxHg4mnkvilRIM1EQfGdY -S5b/WcyF2MYSTeTvK4aIB6VHwpZoZCnDGj2m2D3CkHT0upAD9o0zM1tdsfncLzV+ -mDT/jNmBtYo4QXx5vEPwvEIcgrWjwk7SyaEUhZjtolTkHB7ACl0oD0r71St4iEPR -qTUCEXk2E47bg1Fz58wNt/yo2+4iqiRjg1XCH4evkQuhpW+dTZnDyFNqwSYZapOE -TBA+9zBb6xD1KM2DdY7r4GiyYItN0BKLfuWbh9LXGbl1C+f4P11g+m2MPiavIeCe -1iazG5pcS3KoTLACsYlEX24TINtg4kcuS81XdllcnsV3Kdts0nIqPj6uhTTZD0k= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDvjCCA3ygAwIBAgIFJQaThoEwCwYHKoZIzjgEAwUAMIGFMQswCQYDVQQGEwJG -UjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczEQMA4GA1UEChMHUE0v -U0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcN -AQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAeFw0wMjEyMTMxNDM5MTVaFw0yMDEw -MTcxNDM5MTRaMIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYD -VQQHEwVQYXJpczEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAM -BgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5m -cjCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCFkMImdk9zDzJfTO4XPdAAmLbAdWws -ZiEMZh19RyTo3CyhFqO77OIXrwY6vc1pcc3MgWJ0dgQpAgrDMtmFFxpUu4gmjVsx -8GpxQC+4VOgLY8Cvmcd/UDzYg07EIRto8BwCpPJ/JfUxwzV2V3N713aAX+cEoKZ/ -s+kgxC6nZCA7oQIVALME/JYjkdW2uKIGngsEPbXAjdhDAoGADh/uqWJx94UBm31c -9d8ZTBfRGRnmSSRVFDgPWgA69JD4BR5da8tKz+1HjfMhDXljbMH86ixpD5Ka1Z0V -pRYUPbyAoB37tsmXMJY7kjyD19d5VdaZboUjVvhH6UJy5lpNNNGSvFl4fqkxyvw+ -pq1QV0N5RcvK120hlXdfHUX+YKYDgYQAAoGAQGr7IuKJcYIvJRMjxwl43KxXY2xC -aoCiM/bv117MfI94aNf1UusGhp7CbYAY9CXuL60P0oPMAajbaTE5Z34AuITeHq3Y -CNMHwxalip8BHqSSGmGiQsXeK7T+r1rPXsccZ1c5ikGDZ4xn5gUaCyy2rCmb+fOJ -6VAfCbAbAjmNKwejdzB1MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgFGMBUG -A1UdIAQOMAwwCgYIKoF6AXkBAQEwHQYDVR0OBBYEFPkeNRcUf8idzpKblYbLNxs0 -MQhSMB8GA1UdIwQYMBaAFPkeNRcUf8idzpKblYbLNxs0MQhSMAsGByqGSM44BAMF -AAMvADAsAhRVh+CJA5eVyEYU5AO9Tm7GxX0rmQIUBCqsU5u1WxoZ5lEXicDX5/Ob -sRQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT -AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ -TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG -9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw -MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM -BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO -MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2 -LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI -s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2 -xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4 -u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b -F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx -Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd -PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV -HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx -NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF -AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ -L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY -YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg -Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a -NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R -0982gaEbeC9xs/FZTEYYKKuF0mBWWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw -PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz -cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 -MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz -IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ -ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR -VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL -kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd -EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas -H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 -HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud -DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 -QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu -Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ -AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 -yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR -FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA -ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB -kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E -jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo -ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI -ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu -Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg -AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 -HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA -uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa -TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg -xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q -CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x -O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs -6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz -IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz -MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj -dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw -EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp -MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 -28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq -VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q -DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR -5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL -ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a -Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl -UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s -+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 -Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj -ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx -hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV -HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 -+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN -YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t -L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy -ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt -IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV -HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w -DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW -PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF -5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 -glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH -FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 -pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD -xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG -tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq -jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De -fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg -OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ -d0jQ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD -TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 -MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF -Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh -IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 -dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO -V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC -GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN -v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB -AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB -Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO -76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK -OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH -ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi -yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL -buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj -2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp -ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow -fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV -BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM -cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S -HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 -CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk -3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz -6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV -HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv -Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw -Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww -DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 -5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj -Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI -gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ -aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl -izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 -aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla -MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD -VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW -fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt -TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL -fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW -1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 -kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G -A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v -ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo -dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu -Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ -HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 -pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS -jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ -xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn -dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 -MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG -EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT -CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK -8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 -98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb -2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC -ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi -Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB -o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl -ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD -AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL -AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd -foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M -cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq -8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp -hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk -Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U -AGegcQCCSA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw -PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu -MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx -GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL -MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf -HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh -gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW -v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue -Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr -9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt -6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 -MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl -Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 -ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq -hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p -iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC -dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL -kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL -hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz -OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG -A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh -bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE -ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS -b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 -7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS -J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y -HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP -t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz -FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY -XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw -hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js -MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA -A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj -Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx -XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o -omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc -A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc -MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj -IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB -IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE -RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl -U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 -IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU -ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC -QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr -rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S -NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc -QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH -txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP -BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC -AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp -tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa -IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl -6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ -xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU -Cm26OWMohpLzGITY+9HPBVZkVw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf -MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp -Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww -HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES -MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg -MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B -8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY -tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl -HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj -zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU -JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM -ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv -a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p -K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi -puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT -yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO -owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC -jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy -fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo -Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo -M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM -Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed -2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH -/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl -nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE -O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU -9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 -j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg -bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ -j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV -Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw -MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 -fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i -+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN -QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ -gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ -k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso -LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o -TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 -MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C -TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 -WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR -xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL -B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx -ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w -MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD -VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx -FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu -ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 -gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH -fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a -ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT -ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk -c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto -dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt -aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI -hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk -QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ -h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq -nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR -rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 -9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV -BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt -ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 -MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg -SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl -a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h -4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk -tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s -tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL -dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 -c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um -TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z -+kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O -Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW -OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW -fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 -l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw -FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ -8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI -6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO -TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME -wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY -Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn -xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q -DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q -Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t -hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 -7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 -QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1 -MQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxp -Z2kgQS5TLjE8MDoGA1UEAxMzZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZp -a2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3MDEwNDExMzI0OFoXDTE3MDEwNDEx -MzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0cm9uaWsgQmlsZ2kg -R3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9uaWsg -U2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdU -MZTe1RK6UxYC6lhj71vY8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlT -L/jDj/6z/P2douNffb7tC+Bg62nsM+3YjfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H -5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAIJjjcJRFHLfO6IxClv7wC -90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk9Ok0oSy1 -c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoE -VtstxNulMA0GCSqGSIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLP -qk/CaOv/gKlR6D1id4k9CnU58W5dF4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S -/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwqD2fK/A+JYZ1lpTzlvBNbCNvj -/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4Vwpm+Vganf2X -KWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq -fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy -MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA -vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G -CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA -WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo -oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ -h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 -f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN -B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy -vUxFnmG6v4SBkgPR0ml8xQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u -ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u -ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 -MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j -b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg -U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ -I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 -wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC -AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb -oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 -BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p -dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk -MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 -MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi -E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa -MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI -hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN -95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd -2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy -dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 -MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx -dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f -BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A -cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ -MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm -aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw -ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj -IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y -7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh -1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT -ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw -MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j -LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo -RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu -WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw -Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK -eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM -zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ -WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN -/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj -dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 -NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD -VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G -vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ -BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl -IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw -NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq -y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy -0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 -E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT -ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw -MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj -dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l -c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC -UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc -58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ -o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr -aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA -A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA -Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv -8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx -IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 -dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w -HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx -IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 -dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u -Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY -rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z -hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay -BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL -iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb -AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv -bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0 -MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E -FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n -VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq -u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m -hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl -ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp -QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5 -quGnM/b9Sh/22WA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs -IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg -R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A -PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 -Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL -TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL -5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 -S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe -2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap -EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td -EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv -/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN -A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 -abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF -I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz -4iIprn2DQKi6bA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL -MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj -KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 -MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV -BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw -NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV -BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL -So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal -tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG -CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT -qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz -rD6ogRLQy7rQkgu2npaqBA+K ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB -mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT -MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ -BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 -BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz -+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm -hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn -5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W -JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL -DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC -huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB -AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB -zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN -kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH -SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G -spki4cErx5z481+oghLrGREt ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo -R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx -MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 -AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA -ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 -7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W -kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI -mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ -KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 -6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl -4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K -oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj -UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU -AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy -c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD -VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 -c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 -WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG -FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq -XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL -se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb -KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd -IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 -y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt -hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc -QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 -Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV -HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ -KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ -L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr -Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo -ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY -T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz -GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m -1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV -OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH -6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX -QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy -c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 -IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV -VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 -cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT -QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh -F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v -c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w -mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd -VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX -teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ -f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe -Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ -nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY -MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG -9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX -IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn -ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z -uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN -Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja -QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW -koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 -ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt -DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm -bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx -MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy -cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG -A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl -BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed -KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 -G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 -zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 -ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG -HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 -Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V -yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e -beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r -6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog -zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW -BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr -ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp -ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk -cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt -YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC -CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow -KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI -hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ -UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz -X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x -fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz -a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd -Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd -SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O -AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso -M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge -v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD -VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv -bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv -b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU -cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds -b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH -iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS -r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 -04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r -GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 -3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P -lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx -FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg -Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG -A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr -b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ -jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn -PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh -ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 -nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h -q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED -MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC -mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 -7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB -oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs -EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO -fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi -AmvZWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT -AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ -TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG -9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw -MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM -BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO -MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2 -LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI -s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2 -xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4 -u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b -F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx -Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd -PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV -HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx -NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF -AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ -L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY -YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg -Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a -NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R -0982gaEbeC9xs/FZTEYYKKuF0mBWWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN -AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp -dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw -MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw -CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ -MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB -SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz -ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH -LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP -PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL -2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w -ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC -MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk -AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 -AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz -AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz -AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f -BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE -FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY -P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi -CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g -kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 -HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS -na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q -qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z -TbvGRNs2yyqcjg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAw -cjELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNy -b3NlYyBMdGQuMRQwEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9z -ZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4 -NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMN -TWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMTGU1p -Y3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2u -uO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+ -LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabA -vjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770 -Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx -62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcB -AQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3Aw -LQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAP -BgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIB -AQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1L1NaU1ov -MIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5 -ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn -AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABT -AHoAbwBsAGcA4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABh -ACAAcwB6AGUAcgBpAG4AdAAgAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABo -AHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBa -AFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6Ly93d3cuZS1zemln -bm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NOPU1p -Y3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxP -PU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv -Y2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuB -EGluZm9AZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWdu -w7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWlj -cm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNV -HSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJI -VTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDAS -BgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBS -b290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS -8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds -ZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl -7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a -86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfR -hUZLphK3dehKyVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/ -MPMMNz7UwiiAc7EBt51alhQBS6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD -EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 -OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l -dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG -SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK -gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX -iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc -Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E -BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G -SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu -b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh -bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv -Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln -aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 -IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh -c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph -biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo -ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP -UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj -YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo -dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA -bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 -sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa -n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS -NitjrFgBazMpUIaD8QFI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD -EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X -DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw -DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u -c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr -TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA -OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC -2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW -RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P -AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW -ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 -YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz -b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO -ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB -IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs -b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs -ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s -YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg -a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g -SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 -aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg -YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg -Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY -ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g -pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 -Fp1hBWeAyNDYpQcCNJgEjTME1A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV -MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe -TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 -dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB -KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 -N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC -dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu -MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL -b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD -zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi -3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 -WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY -Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi -NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC -ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 -QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 -YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz -aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu -IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm -ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg -ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs -amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv -IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 -Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 -ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 -YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg -dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs -b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G -CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO -xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP -0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ -QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk -f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK -8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD -EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz -aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w -MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l -dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh -bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq -eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe -r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 -3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd -vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l -mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC -wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg -hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 -TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh -biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg -ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg -dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 -b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl -c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 -ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 -dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu -ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh -bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo -ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 -Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u -ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA -A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ -MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ -NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR -VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY -83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 -macqaJVmlaut74nLYKkGEsaUR+ko ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi -MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV -UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO -ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz -c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP -OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl -mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF -BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 -qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw -gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu -bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp -dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 -6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ -h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH -/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN -pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB -ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly -aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl -ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w -NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G -A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD -VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX -SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR -VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 -w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF -mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg -4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 -4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw -EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx -SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 -ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 -vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa -hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi -Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ -/L7fCg0= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz -MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw -IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR -dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp -li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D -rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ -WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug -F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU -xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC -Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv -dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw -ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl -IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh -c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy -ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI -KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T -KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq -y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p -dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD -VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk -fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 -7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R -cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y -mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW -xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK -SnQ2+Q== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy -NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD -cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs -2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY -JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE -Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ -n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A -PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 -MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp -dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX -BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy -MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp -eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg -/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl -wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh -AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 -PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu -AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR -MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc -HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ -Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ -f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO -rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch -6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 -7CAFYd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr -MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG -A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 -MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp -Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD -QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz -i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 -h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV -MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 -UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni -8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC -h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD -VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB -AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm -KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ -X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr -QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 -pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN -QSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz -MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N -IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 -bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE -RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO -zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 -bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF -MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 -VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC -OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW -tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ -q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb -EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ -Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O -VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw -OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu -ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h -gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K -5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy -9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE -gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3 -eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs -YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp -aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp -dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb -sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB -FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy -f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W -+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2 -uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf -tXncwKJrMiE3lvgOOBITRzcahirLer4c ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa -Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g -eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND -IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu -QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui -me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm -RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/ -OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G -O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF -BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI -KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh -c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl -cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw -HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX -hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV -Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw -6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF -6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e -Pr3WHV1wA7EY6oT4zBx+2gT9XBTB ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE -ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE -AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ -BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT -aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl -KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX -GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj -93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+ -P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow -ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g -ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN -W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB -IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB -ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA -ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb -MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv -J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW -pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J -HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD -QSBLbGFzYSAyMB4XDTAzMTAxNDExNTgyMloXDTE3MDQxODEyNTMwN1owdzELMAkG -A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV -BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEhMB8GA1UEAxMYQ0MgU2ln -bmV0IC0gT0NTUCBLbGFzYSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo -VCsaBStblXQYVNthe3dvaCrfvKpPXngh4almm988iIlEv9CVTaAdCfaJNihvA+Vs -Qw8++ix1VqteMQE474/MV/YaXigP0Zr0QB+g+/7PWVlv+5U9Gzp9+Xx4DJay8AoI -iB7Iy5Qf9iZiHm5BiPRIuUXT4ZRbZRYPh0/76vgRsQIDAQABo4IBkjCCAY4wDgYD -VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEEGA1UdHwQ6MDgwNqA0 -oDKGMGh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9jcmwva2xhc2Ey -LmNybDCB2AYDVR0gBIHQMIHNMIHKBg4rBgEEAb4/AoFICgwBADCBtzBsBggrBgEF -BQcCAjBgGl5DZXJ0eWZpa2F0IHd5ZGFueSB6Z29kbmllIHogZG9rdW1lbnRlbSAi -UG9saXR5a2EgQ2VydHlmaWthY2ppIC0gQ2VydHlmaWthdHkgcmVzcG9uZGVyb3cg -T0NTUCIuMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0 -b3JpdW0vZG9rdW1lbnR5L3BjX29jc3BfMV8wLnBkZjAfBgNVHSMEGDAWgBS7RQZS -C8uBzSlUs7x8QUzNBw6MJTAdBgNVHQ4EFgQUKEVrOY7cEHvsVgvoyZdytlbtgwEw -CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAQrRg5MV6dxr0HU2IsLInxhvt -iUVmSFkIUsBCjzLoewOXA16d2oDyHhI/eE+VgAsp+2ANjZu4xRteHIHoYMsN218M -eD2MLRsYS0U9xxAFK9gDj/KscPbrrdoqLvtPSMhUb4adJS9HLhvUe6BicvBf3A71 -iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp -ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv -hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg -U2lnbmV0IC0gQ0EgS2xhc2EgMzEXMBUGA1UEBRMOTnVtZXIgd3Bpc3U6IDQwHhcN -MDMxMDE0MTIwODAwWhcNMDgwNDI4MTA1MDU1WjB3MQswCQYDVQQGEwJQTDEfMB0G -A1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBD -ZXJ0eWZpa2FjamkgU2lnbmV0MSEwHwYDVQQDExhDQyBTaWduZXQgLSBPQ1NQIEts -YXNhIDMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM/9GwvARNuCVN+PqZmO -4FqH8vTqhenUyqRkmAVT4YhLu0a9AXeLAYVDu+NTkYzsAUMAfu55rIKHNLlm6WbF -KvLiKKz4p4pbUr+ToPcwl/TDotidloUdBAxDg0SL+PmQqACZDe3seJho2IYf2vDL -/G4TLMbKmNB0mlWFuN0f4fJNAgMBAAGjggGgMIIBnDAOBgNVHQ8BAf8EBAMCB4Aw -EwYDVR0lBAwwCgYIKwYBBQUHAwkwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 -dy5zaWduZXQucGwva3dhbGlmaWtvd2FuZS9yZXBvenl0b3JpdW0vY3JsL2tsYXNh -My5jcmwwgdgGA1UdIASB0DCBzTCBygYOKwYBBAG+PwKCLAoCAQAwgbcwbAYIKwYB -BQUHAgIwYBpeQ2VydHlmaWthdCB3eWRhbnkgemdvZG5pZSB6IGRva3VtZW50ZW0g -IlBvbGl0eWthIENlcnR5ZmlrYWNqaSAtIENlcnR5ZmlrYXR5IHJlc3BvbmRlcm93 -IE9DU1AiLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5 -dG9yaXVtL2Rva3VtZW50eS9wY19vY3NwXzFfMC5wZGYwHwYDVR0jBBgwFoAUe2PM -GZB6tM62O559bRUnUND5SbkwHQYDVR0OBBYEFG4jnCMvBALRQXtmDn9TyXQ/EKP+ -MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBACXrKG5Def5lpRwmZom3UEDq -bl7y4U3qomG4B+ok2FVZGgPZti+ZgvrenPj7PtbYCUBPsCSTNrznKinoT3gD9lQQ -xkEHwdc6VD1GlFp+qI64u0+wS9Epatrdf7aBnizrOIB4LJd4E2TWQ6trspetjMIU -upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk -GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug -5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw -OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu -ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma -M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+ -HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW -Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9 -JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x -W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC -AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 -IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z -aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy -bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE -82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx -UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan -ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2 -2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV -tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw -OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu -ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue -Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA -iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE -OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db -w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC -3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC -AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 -IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z -aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy -bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM -ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4 -7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG -dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF -JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz -1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw -OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu -ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks -ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX -REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D -CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU -YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP -l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8 -MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz -dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg -Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg -Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt -L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf -BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN -AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI -cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1 -CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW -ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB -KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX -DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6 -IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg -U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd -uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v -LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c -ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w -bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM -MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH -AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr -YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC -ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf -MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO -Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz -+z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB -vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx -MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG -29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk -oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk -3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL -qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN -nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX -ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H -DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO -TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv -kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w -zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx -MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o -Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt -5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s -3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej -vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu -8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil -zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ -3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD -FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 -Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 -ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE -ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z -dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq -hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDMwMTE1MTYyOTE3 -WhcNMDcwMTE0MTYyOTE3WjCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh -bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g -dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEgMB4GA1UE -AxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEWFmhvc3Rt -YXN0ZXJAc3BpLWluYy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPB6 -rdoiLR3RodtM22LMcfwfqb5OrJNl7fwmvskgF7yP6sdD2bOfDIXhg9852jhY8/kL -VOFe1ELAL2OyN4RAxk0rliZQVgeTgqvgkOVIBbNwgnjN6mqtuWzFiPL+NXQExq40 -I3whM+4lEiwSHaV+MYxWanMdhc+kImT50LKfkxcdAgMBAAGjggEfMIIBGzAdBgNV -HQ4EFgQUB63oQR1/vda/G4F6P4xLiN4E0vowgesGA1UdIwSB4zCB4IAUB63oQR1/ -vda/G4F6P4xLiN4E0vqhgcSkgcEwgb4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdJ -bmRpYW5hMRUwEwYDVQQHEwxJbmRpYW5hcG9saXMxKDAmBgNVBAoTH1NvZnR3YXJl -IGluIHRoZSBQdWJsaWMgSW50ZXJlc3QxEzARBgNVBAsTCmhvc3RtYXN0ZXIxIDAe -BgNVBAMTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo -b3N0bWFzdGVyQHNwaS1pbmMub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW -iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms -1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD -VQQGEwJVUzEQMA4GA1UECBMHSW5kaWFuYTEVMBMGA1UEBxMMSW5kaWFuYXBvbGlz -MSgwJgYDVQQKEx9Tb2Z0d2FyZSBpbiB0aGUgUHVibGljIEludGVyZXN0MRMwEQYD -VQQLEwpob3N0bWFzdGVyMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkx -JTAjBgkqhkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDgwNTEz -MDgwNzU2WhcNMTgwNTExMDgwNzU2WjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh -cmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEe -MBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo -b3N0bWFzdGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEA3DbmR0LCxFF1KYdAw9iOIQbSGE7r7yC9kDyFEBOMKVuUY/b0LfEGQpG5 -GcRCaQi/izZF6igFM0lIoCdDkzWKQdh4s/Dvs24t3dHLfer0dSbTPpA67tfnLAS1 -fOH1fMVO73e9XKKTM5LOfYFIz2u1IiwIg/3T1c87Lf21SZBb9q1NE8re06adU1Fx -Y0b4ShZcmO4tbZoWoXaQ4mBDmdaJ1mwuepiyCwMs43pPx93jzONKao15Uvr0wa8u -jyoIyxspgpJyQ7zOiKmqp4pRQ1WFmjcDeJPI8L20QcgHQprLNZd6ioFl3h1UCAHx -ZFy3FxpRvB7DWYd2GBaY7r/2Z4GLBjXFS21ZGcfSxki+bhQog0oQnBv1b7ypjvVp -/rLBVcznFMn5WxRTUQfqzj3kTygfPGEJ1zPSbqdu1McTCW9rXRTunYkbpWry9vjQ -co7qch8vNGopCsUK7BxAhRL3pqXTT63AhYxMfHMgzFMY8bJYTAH1v+pk1Vw5xc5s -zFNaVrpBDyXfa1C2x4qgvQLCxTtVpbJkIoRRKFauMe5e+wsWTUYFkYBE7axt8Feo -+uthSKDLG7Mfjs3FIXcDhB78rKNDCGOM7fkn77SwXWfWT+3Qiz5dW8mRvZYChD3F -TbxCP3T9PF2sXEg2XocxLxhsxGjuoYvJWdAY4wCAs1QnLpnwFVMCAwEAAaOCAg8w -ggILMB0GA1UdDgQWBBQ0cdE41xU2g0dr1zdkQjuOjVKdqzCB8QYDVR0jBIHpMIHm -gBQ0cdE41xU2g0dr1zdkQjuOjVKdq6GBwqSBvzCBvDELMAkGA1UEBhMCVVMxEDAO -BgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMf -U29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1h -c3RlcjEeMBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcN -AQkBFhZob3N0bWFzdGVyQHNwaS1pbmMub3JnggkA6I62yfgqFCgwDwYDVR0TAQH/ -BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAAcwCQYDVR0SBAIwADAuBglghkgBhvhC -AQ0EIRYfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDAwBglghkgBhvhC -AQQEIxYhaHR0cHM6Ly9jYS5zcGktaW5jLm9yZy9jYS1jcmwucGVtMDIGCWCGSAGG -+EIBAwQlFiNodHRwczovL2NhLnNwaS1pbmMub3JnL2NlcnQtY3JsLnBlbTAhBgNV -HREEGjAYgRZob3N0bWFzdGVyQHNwaS1pbmMub3JnMA4GA1UdDwEB/wQEAwIBBjAN -BgkqhkiG9w0BAQUFAAOCAgEAtM294LnqsgMrfjLp3nI/yUuCXp3ir1UJogxU6M8Y -PCggHam7AwIvUjki+RfPrWeQswN/2BXja367m1YBrzXU2rnHZxeb1NUON7MgQS4M -AcRb+WU+wmHo0vBqlXDDxm/VNaSsWXLhid+hoJ0kvSl56WEq2dMeyUakCHhBknIP -qxR17QnwovBc78MKYiC3wihmrkwvLo9FYyaW8O4x5otVm6o6+YI5HYg84gd1GuEP -sTC8cTLSOv76oYnzQyzWcsR5pxVIBcDYLXIC48s9Fmq6ybgREOJJhcyWR2AFJS7v -dVkz9UcZFu/abF8HyKZQth3LZjQl/GaD68W2MEH4RkRiqMEMVObqTFoo5q7Gt/5/ -O5aoLu7HaD7dAD0prypjq1/uSSotxdz70cbT0ZdWUoa2lOvUYFG3/B6bzAKb1B+P -+UqPti4oOxfMxaYF49LTtcYDyeFIQpvLP+QX4P4NAZUJurgNceQJcHdC2E3hQqlg -g9cXiUPS1N2nGLar1CQlh7XU4vwuImm9rWgs/3K1mKoGnOcqarihk3bOsPN/nOHg -T7jYhkalMwIsJWE3KpLIrIF0aGOHM3a9BX9e1dUCbb2v/ypaqknsmHlHU5H2DjRa -yaXG67Ljxay2oHA1u8hRadDytaIybrw/oDc5fHE2pgXfDBLkFqfF1stjo5VwP+YE -o2A= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICqDCCAZACCQCHc5eBqnSyFTANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDEwt0 -aGlua3BhZC1wZTAeFw0xMTA3MTExNzU4NTVaFw0yMTA3MDgxNzU4NTVaMBYxFDAS -BgNVBAMTC3RoaW5rcGFkLXBlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtS6SgGwg+IEzl85WsXc2TnfLPZZTjoNGL/tb/fLIyaEx1/YopEyo0zSsenyA -95RFvPs4fK6+onmiRLq3YgYtbxSbv83/no/ggMkhMZw7Il2cguoxaiTpf6Z+zGNA -nX98M7ig5ISPnq+06Sw869NEAsYbiReNgazAJM53RdfSqZsok1A5CyXd3XUERLNm -UoCw917DNhu+N3xed/1t376yW4Bo/kkyrn1CRTG8jxi5xe+tCsDTWSjJzkS0e6WJ -MVK6PJxP0if7lw28Qh0zd9orR26HDbQ6TPpAF2sj7UhPleA4xkKjtiir3nITHkRR -bMvyd22gDAPIhZsF19X+dua8UwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCm+aKc -dvClUqqhe/wACAHn+NOLGAYK6kLVJaWUzvcSFMU9M6iyJllpxO0BwhdxXrmLtG72 -lermeKh4wTiREP16Qdh0nNbtiB4cOAzBvHNzj6RymGAL50RBugu0zlY3wDUxDGS8 -M/7c4ZAB/BvieA09o2tnUGmL7PijDGPLE5bclIwVAkXaeXKa6bG0kJnr0ndxX68d -AJGNoSFTdxBMPw6gau77w7wQULFKFj4xTEKkYngNDsKERc/u/yrYRfkeehehRNmT -BcKocK4dDPPPzcJ12AjBnYtxitTRlJyXAkNVjLMTSg7lAU36JjNkvXqhSqDQJf04 -yW2ZnchxqK6f0gWO ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX -DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl -ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv -b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 -qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp -uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU -Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE -pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp -5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M -UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN -GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy -5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv -6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK -eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 -B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ -BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov -L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG -SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS -CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen -5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 -IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK -gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL -+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL -vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm -bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk -N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC -Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z -ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO -TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy -MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk -ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn -ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 -9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO -hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U -tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o -BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh -SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww -OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv -cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA -7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k -/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm -eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 -u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy -7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR -iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCB -rjELMAkGA1UEBhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcp -MRIwEAYDVQQHEwlTdHV0dGdhcnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fz -c2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVTLVRSVVNUIEF1dGhlbnRpY2F0aW9u -IGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0wNTA2MjIwMDAwMDBa -Fw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFkZW4t -V3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMg -RGV1dHNjaGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJV -U1QgQXV0aGVudGljYXRpb24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBO -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1 -toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob4QSwI7+Vio5bG0F/WsPo -TUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXLg3KSwlOy -ggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1 -XgqfeN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteF -hy+S8dF2g08LOlk3KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm -7QIDAQABo4GSMIGPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEG -MCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJvbmxpbmUxLTIwNDgtNTAdBgNV -HQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAUD8oeXHngovMp -ttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD -pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFo -LtU96G7m1R08P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersF -iXOMy6ZNwPv2AtawB6MDwidAnwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0y -h9WUUpY6RsZxlj33mA6ykaqP2vROJAA5VeitF7nTNCtKqUDMFypVZUF0Qn71wK/I -k63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8bHz2eBIPdltkdOpQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk -MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 -YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg -Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT -AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp -Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 -m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih -FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ -TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F -EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco -kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu -HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF -vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo -19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC -L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW -bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX -JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw -FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j -BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc -K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf -ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik -Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB -sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e -3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR -ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip -mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH -b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf -rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms -hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y -zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 -MBr1mmz0DlP5OlvRHA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu -IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw -WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD -ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y -IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn -IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ -6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob -jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw -izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl -+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY -zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP -pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF -KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW -ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB -AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 -ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW -IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA -A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 -uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ -FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 -jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ -u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D -YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 -puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa -icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG -DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x -kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z -Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu -IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow -RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY -U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv -Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br -YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF -nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH -6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt -eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ -c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ -MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH -HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf -jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 -5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB -rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c -wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB -AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp -WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 -xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ -2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ -IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 -aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X -em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR -dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ -OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ -hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy -tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ -MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow -PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR -IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q -gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy -yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts -F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 -jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx -ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC -VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK -YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH -EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN -Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud -DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE -MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK -UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ -TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf -qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK -ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE -JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 -hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 -EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm -nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX -udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz -ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe -LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl -pYYsfPQS ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV -BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 -Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 -OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i -SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc -VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf -tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg -uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J -XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK -8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 -5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 -kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 -Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz -JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 -Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS -GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt -ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 -au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV -hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI -dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV -BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 -Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 -OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i -SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc -VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW -Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q -Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 -1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq -ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 -Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX -XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 -Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz -JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 -Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN -irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 -TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 -g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB -95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj -S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF -MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU -QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI -MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN -AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla -Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy -ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y -IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 -c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA -dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y -AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw -TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8 -/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 -LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/ -jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms -Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF -MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU -QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI -MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN -AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla -Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy -ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y -IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 -c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA -dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF -Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw -Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW -w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 -LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE -Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD -2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV -BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 -c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy -MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl -ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm -BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF -5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv -DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v -zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT -yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj -dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh -MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI -4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz -dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY -aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G -DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV -CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH -LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV -BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 -c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx -MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg -R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD -VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR -JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T -fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu -jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z -wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ -fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD -VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G -CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 -7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn -8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs -ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT -ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ -2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE -SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg -Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV -BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl -cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA -vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu -Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a -0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 -4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN -eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD -R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG -A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu -dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME -Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 -WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw -HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ -KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO -Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX -wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ -2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 -9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 -jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 -aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE -SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw -ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU -REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr -2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s -2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU -GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj -dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r -TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB -AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv -c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl -ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu -MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg -T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud -HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD -VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny -bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy -MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ -J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG -SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom -JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO -inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y -caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB -mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ -YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 -BKNDLdr8C2LqL19iUw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt -YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu -Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT -AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa -MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG -cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh -d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY -DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E -rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq -uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN -BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP -MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa -/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei -gQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy -dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t -MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB -MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG -A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl -cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE -VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ -ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR -uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG -9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM -pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp -IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi -BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw -MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig -YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v -dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ -BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 -papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K -DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 -KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox -XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB -rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV -BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa -Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl -LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u -MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl -ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm -gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 -YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf -b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 -9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S -zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk -OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA -2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW -oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c -KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM -m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu -MdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB -qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV -BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw -NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j -LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG -A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs -W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta -3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk -6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 -Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J -NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP -r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU -DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz -YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 -/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ -LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 -jVaMaA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm -MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx -MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 -dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl -cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 -DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD -gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 -yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX -L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj -EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG -7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e -QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ -qdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN -BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd -BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN -MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g -Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG -A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l -c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT -6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa -Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL -8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC -9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ -pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ -CayJSdM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS -MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp -bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw -VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy -YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy -dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 -ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe -Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx -GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls -aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU -QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh -xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 -aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr -IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h -gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK -O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO -fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw -lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL -hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID -AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP -NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t -wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM -7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh -gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n -oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs -yZyQ2uypQjyttgI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc -UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg -MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 -dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz -MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy -dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD -VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg -xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu -xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 -XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k -heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J -YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C -urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 -JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 -b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV -9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 -kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh -fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy -B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA -aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS -RGQDJereW26fyfJOrN3H ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc -UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS -S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg -SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 -WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv -bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU -UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw -bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe -LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef -J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh -R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ -Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX -JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p -zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S -Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq -ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 -Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz -gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH -uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS -y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB -kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw -IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD -VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu -dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 -E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ -D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK -4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq -lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW -bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB -o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT -MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js -LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr -BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB -AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj -j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH -KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv -2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 -mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB -rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt -Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa -Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV -BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l -dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE -AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B -YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 -hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l -L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm -SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM -1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws -6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw -Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 -aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH -AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u -7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 -xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ -rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim -eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk -USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe -MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v -d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh -cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn -0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ -M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a -MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd -oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI -DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy -oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 -dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy -bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF -BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli -CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE -CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t -3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS -KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy -NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y -LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ -TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y -TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 -LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW -I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw -nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy -NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY -dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 -WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS -v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v -UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu -IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK -VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm -Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J -h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul -uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 -DzFc6PLZ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 -nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO -8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV -ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb -PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 -6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr -n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a -qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 -wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 -ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs -pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 -E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0f -zGVuDLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHi -TkVWaR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAFgVKTk8d6PaXCUDfGD67gmZPCcQcMgMCeazh88K4hiW -NWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n0a3hUKw8fGJLj7qE1xIV -Gx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZRjXZ+Hxb ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns -YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y -aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe -Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj -IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx -KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM -HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw -DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC -AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji -nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX -rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn -jBJ7xUS0rg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy -aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp -Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV -BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp -Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g -Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt -IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU -J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO -JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY -wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o -koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN -qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E -Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe -xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u -7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU -sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI -sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP -cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh -YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 -FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg -J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc -r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 -pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 -13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk -U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i -F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY -oJ2daZH9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b -N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t -KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu -kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm -CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ -Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu -imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te -2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe -DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p -F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt -TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp -U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg -SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln -biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm -GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve -fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ -aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj -aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW -kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC -4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga -FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 -nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex -t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz -SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG -BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ -rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ -NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E -BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH -BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv -MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE -p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y -5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK -WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ -4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N -hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i -2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ -2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM -HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK -qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj -cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y -cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP -T8qAkbYp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 -GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ -+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd -U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm -NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY -ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ -ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 -CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq -g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm -fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c -2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ -bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB -vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W -ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 -IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y -IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh -bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF -9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH -H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H -LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN -/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT -rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw -WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs -exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 -sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ -seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz -4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ -BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR -lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 -7M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr -MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl -cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw -CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h -dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l -cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h -2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E -lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV -ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq -299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t -vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL -dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF -AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR -zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 -LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd -7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw -++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v -dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0 -MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww -KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G -A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13 -5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE -SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O -JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu -ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE -AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB -AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB -CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw -b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo -7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/ -0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7 -nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx -x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ -33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx -IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs -cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v -dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 -MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl -bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD -DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r -WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU -Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs -HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj -z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf -SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl -AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG -KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P -AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j -BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC -VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX -ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB -ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd -/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB -A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn -k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 -iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv -2G0xffX8oRAHh84vWdw+WNs= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt new file mode 100644 index 000000000..2b02ff6c0 --- /dev/null +++ b/tester/CMakeLists.txt @@ -0,0 +1,81 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +set(SOURCE_FILES + common/bc_tester_utils.c + accountmanager.c + call_tester.c + dtmf_tester.c + eventapi_tester.c + flexisip_tester.c + liblinphone_tester.c + log_collection_tester.c + message_tester.c + multi_call_tester.c + multicast_call_tester.c + offeranswer_tester.c + player_tester.c + presence_tester.c + proxy_config_tester.c + quality_reporting_tester.c + register_tester.c + remote_provisioning_tester.c + setup_tester.c + stun_tester.c + tester.c + tunnel_tester.c + upnp_tester.c + video_tester.c +) + +add_definitions(-DBC_CONFIG_FILE="config.h") + +if(IOS) + +add_library(linphonetester STATIC ${SOURCE_FILES}) +target_include_directories(linphonetester PUBLIC ${CUNIT_INCLUDE_DIRS} PRIVATE common) +target_link_libraries(linphonetester linphone ${CUNIT_LIBRARIES}) +install(TARGETS linphonetester + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) +install(FILES "liblinphone_tester.h" "common/bc_tester_utils.h" + DESTINATION include/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +else() + +add_executable(liblinphone_tester ${SOURCE_FILES}) +set_target_properties(liblinphone_tester PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories(liblinphone_tester PUBLIC ${CUNIT_INCLUDE_DIRS} PRIVATE common) +target_link_libraries(liblinphone_tester linphone ${CUNIT_LIBRARIES}) +if (GTK2_FOUND) + target_compile_definitions(liblinphone_tester PRIVATE HAVE_GTK) + target_include_directories(liblinphone_tester PUBLIC ${GTK2_INCLUDE_DIRS}) + target_link_libraries(liblinphone_tester linphone ${GTK2_LIBRARIES}) +endif() + +endif() + diff --git a/tester/Makefile.am b/tester/Makefile.am new file mode 100644 index 000000000..c3c3552b1 --- /dev/null +++ b/tester/Makefile.am @@ -0,0 +1,74 @@ +EXTRA_DIST= tester_hosts sounds images certificates rcfiles + + +if BUILD_CUNIT_TESTS + +# there are 2 targets: liblinphonetester.la and the executable liblinphone_tester + +liblinphonedir = $(includedir)/linphone +liblinphone_HEADERS = liblinphone_tester.h + +lib_LTLIBRARIES = liblinphonetester.la + +liblinphonetester_la_SOURCES = \ + accountmanager.c \ + call_tester.c \ + dtmf_tester.c \ + eventapi_tester.c \ + flexisip_tester.c \ + log_collection_tester.c \ + message_tester.c \ + multi_call_tester.c \ + multicast_call_tester.c \ + offeranswer_tester.c \ + player_tester.c \ + presence_tester.c \ + proxy_config_tester.c \ + quality_reporting_tester.c \ + register_tester.c \ + remote_provisioning_tester.c \ + setup_tester.c \ + stun_tester.c \ + tunnel_tester.c \ + tester.c \ + upnp_tester.c \ + video_tester.c \ + common/bc_tester_utils.c + +liblinphonetester_ladir = $(includedir)/linphone +liblinphonetester_la_HEADERS = common/bc_tester_utils.h + +liblinphonetester_la_LDFLAGS= -no-undefined +liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi -I$(top_srcdir)/tester/common +AM_CFLAGS = -DBC_CONFIG_FILE=\"config.h\" $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) \ + -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) \ + $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) $(SQLITE3_CFLAGS) + +if BUILD_GTK_UI + +liblinphonetester_la_LIBADD += $(LIBGTK_LIBS) $(LIBGTKMAC_LIBS) +AM_CFLAGS += $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) -DHAVE_GTK + +endif + +if !BUILD_IOS + +noinst_PROGRAMS = liblinphone_tester + +liblinphone_tester_SOURCES = liblinphone_tester.c +liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la -lm + +endif + + +test: liblinphone_tester + ./liblinphone_tester --config $(abs_srcdir) $(TEST_OPTIONS) + +else !BUILD_CUNIT_TESTS + +test: + @echo "CUnit must be installed to be able to run the tests!" + +endif !BUILD_CUNIT_TESTS diff --git a/tester/README b/tester/README new file mode 100644 index 000000000..dfc060ecc --- /dev/null +++ b/tester/README @@ -0,0 +1,9 @@ +This is the test suite of liblinphone, with many tests suites for Register, Calls, Message, Presence. + +All thoses tests suites require a SIP server configured accordingly in order to execute. Naturally a Flexisip SIP server is used, whose configuration is put in the flexisip/ directory here. + +In order to invoke it, just place into the tester directory and run +$ flexisip --configfile flexisip/flexisip.conf + +The tester_hosts file contains the host-like DNS configuration file to be used by the test suite in order to resolve the virtual SIP domains used by the SIP stack. +It is possible to run the flexisip SIP server and the test suite on the same machine by passing a new tester_hosts file where domains resolve to 127.0.0.1 to the tester, using the --dns-hosts option. diff --git a/tester/accountmanager.c b/tester/accountmanager.c new file mode 100644 index 000000000..c3b6d1090 --- /dev/null +++ b/tester/accountmanager.c @@ -0,0 +1,233 @@ + /* + tester - liblinphone test suite + 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, see . + */ + +#include "liblinphone_tester.h" +#include "private.h" + +struct _Account{ + LinphoneAddress *identity; + LinphoneAddress *modified_identity; + char *password; + int created; + int done; + int auth_requested; +}; + +typedef struct _Account Account; + +Account *account_new(LinphoneAddress *identity, const char *unique_id){ + char *modified_username; + Account *obj=ms_new0(Account,1); + + /* we need to inhibit leak detector because the two LinphoneAddress will remain behond the scope of the test being run */ + belle_sip_object_inhibit_leak_detector(TRUE); + obj->identity=linphone_address_clone(identity); + obj->password=sal_get_random_token(8); + obj->modified_identity=linphone_address_clone(identity); + modified_username=ms_strdup_printf("%s_%s",linphone_address_get_username(identity), unique_id); + linphone_address_set_username(obj->modified_identity, modified_username); + ms_free(modified_username); + belle_sip_object_inhibit_leak_detector(FALSE); + return obj; +}; + +void account_destroy(Account *obj){ + linphone_address_unref(obj->identity); + linphone_address_unref(obj->modified_identity); + ms_free(obj->password); + ms_free(obj); +} + +struct _AccountManager{ + char *unique_id; + MSList *accounts; +}; + +typedef struct _AccountManager AccountManager; + +static AccountManager *the_am=NULL; + +AccountManager *account_manager_get(void){ + if (the_am==NULL){ + the_am=ms_new0(AccountManager,1); + the_am->unique_id=sal_get_random_token(6); + } + return the_am; +} + +void account_manager_destroy(void){ + if (the_am){ + ms_free(the_am->unique_id); + ms_list_free_with_data(the_am->accounts,(void(*)(void*))account_destroy); + ms_free(the_am); + } + the_am=NULL; + ms_message("Test account manager destroyed."); +} + +Account *account_manager_get_account(AccountManager *m, const LinphoneAddress *identity){ + MSList *it; + + for(it=m->accounts;it!=NULL;it=it->next){ + Account *a=(Account*)it->data; + if (linphone_address_weak_equal(a->identity,identity)){ + return a; + } + } + return NULL; +} + +static void account_created_on_server_cb(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *info){ + Account *account=(Account*)linphone_core_get_user_data(lc); + switch(state){ + case LinphoneRegistrationOk: + account->created=1; + break; + case LinphoneRegistrationCleared: + account->done=1; + break; + default: + break; + } +} + +static void account_created_auth_requested_cb(LinphoneCore *lc, const char *username, const char *realm, const char *domain){ + Account *account=(Account*)linphone_core_get_user_data(lc); + account->auth_requested=1; +} + +void account_create_on_server(Account *account, const LinphoneProxyConfig *refcfg){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc; + LinphoneAddress *tmp_identity=linphone_address_clone(account->modified_identity); + LinphoneProxyConfig *cfg; + LinphoneAuthInfo *ai; + char *tmp; + LinphoneAddress *server_addr; + LCSipTransports tr; + + vtable.registration_state_changed=account_created_on_server_cb; + vtable.auth_info_requested=account_created_auth_requested_cb; + lc=configure_lc_from(&vtable,bc_tester_get_resource_dir_prefix(),NULL,account); + 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); + + cfg=linphone_core_create_proxy_config(lc); + linphone_address_set_secure(tmp_identity, FALSE); + linphone_address_set_password(tmp_identity,account->password); + linphone_address_set_header(tmp_identity,"X-Create-Account","yes"); + tmp=linphone_address_as_string(tmp_identity); + linphone_proxy_config_set_identity(cfg,tmp); + ms_free(tmp); + linphone_address_unref(tmp_identity); + + server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg)); + linphone_address_set_secure(server_addr, FALSE); + linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/ + linphone_address_set_port(server_addr,0); + tmp=linphone_address_as_string(server_addr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + linphone_address_unref(server_addr); + linphone_proxy_config_set_expires(cfg,3600); + + linphone_core_add_proxy_config(lc,cfg); + + if (wait_for_until(lc,NULL,&account->auth_requested,1,10000)==FALSE){ + ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg)); + } + linphone_proxy_config_edit(cfg); + tmp_identity=linphone_address_clone(account->modified_identity); + linphone_address_set_secure(tmp_identity, FALSE); + tmp=linphone_address_as_string(tmp_identity); + linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/ + linphone_address_unref(tmp_identity); + ms_free(tmp); + linphone_proxy_config_done(cfg); + + ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity), + NULL, + account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity)); + linphone_core_add_auth_info(lc,ai); + linphone_auth_info_destroy(ai); + + if (wait_for_until(lc,NULL,&account->created,1,3000)==FALSE){ + ms_fatal("Account for %s is not working on server.", linphone_proxy_config_get_identity(refcfg)); + } + linphone_core_remove_proxy_config(lc,cfg); + linphone_proxy_config_unref(cfg); + if (wait_for_until(lc,NULL,&account->done,1,3000)==FALSE){ + ms_error("Account creation could not clean the registration context."); + } + linphone_core_destroy(lc); +} + +LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg){ + LinphoneCore *lc=linphone_proxy_config_get_core(cfg); + const char *identity=linphone_proxy_config_get_identity(cfg); + LinphoneAddress *id_addr=linphone_address_new(identity); + Account *account=account_manager_get_account(m,id_addr); + LinphoneAuthInfo *ai; + char *tmp; + bool_t create_account=FALSE; + const LinphoneAuthInfo *original_ai = linphone_core_find_auth_info(lc + ,NULL + , linphone_address_get_username(id_addr) + , linphone_address_get_domain(id_addr)); + + if (!account){ + account=account_new(id_addr,m->unique_id); + ms_message("No account for %s exists, going to create one.",identity); + create_account=TRUE; + m->accounts=ms_list_append(m->accounts,account); + } + /*modify the username of the identity of the proxy config*/ + linphone_address_set_username(id_addr, linphone_address_get_username(account->modified_identity)); + tmp=linphone_address_as_string(id_addr); + linphone_proxy_config_set_identity(cfg,tmp); + ms_free(tmp); + + if (create_account){ + account_create_on_server(account,cfg); + } + + /*remove previous auth info to avoid mismatching*/ + if (original_ai) + linphone_core_remove_auth_info(lc,original_ai); + + ai=linphone_auth_info_new(linphone_address_get_username(account->modified_identity), + NULL, + account->password,NULL,NULL,linphone_address_get_domain(account->modified_identity)); + linphone_core_add_auth_info(lc,ai); + linphone_auth_info_destroy(ai); + + linphone_address_unref(id_addr); + return account->modified_identity; +} + +void linphone_core_manager_check_accounts(LinphoneCoreManager *m){ + const MSList *it; + AccountManager *am=account_manager_get(); + + for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data; + account_manager_check_account(am,cfg); + } +} diff --git a/tester/call_tester.c b/tester/call_tester.c new file mode 100644 index 000000000..953632bb7 --- /dev/null +++ b/tester/call_tester.c @@ -0,0 +1,5045 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#include +#include +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "mediastreamer2/msutils.h" +#include "belle-sip/sipstack.h" + +#ifdef _WIN32 +#define unlink _unlink +#ifndef F_OK +#define F_OK 00 /*visual studio does not define F_OK*/ +#endif +#endif + +static void srtp_call(void); +static char *create_filepath(const char *dir, const char *filename, const char *ext); + +// prototype definition for call_recording() +#ifdef ANDROID +#ifdef HAVE_OPENH264 +extern void libmsopenh264_init(void); +#endif +#endif + +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; + case LinphoneCallEarlyUpdating: counters->number_of_LinphoneCallEarlyUpdating++;break; + case LinphoneCallEarlyUpdatedByRemote: counters->number_of_LinphoneCallEarlyUpdatedByRemote++;break; + default: + BC_FAIL("unexpected event");break; + } +} + +void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *lstats) { + stats* counters = get_stats(lc); + counters->number_of_LinphoneCallStatsUpdated++; + if (lstats->updated & LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { + counters->number_of_rtcp_received++; + } + if (lstats->updated & LINPHONE_CALL_STATS_SENT_RTCP_UPDATE ) { + counters->number_of_rtcp_sent++; + } + if (lstats->updated & LINPHONE_CALL_STATS_PERIODICAL_UPDATE ) { + int tab_size = sizeof (counters->audio_download_bandwidth)/sizeof(int); + int index = (counters->current_bandwidth_index++) % tab_size; + + counters->current_audio_download_bandwidth = counters->audio_download_bandwidth + index; + counters->current_audio_upload_bandwidth = counters->audio_upload_bandwidth +index; + + counters->audio_download_bandwidth[index] = linphone_call_get_audio_stats(call)->download_bandwidth; + counters->audio_upload_bandwidth[index] = linphone_call_get_audio_stats(call)->upload_bandwidth; + counters->video_download_bandwidth[index] = linphone_call_get_video_stats(call)->download_bandwidth; + counters->video_upload_bandwidth[index] = linphone_call_get_video_stats(call)->upload_bandwidth; + } + +} + +void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) { + 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], is now [%s]",linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + ,from + ,to + ,(on?"encrypted":"unencrypted")); + ms_free(to); + ms_free(from); + counters = get_stats(lc); + if (on) + counters->number_of_LinphoneCallEncryptedOn++; + else + counters->number_of_LinphoneCallEncryptedOff++; +} + +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: + BC_FAIL("unexpected event");break; + } +} + + +void linphone_call_iframe_decoded_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++; +} + +void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { + LinphoneCall *c1,*c2; + MSTimeSpec ts; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + + if (!c1 || !c2) return; + linphone_call_ref(c1); + linphone_call_ref(c2); + + liblinphone_tester_clock_start(&ts); + do { + 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,NULL,0,20); /*just to sleep while iterating*/ + }while (!liblinphone_tester_clock_elapsed(&ts,15000)); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(c1)->round_trip_delay,0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(c2)->round_trip_delay,0.0,float,"%f"); + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { + BC_ASSERT_GREATER(linphone_call_get_video_stats(c1)->round_trip_delay,0.0,float,"%f"); + } + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { + BC_ASSERT_GREATER(linphone_call_get_video_stats(c2)->round_trip_delay,0.0,float,"%f"); + } + linphone_call_unref(c1); + linphone_call_unref(c2); +} + +static void setup_sdp_handling(const LinphoneCallTestParams* params, LinphoneCoreManager* mgr ){ + if( params->sdp_removal ){ + sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateRemove); + } else if( params->sdp_simulate_error ){ + sal_default_set_sdp_handling(mgr->lc->sal, SalOpSDPSimulateError); + } +} + +bool_t call_with_params2(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + , const LinphoneCallTestParams *caller_test_params + , const LinphoneCallTestParams *callee_test_params + , bool_t build_callee_params) { + int retry=0; + stats initial_caller=caller_mgr->stat; + stats initial_callee=callee_mgr->stat; + bool_t result=FALSE; + LinphoneCallParams *caller_params = caller_test_params->base; + LinphoneCallParams *callee_params = callee_test_params->base; + bool_t did_receive_call; + LinphoneCall *callee_call=NULL; + + setup_sdp_handling(caller_test_params, caller_mgr); + setup_sdp_handling(callee_test_params, callee_mgr); + + if (!caller_params){ + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + }else{ + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)); + } + + did_receive_call = wait_for(callee_mgr->lc + ,caller_mgr->lc + ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived + ,initial_callee.number_of_LinphoneCallIncomingReceived+1); + BC_ASSERT_EQUAL(did_receive_call, !callee_test_params->sdp_simulate_error, int, "%d"); + + sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal); + sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal); + + if (!did_receive_call) return 0; + + + if (linphone_core_get_calls_nb(callee_mgr->lc)<=1) + BC_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1, int, "%d"); + + + 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++ < 100) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(20000); + } + + + BC_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)); + + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + callee_call=linphone_core_get_call_by_remote_address2(callee_mgr->lc,caller_mgr->identity); + + if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) { + return 0; + } else if (caller_mgr->identity){ + 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) { + /*don't check in case of p asserted id*/ + if (!lp_config_get_int(callee_mgr->lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) + BC_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(callee_call))); + } else { + BC_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_call_get_remote_address(linphone_core_get_current_call(callee_mgr->lc)))); + } + linphone_address_destroy(callee_from); + } + + + if (callee_params){ + linphone_core_accept_call_with_params(callee_mgr->lc,callee_call,callee_params); + }else if (build_callee_params){ + LinphoneCallParams *default_params=linphone_core_create_call_params(callee_mgr->lc,callee_call); + ms_message("Created default call params with video=%i", linphone_call_params_video_enabled(default_params)); + linphone_core_accept_call_with_params(callee_mgr->lc,callee_call,default_params); + linphone_call_params_destroy(default_params); + }else{ + linphone_core_accept_call(callee_mgr->lc,callee_call); + } + + BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + + result = wait_for_until(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1, 2000) + && + wait_for_until(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1, 2000); + + if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone + || linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) { + /*wait for encryption to be on, in case of zrtp or dtls, it can take a few seconds*/ + if ( (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) + || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS)) + wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1); + if ((linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) + || (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionDTLS) + || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS) /*also take care of caller policy*/ ) + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); + { + const LinphoneCallParams* call_param = linphone_call_get_current_params(callee_call); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc), int, "%d"); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc), int, "%d"); + + } + } + /*wait ice re-invite*/ + if (linphone_core_get_firewall_policy(caller_mgr->lc) == LinphonePolicyUseIce + && linphone_core_get_firewall_policy(callee_mgr->lc) == LinphonePolicyUseIce + && !linphone_core_sdp_200_ack_enabled(caller_mgr->lc)) { /*ice does not work with sdp less invite*/ + BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+2)); + BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+2)); + + } + return result; +} + +bool_t call_with_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + ,const LinphoneCallParams *caller_params + ,const LinphoneCallParams *callee_params){ + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + caller_test_params.base = (LinphoneCallParams*)caller_params; + callee_test_params.base = (LinphoneCallParams*)caller_params; + return call_with_params2(caller_mgr,callee_mgr,&caller_test_params,&callee_test_params,FALSE); +} + +bool_t call_with_test_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + ,const LinphoneCallTestParams *caller_test_params + ,const LinphoneCallTestParams *callee_test_params){ + return call_with_params2(caller_mgr,callee_mgr,caller_test_params,callee_test_params,FALSE); +} + +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); +} + +void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ + linphone_core_terminate_all_calls(m1->lc); + BC_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m1->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m1->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallReleased,1)); +} + +void simple_call_base(bool_t enable_multicast_recv_side) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + const LinphoneAddress *from; + LinphoneCall *pauline_call; + LinphoneProxyConfig* marie_cfg; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + /* with the account manager, we might lose the identity */ + marie_cfg = linphone_core_get_default_proxy_config(marie->lc); + { + LinphoneAddress* marie_addr = linphone_address_clone(linphone_proxy_config_get_identity_address(marie_cfg)); + char* marie_tmp_id = NULL; + linphone_address_set_display_name(marie_addr, "Super Marie"); + marie_tmp_id = linphone_address_as_string(marie_addr); + + linphone_proxy_config_edit(marie_cfg); + linphone_proxy_config_set_identity(marie_cfg,marie_tmp_id); + linphone_proxy_config_done(marie_cfg); + + ms_free(marie_tmp_id); + linphone_address_destroy(marie_addr); + } + + linphone_core_enable_audio_multicast(pauline->lc,enable_multicast_recv_side); + + BC_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + /*check that display name is correctly propagated in From */ + if (pauline_call){ + from=linphone_call_get_remote_address(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_PTR_NOT_NULL(from); + if (from){ + const char *dname=linphone_address_get_display_name(from); + BC_ASSERT_PTR_NOT_NULL(dname); + if (dname){ + BC_ASSERT_STRING_EQUAL(dname, "Super Marie"); + } + } + } + + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void simple_call() { + simple_call_base(FALSE); +} + +static void call_with_timeouted_bye(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + belle_sip_timer_config_t timer_config; + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + BC_ASSERT_TRUE(call(marie,pauline)); + + sal_set_send_error(pauline->lc->sal,1500); /*to trash the message without generating error*/ + timer_config.T1=50; /*to have timer F = 3s*/ + timer_config.T2=4000; + timer_config.T3=0; + timer_config.T4=5000; + + belle_sip_stack_set_timer_config(sal_get_belle_sip_stack(pauline->lc->sal),&timer_config); + linphone_core_terminate_all_calls(pauline->lc); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1,timer_config.T1*84)); + + sal_set_send_error(pauline->lc->sal,0); + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1,5000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void direct_call_over_ipv6(){ + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + + if (liblinphone_tester_ipv6_available()){ + LCSipTransports pauline_transports; + LinphoneAddress* pauline_dest = linphone_address_new("sip:[::1];transport=tcp"); + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_enable_ipv6(marie->lc,TRUE); + linphone_core_enable_ipv6(pauline->lc,TRUE); + linphone_core_set_default_proxy_config(marie->lc,NULL); + /*wait for register in v6 mode, however sip2.linphone.org has an ipv6 address but doesn't listen to it*/ +#if 0 + BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 2, 2000)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 2, 2000)); +#endif + + linphone_core_get_sip_transports_used(pauline->lc,&pauline_transports); + linphone_address_set_port(pauline_dest,pauline_transports.tcp_port); + linphone_core_invite_address(marie->lc,pauline_dest); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallOutgoingRinging,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1)); + linphone_core_accept_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1)); + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_address_destroy(pauline_dest); + }else ms_warning("Test skipped, no ipv6 available"); +} + +static void call_outbound_with_multiple_proxy() { + LinphoneCoreManager* marie = linphone_core_manager_new2( "marie_rc", FALSE); + LinphoneCoreManager* pauline = linphone_core_manager_new2( "pauline_tcp_rc", FALSE); + + LinphoneProxyConfig* lpc = NULL; + LinphoneProxyConfig* registered_lpc = linphone_proxy_config_new(); + + linphone_core_get_default_proxy(marie->lc, &lpc); + linphone_core_set_default_proxy(marie->lc,NULL); + + BC_ASSERT_FATAL(lpc != NULL); + BC_ASSERT_FATAL(registered_lpc != NULL); + + // create new LPC that will successfully register + linphone_proxy_config_set_identity(registered_lpc, linphone_proxy_config_get_identity(lpc)); + linphone_proxy_config_set_server_addr(registered_lpc, linphone_proxy_config_get_addr(lpc)); + linphone_proxy_config_set_route(registered_lpc, linphone_proxy_config_get_route(lpc)); + linphone_proxy_config_enable_register(registered_lpc, TRUE); + + linphone_core_add_proxy_config(marie->lc, registered_lpc); + + // set first LPC to unreacheable proxy addr + linphone_proxy_config_edit(lpc); + linphone_proxy_config_set_server_addr(lpc,"12.13.14.15:5223;transport=udp"); + linphone_proxy_config_set_route(lpc, "12.13.14.15:5223;transport=udp;lr"); + linphone_proxy_config_done(lpc); + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + BC_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationProgress, 2, 200)); + BC_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + // calling marie should go through the second proxy config + BC_ASSERT_TRUE(call(marie, pauline)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#if 0 /* TODO: activate test when the implementation is ready */ +static void multiple_answers_call() { + /* Scenario is this: pauline calls marie, which is registered 2 times. + Both linphones answer at the same time, and only one should get the + call running, the other should be terminated */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); + LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); + + LinphoneCall* call1, *call2; + + MSList* lcs = ms_list_append(NULL,pauline->lc); + lcs = ms_list_append(lcs,marie1->lc); + lcs = ms_list_append(lcs,marie2->lc); + + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + BC_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); + + // marie 1 and 2 answer at the same time + call1 = linphone_core_get_current_call(marie1->lc); + call2 = linphone_core_get_current_call(marie2->lc); + + BC_ASSERT_PTR_NOT_NULL_FATAL(call1); + BC_ASSERT_PTR_NOT_NULL_FATAL(call2); + + BC_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0, int, "%d"); + BC_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0, int, "%d"); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); + + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); +} +#endif + +static void multiple_answers_call_with_media_relay(void) { + + /* Scenario is this: pauline calls marie, which is registered 2 times. + * Both linphones answer at the same time, and only one should get the + * call running, the other should be terminated */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc" ); + LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); + + LinphoneCall* call1, *call2; + + MSList* lcs = ms_list_append(NULL,pauline->lc); + lcs = ms_list_append(lcs,marie1->lc); + lcs = ms_list_append(lcs,marie2->lc); + + linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL); + linphone_core_set_user_agent(marie1->lc, "Natted Linphone", NULL); + linphone_core_set_user_agent(marie2->lc, "Natted Linphone", NULL); + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + BC_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); + + // marie 1 and 2 answer at the same time + call1 = linphone_core_get_current_call(marie1->lc); + call2 = linphone_core_get_current_call(marie2->lc); + + BC_ASSERT_PTR_NOT_NULL_FATAL(call1); + BC_ASSERT_PTR_NOT_NULL_FATAL(call2); + + BC_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0, int, "%d"); + BC_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0, int, "%d"); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); + + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); +} + +static void call_with_specified_codec_bitrate(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + const char * codec = "opus"; + int rate = 48000; + int min_bw=24; + int max_bw=50; + +#ifdef __arm__ + if (ms_get_cpu_count() <2) { /*2 opus codec channel + resampler is too much for a single core*/ +#ifndef ANDROID + codec = "speex"; + rate = 8000; + min_bw=20; + max_bw=35; +#else + BC_PASS("Test requires at least a dual core"); + goto end; +#endif + } +#endif + /*Force marie to play from file: if soundcard is used and it is silient, then vbr mode will drop down the bitrate + Note that a play file is already set by linphone_core_manager_new() (but not used)*/ + linphone_core_set_use_files(marie->lc, TRUE); + + if (linphone_core_find_payload_type(marie->lc,codec,rate,-1)==NULL){ + BC_PASS("opus codec not supported, test skipped."); + goto end; + } + + disable_all_audio_codecs_except_one(marie->lc,codec,rate); + disable_all_audio_codecs_except_one(pauline->lc,codec,rate); + + linphone_core_set_payload_type_bitrate(marie->lc, + linphone_core_find_payload_type(marie->lc,codec,rate,-1), + max_bw); + linphone_core_set_payload_type_bitrate(pauline->lc, + linphone_core_find_payload_type(pauline->lc,codec,rate,-1), + min_bw); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + liblinphone_tester_check_rtcp(marie,pauline); + /*wait a bit that bitstreams are stabilized*/ + wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000); + + BC_ASSERT_LOWER(linphone_core_manager_get_mean_audio_down_bw(marie), min_bw+5+min_bw*.1, int, "%i"); + BC_ASSERT_GREATER(linphone_core_manager_get_mean_audio_down_bw(marie), 10, int, "%i"); /*check that at least something is received */ + BC_ASSERT_GREATER(linphone_core_manager_get_mean_audio_down_bw(pauline), (max_bw-5-max_bw*.1), int, "%i"); + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + 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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; + LinphoneProxyConfig* proxy; + const LinphoneAddress* identity; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + + linphone_core_get_default_proxy(lc_marie,&proxy); + BC_ASSERT_PTR_NOT_NULL (proxy); + identity = linphone_proxy_config_get_identity_address(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; + + BC_ASSERT_TRUE (wait_for(lc_marie,lc_marie,&stat_marie->number_of_LinphoneRegistrationOk,1)); + + linphone_core_invite_address(lc_marie,pauline->identity); + + BC_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); + BC_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); + BC_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1, int, "%d"); + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(lc_pauline)); + if (linphone_core_get_current_call_remote_address(lc_pauline)) { + BC_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); + + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + BC_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + BC_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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0, int, "%d"); + BC_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); +} + +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate){ + 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,rate,-1); + BC_ASSERT_PTR_NOT_NULL_FATAL(pt); + linphone_core_enable_payload_type(lc,pt,TRUE); +} + +#ifdef VIDEO_ENABLED +void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime) { + const MSList *codecs = linphone_core_get_video_codecs(lc); + const MSList *it = NULL; + PayloadType *pt = NULL; + + for(it = codecs; it != NULL; it = it->next) { + linphone_core_enable_payload_type(lc, (PayloadType *)it->data, FALSE); + } + pt = linphone_core_find_payload_type(lc, mime, -1, -1); + BC_ASSERT_PTR_NOT_NULL_FATAL(pt); + linphone_core_enable_payload_type(lc, pt, TRUE); +} +#endif + +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,"\"t\x8et\x8e\" "); /*just to use non ascii values*/ + for(i=0;i<10;i++){ + ms_usleep(200000); + linphone_core_iterate(marie->lc); + } + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,1, int, "%d"); + 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); + + BC_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.*/ + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d"); + + BC_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*/ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + BC_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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d"); + + 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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCallLog* out_call_log; + LinphoneCall* out_call; + + linphone_core_set_max_calls(marie->lc,0); + out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + + /*wait until flexisip transfers the busy...*/ + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,33000)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1, int, "%d"); + /* FIXME http://git.linphone.org/mantis/view.php?id=757 + + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy, int, "%d"); + */ + if (ms_list_size(linphone_core_get_call_logs(pauline->lc))>0) { + BC_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(pauline->lc)->data)); + BC_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted, int, "%d"); + } + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_busy_when_calling_self(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCall *out_call=linphone_core_invite_address(marie->lc,marie->identity); + linphone_call_ref(out_call); + + /*wait until flexisip transfers the busy...*/ + BC_ASSERT_TRUE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1,33000)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1, int, "%d"); + + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy, int, "%d"); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); +} + + +static void call_declined(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + LinphoneCall* in_call; + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + BC_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); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined, int, "%d"); + 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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + BC_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + + BC_ASSERT_TRUE(call(marie,pauline)); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_ack_without_sdp(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *call; + + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + + linphone_core_invite_address(marie->lc,pauline->identity); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallIncomingReceived,1)); + call=linphone_core_get_current_call(pauline->lc); + if (call){ + sal_call_set_sdp_handling(call->op, SalOpSDPSimulateError); /*this will have the effect that the SDP received in the ACK will be ignored*/ + linphone_core_accept_call(pauline->lc, call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1)); + BC_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 audio_success=FALSE; + bool_t video_success=FALSE; + bool_t video_enabled; + MSTimeSpec ts; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + if (!c1 || !c2) return FALSE; + linphone_call_ref(c1); + linphone_call_ref(c2); + + BC_ASSERT_EQUAL(linphone_call_params_video_enabled(linphone_call_get_current_params(c1)),linphone_call_params_video_enabled(linphone_call_get_current_params(c2)), int, "%d"); + video_enabled=linphone_call_params_video_enabled(linphone_call_get_current_params(c1)); + liblinphone_tester_clock_start(&ts); + do{ + if ((c1 != NULL) && (c2 != NULL)) { + if (linphone_call_get_audio_stats(c1)->ice_state==state && + linphone_call_get_audio_stats(c2)->ice_state==state ){ + audio_success=TRUE; + break; + } + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); + } + ms_usleep(20000); + }while(!liblinphone_tester_clock_elapsed(&ts,10000)); + + if (video_enabled){ + liblinphone_tester_clock_start(&ts); + do{ + if ((c1 != NULL) && (c2 != NULL)) { + if (linphone_call_get_video_stats(c1)->ice_state==state && + linphone_call_get_video_stats(c2)->ice_state==state ){ + video_success=TRUE; + break; + } + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); + } + ms_usleep(20000); + }while(!liblinphone_tester_clock_elapsed(&ts,10000)); + } + + /*make sure encryption mode are preserved*/ + if (c1) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(c1); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc), int, "%d"); + } + if (c2) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(c2); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee->lc), int, "%d"); + } + linphone_call_unref(c1); + linphone_call_unref(c2); + return video_enabled ? audio_success && video_success : audio_success; +} + +static void _call_with_ice_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports) { + if (callee_with_ice){ + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + } + if (caller_with_ice){ + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + } + + if (random_ports){ + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + } + + + if (!BC_ASSERT_TRUE(call(pauline,marie))) + goto end; + + if (callee_with_ice && caller_with_ice) { + /*wait for the ICE reINVITE to complete*/ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + } + + liblinphone_tester_check_rtcp(marie,pauline); + /*then close the call*/ + linphone_core_terminate_all_calls(pauline->lc); +end: + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + +} +static void _call_with_ice(bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + _call_with_ice_base(pauline,marie,caller_with_ice,callee_with_ice,random_ports); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_with_ice(void){ + _call_with_ice(TRUE,TRUE,FALSE); +} + +/*ICE is not expected to work in this case, however this should not crash*/ +static void call_with_ice_no_sdp(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_enable_sdp_200_ack(pauline->lc,TRUE); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + + call(pauline,marie); + + liblinphone_tester_check_rtcp(marie,pauline); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_ice_random_ports(void){ + _call_with_ice(TRUE,TRUE,TRUE); +} + +static void ice_to_not_ice(void){ + _call_with_ice(TRUE,FALSE,FALSE); +} + +static void not_ice_to_ice(void){ + _call_with_ice(FALSE,TRUE,FALSE); +} + +static void call_with_custom_headers(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *call_marie,*call_pauline; + LinphoneCallParams *params; + const LinphoneCallParams *marie_remote_params; + const char *hvalue; + char *pauline_remote_contact_header, + *pauline_remote_contact, + *marie_remote_contact, + *marie_remote_contact_header; + LinphoneAddress* marie_identity; + char* tmp=linphone_address_as_string_uri_only(marie->identity); + char tmp2[256]; + snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); + 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"); + + BC_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + call_marie=linphone_core_get_current_call(marie->lc); + call_pauline=linphone_core_get_current_call(pauline->lc); + + BC_ASSERT_PTR_NOT_NULL(call_marie); + BC_ASSERT_PTR_NOT_NULL(call_pauline); + + marie_remote_params=linphone_call_get_remote_params(call_marie); + hvalue=linphone_call_params_get_custom_header(marie_remote_params,"Weather"); + BC_ASSERT_PTR_NOT_NULL(hvalue); + BC_ASSERT_STRING_EQUAL(hvalue,"bad"); + hvalue=linphone_call_params_get_custom_header(marie_remote_params,"uriHeader"); + BC_ASSERT_PTR_NOT_NULL(hvalue); + BC_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); + + + // FIXME: we have to strdup because successive calls to get_remote_params erase the returned const char*!! + pauline_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_pauline)); + pauline_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact")); + + marie_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_marie)); + marie_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_marie), "Contact")); + + BC_ASSERT_PTR_NOT_NULL(pauline_remote_contact); + BC_ASSERT_PTR_NOT_NULL(pauline_remote_contact_header); + BC_ASSERT_PTR_NOT_NULL(marie_remote_contact); + BC_ASSERT_PTR_NOT_NULL(marie_remote_contact_header); + BC_ASSERT_STRING_EQUAL(pauline_remote_contact,pauline_remote_contact_header); + BC_ASSERT_STRING_EQUAL(marie_remote_contact,marie_remote_contact_header); + + ms_free(pauline_remote_contact); + ms_free(pauline_remote_contact_header); + ms_free(marie_remote_contact); + ms_free(marie_remote_contact_header); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void call_paused_resumed_base(bool_t multicast) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline; + const rtp_stats_t * stats; + bool_t call_ok; + + linphone_core_enable_audio_multicast(pauline->lc,multicast); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (!call_ok) goto end; + + call_pauline = linphone_core_get_current_call(pauline->lc); + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_resume_call(pauline->lc,call_pauline); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_paused_resumed(void) { + call_paused_resumed_base(FALSE); +} + +static void call_paused_by_both() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline, *call_marie; + const rtp_stats_t * stats; + MSList *lcs = NULL; + bool_t call_ok; + + lcs = ms_list_append(lcs, pauline->lc); + lcs = ms_list_append(lcs, marie->lc); + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (!call_ok) goto end; + + call_pauline = linphone_core_get_current_call(pauline->lc); + call_marie = linphone_core_get_current_call(marie->lc); + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + /*marie pauses the call also*/ + linphone_core_pause_call(marie->lc, call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + /*pauline must stay in paused state*/ + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallPaused, 1, int, "%i"); + check_media_direction(pauline, call_pauline, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid); + check_media_direction(marie, call_marie, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid); + + + /*now pauline wants to resume*/ + linphone_core_resume_call(pauline->lc, call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallResuming,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + /*Marie must stay in paused state*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallPaused, 1, int, "%i"); + + /*now marie wants to resume also*/ + linphone_core_resume_call(marie->lc, call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallResuming,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + end_call(marie, pauline); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + +#define CHECK_CURRENT_LOSS_RATE() \ + rtcp_count_current = pauline->stat.number_of_rtcp_sent; \ + /*wait for an RTCP packet to have an accurate cumulative lost value*/ \ + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_rtcp_sent, rtcp_count_current+1, 10000)); \ + stats = rtp_session_get_stats(call_pauline->audiostream->ms.sessions.rtp_session); \ + loss_percentage = stats->cum_packet_loss * 100.f / (stats->packet_recv + stats->cum_packet_loss); \ + BC_ASSERT_LOWER(.75 * params.loss_rate , loss_percentage, float, "%f"); \ + BC_ASSERT_LOWER(loss_percentage , 1.25 * params.loss_rate, float, "%f") + +static void call_paused_resumed_with_loss(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline; + const rtp_stats_t * stats; + float loss_percentage; + int rtcp_count_current; + + OrtpNetworkSimulatorParams params={0}; + params.enabled=TRUE; + params.loss_rate=20; + + BC_ASSERT_TRUE(call(pauline,marie)); + call_pauline = linphone_core_get_current_call(pauline->lc); + if (call_pauline){ + rtp_session_enable_network_simulation(call_pauline->audiostream->ms.sessions.rtp_session,¶ms); + + /*generate some traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 6000); + CHECK_CURRENT_LOSS_RATE(); + + /*pause call*/ + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + CHECK_CURRENT_LOSS_RATE(); + + /*resume*/ + linphone_core_resume_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + wait_for_until(pauline->lc, marie->lc, NULL, 5, 6000); + + /*since stats are NOT totally reset during pause, the stats->packet_recv is computed from + the start of call. This test ensures that the loss rate is consistent during the entire call.*/ + CHECK_CURRENT_LOSS_RATE(); + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +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); + BC_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPausing,initial_call_stat_1.number_of_LinphoneCallPausing+1)); + BC_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPaused,initial_call_stat_1.number_of_LinphoneCallPaused+1)); + BC_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_2->stat.number_of_LinphoneCallPausedByRemote,initial_call_stat_2.number_of_LinphoneCallPausedByRemote+1)); + BC_ASSERT_EQUAL(linphone_call_get_state(call_1),LinphoneCallPaused, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_state(call_2),LinphoneCallPausedByRemote, int, "%d"); + return linphone_call_get_state(call_1) == LinphoneCallPaused && linphone_call_get_state(call_2)==LinphoneCallPausedByRemote; +} +#if 0 +void concurrent_paused_resumed_base() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline,call_marie; + const rtp_stats_t * stats; + + + BC_ASSERT_TRUE(call(pauline,marie)); + + call_pauline = linphone_core_get_current_call(pauline->lc); + call_marie = linphone_core_get_current_call(marie->lc); + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + + linphone_core_pause_call(marie->lc,call_marie); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_resume_call(pauline->lc,call_pauline); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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 +static void call_paused_resumed_from_callee(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_marie; + const rtp_stats_t * stats; + bool_t call_ok; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + call_marie = linphone_core_get_current_call(marie->lc); + + linphone_core_pause_call(marie->lc,call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_resume_call(marie->lc,call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_marie->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void audio_call_with_ice_no_matching_audio_codecs(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *out_call; + + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, 1), FALSE); /* Disable PCMU */ + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMA", 8000, 1), TRUE); /* Enable PCMA */ + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); + + out_call = linphone_core_invite_address(marie->lc, pauline->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingInit, 1)); + + /* flexisip will retain the 488 until the "urgent reply" timeout arrives. */ + BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallError, 1, 6000)); + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call), LinphoneReasonNotAcceptable, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#ifdef VIDEO_ENABLED +static LinphoneCall* setup_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bool_t change_video_policy) { + LinphoneVideoPolicy caller_policy; + LinphoneCallParams* callee_params; + LinphoneCall* call_obj; + + if (!linphone_core_get_current_call(callee->lc) || linphone_call_get_state(linphone_core_get_current_call(callee->lc)) != LinphoneCallStreamsRunning + || !linphone_core_get_current_call(caller->lc) || linphone_call_get_state(linphone_core_get_current_call(caller->lc)) != LinphoneCallStreamsRunning ) { + ms_warning("bad state for adding video"); + return NULL; + } + + if (change_video_policy) { + caller_policy.automatically_accept=TRUE; + caller_policy.automatically_initiate=TRUE; + linphone_core_set_video_policy(caller->lc,&caller_policy); + } + 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); + + if ((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); + } + return call_obj; +} + +bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bool_t change_video_policy) { + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + const LinphoneVideoPolicy *video_policy; + LinphoneCall *call_obj; + if ((call_obj=setup_video(caller, callee, change_video_policy))){ + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning+1)); + + video_policy = linphone_core_get_video_policy(caller->lc); + if (video_policy->automatically_accept) { + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + } else { + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + } + if (linphone_core_get_media_encryption(caller->lc) != LinphoneMediaEncryptionNone + && linphone_core_get_media_encryption(callee->lc) != LinphoneMediaEncryptionNone) { + const LinphoneCallParams* call_param; + + switch (linphone_core_get_media_encryption(caller->lc)) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + /*wait for encryption to be on, in case of zrtp/dtls, it can take a few seconds*/ + wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallEncryptedOn,initial_caller_stat.number_of_LinphoneCallEncryptedOn+1); + break; + case LinphoneMediaEncryptionNone: + case LinphoneMediaEncryptionSRTP: + break; + } + switch (linphone_core_get_media_encryption(callee->lc)) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallEncryptedOn,initial_callee_stat.number_of_LinphoneCallEncryptedOn+1); + break; + case LinphoneMediaEncryptionNone: + case LinphoneMediaEncryptionSRTP: + break; + } + + call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc), int, "%d"); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc), int, "%d"); + + } + + if (video_policy->automatically_accept) { + linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_iframe_decoded_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); + } else { + return TRUE; + } + } + return FALSE; +} + +static bool_t remove_video(LinphoneCoreManager *caller, LinphoneCoreManager *callee) { + LinphoneCallParams *callee_params; + LinphoneCall *call_obj; + stats initial_caller_stat = caller->stat; + stats initial_callee_stat = callee->stat; + + if (!linphone_core_get_current_call(callee->lc) + || (linphone_call_get_state(linphone_core_get_current_call(callee->lc)) != LinphoneCallStreamsRunning) + || !linphone_core_get_current_call(caller->lc) + || (linphone_call_get_state(linphone_core_get_current_call(caller->lc)) != LinphoneCallStreamsRunning)) { + ms_warning("bad state for removing video"); + return FALSE; + } + + if ((call_obj = linphone_core_get_current_call(callee->lc))) { + callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); + + /* Remove video. */ + linphone_call_params_enable_video(callee_params, FALSE); + linphone_core_update_call(callee->lc, call_obj, callee_params); + + BC_ASSERT_TRUE(wait_for(caller->lc, callee->lc, &caller->stat.number_of_LinphoneCallUpdatedByRemote, initial_caller_stat.number_of_LinphoneCallUpdatedByRemote + 1)); + BC_ASSERT_TRUE(wait_for(caller->lc, callee->lc, &callee->stat.number_of_LinphoneCallUpdating, initial_callee_stat.number_of_LinphoneCallUpdating + 1)); + BC_ASSERT_TRUE(wait_for(caller->lc, callee->lc, &callee->stat.number_of_LinphoneCallStreamsRunning, initial_callee_stat.number_of_LinphoneCallStreamsRunning + 1)); + BC_ASSERT_TRUE(wait_for(caller->lc, callee->lc, &caller->stat.number_of_LinphoneCallStreamsRunning, initial_caller_stat.number_of_LinphoneCallStreamsRunning + 1)); + + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + + return TRUE; + } + return FALSE; +} + +static void call_with_video_added(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_video_added_2(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + /*in this variant marie is already in automatically accept*/ + LinphoneVideoPolicy marie_policy; + marie_policy.automatically_accept=TRUE; + + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + + BC_ASSERT_TRUE(add_video(marie,pauline, TRUE)); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_video_added_random_ports(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_several_video_switches(void) { + int dummy = 0; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + + if (!call_ok) goto end; + + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + wait_for_until(pauline->lc,marie->lc,&dummy,1,1000); /* Wait for VFU request exchanges to be finished. */ + BC_ASSERT_TRUE(remove_video(pauline,marie)); + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + wait_for_until(pauline->lc,marie->lc,&dummy,1,1000); /* Wait for VFU request exchanges to be finished. */ + BC_ASSERT_TRUE(remove_video(pauline,marie)); + /**/ + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void srtp_call_with_several_video_switches(void) { + int dummy = 0; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + + 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); + + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + wait_for_until(pauline->lc,marie->lc,&dummy,1,1000); /* Wait for VFU request exchanges to be finished. */ + BC_ASSERT_TRUE(remove_video(pauline,marie)); + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + wait_for_until(pauline->lc,marie->lc,&dummy,1,1000); /* Wait for VFU request exchanges to be finished. */ + BC_ASSERT_TRUE(remove_video(pauline,marie)); + /**/ + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning("Not tested because SRTP is not available."); + } +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_declined_video_base(bool_t using_policy) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + LinphoneVideoPolicy marie_policy, pauline_policy; + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + bool_t call_ok; + + 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); + + if (using_policy) { + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=FALSE; + marie_policy.automatically_initiate=FALSE; + marie_policy.automatically_accept=FALSE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + } + + caller_test_params.base=linphone_core_create_default_call_parameters(pauline->lc); + if (!using_policy) + linphone_call_params_enable_video(caller_test_params.base,TRUE); + + if (!using_policy){ + callee_test_params.base=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(callee_test_params.base,FALSE); + } + + BC_ASSERT_TRUE((call_ok=call_with_params2(pauline,marie,&caller_test_params,&callee_test_params,using_policy))); + if (!call_ok) goto end; + + linphone_call_params_destroy(caller_test_params.base); + if (callee_test_params.base) linphone_call_params_destroy(callee_test_params.base); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + BC_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + BC_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_with_declined_video(void) { + call_with_declined_video_base(FALSE); +} +static void call_with_declined_video_using_policy(void) { + call_with_declined_video_base(TRUE); +} + +void video_call_base_2(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy,LinphoneMediaEncryption mode, bool_t callee_video_enabled, bool_t caller_video_enabled) { + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + LinphoneVideoPolicy marie_policy, pauline_policy; + + 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); + + if (using_policy) { + marie_policy.automatically_initiate=FALSE; + marie_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=FALSE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + } + if (callee_video_enabled) { + linphone_core_enable_video_display(marie->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + } else { + linphone_core_enable_video_display(marie->lc, FALSE); + linphone_core_enable_video_capture(marie->lc, FALSE); + } + if (caller_video_enabled) { + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + } else { + linphone_core_enable_video_display(pauline->lc, FALSE); + linphone_core_enable_video_capture(pauline->lc, FALSE); + } + + if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ + marie->lc->user_certificates_path = bc_tester_file("certificates-marie"); + pauline->lc->user_certificates_path = bc_tester_file("certificates-pauline"); + belle_sip_mkdir(marie->lc->user_certificates_path); + belle_sip_mkdir(pauline->lc->user_certificates_path); + } + + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); + + caller_test_params.base=linphone_core_create_default_call_parameters(pauline->lc); + if (!using_policy) + linphone_call_params_enable_video(caller_test_params.base,TRUE); + + if (!using_policy){ + callee_test_params.base=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(callee_test_params.base,TRUE); + } + + BC_ASSERT_TRUE(call_with_params2(pauline,marie,&caller_test_params,&callee_test_params,using_policy)); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + linphone_call_params_destroy(caller_test_params.base); + if (callee_test_params.base) linphone_call_params_destroy(callee_test_params.base); + + if (marie_call && pauline_call ) { + if (callee_video_enabled && caller_video_enabled) { + BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + BC_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_iframe_decoded_cb,marie->lc); + linphone_call_send_vfu_request(marie_call); + BC_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + } else { + BC_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + BC_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + } + + liblinphone_tester_check_rtcp(marie,pauline); + + } + +} +static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy,LinphoneMediaEncryption mode, bool_t callee_video_enabled, bool_t caller_video_enabled) { + video_call_base_2(pauline,marie,using_policy,mode,callee_video_enabled,caller_video_enabled); + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +} +static void video_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionNone,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_zrtp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionZRTP)) { + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionZRTP,TRUE,TRUE); + } else + ms_message("Skipping video_call_zrtp"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_dtls(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + if (linphone_core_media_encryption_supported(pauline->lc,LinphoneMediaEncryptionDTLS)) { + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionDTLS,TRUE,TRUE); + } else + ms_message("Skipping video_call_dtls"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + +static void video_call_using_policy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + video_call_base(marie,pauline,TRUE,LinphoneMediaEncryptionNone,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_using_policy_with_callee_video_disabled(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + video_call_base(marie,pauline,TRUE,LinphoneMediaEncryptionNone,FALSE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_using_policy_with_caller_video_disabled(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + video_call_base(marie,pauline,TRUE,LinphoneMediaEncryptionNone,TRUE,FALSE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_no_sdp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + linphone_core_enable_sdp_200_ack(pauline->lc,TRUE); + video_call_base(pauline,marie,FALSE,LinphoneMediaEncryptionNone,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_ice_video_to_novideo(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneVideoPolicy vpol={0}; + vpol.automatically_initiate=TRUE; + linphone_core_set_video_policy(pauline->lc,&vpol); + vpol.automatically_initiate=FALSE; + linphone_core_set_video_policy(marie->lc,&vpol); + _call_with_ice_base(pauline,marie,TRUE,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVideoPolicy callee_policy, + bool_t video_added_by_caller, bool_t video_added_by_callee, bool_t video_removed_by_caller, bool_t video_removed_by_callee) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + + linphone_core_set_video_policy(pauline->lc, &caller_policy); + linphone_core_set_video_policy(marie->lc, &callee_policy); + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); + + linphone_core_set_audio_port(marie->lc, -1); + linphone_core_set_video_port(marie->lc, -1); + linphone_core_set_audio_port(pauline->lc, -1); + linphone_core_set_video_port(pauline->lc, -1); + + BC_ASSERT_TRUE(call_ok = call(pauline, marie)); + if (!call_ok) goto end; + BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); + + /* Wait for ICE reINVITEs to complete. */ + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2) + && wait_for(pauline->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); + + if (video_added_by_caller) { + BC_ASSERT_TRUE(add_video(marie, pauline, FALSE)); + } else if (video_added_by_callee) { + BC_ASSERT_TRUE(add_video(pauline, marie, FALSE)); + } + if (video_added_by_caller || video_added_by_callee) { + BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); + } + + if (video_removed_by_caller) { + BC_ASSERT_TRUE(remove_video(marie, pauline)); + } else if (video_removed_by_callee) { + BC_ASSERT_TRUE(remove_video(pauline, marie)); + } + if (video_removed_by_caller || video_removed_by_callee) { + BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); + } + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_ice_video_added(void) { + LinphoneVideoPolicy vpol = { TRUE, TRUE }; + _call_with_ice_video(vpol, vpol, TRUE, FALSE, TRUE, FALSE); +} + +static void call_with_ice_video_added_2(void) { + LinphoneVideoPolicy vpol = { TRUE, TRUE }; + _call_with_ice_video(vpol, vpol, TRUE, FALSE, FALSE, TRUE); +} + +static void call_with_ice_video_added_3(void) { + LinphoneVideoPolicy vpol = { TRUE, TRUE }; + _call_with_ice_video(vpol, vpol, FALSE, TRUE, TRUE, FALSE); +} + +static void call_with_ice_video_added_and_refused(void) { + LinphoneVideoPolicy caller_policy = { TRUE, TRUE }; + LinphoneVideoPolicy callee_policy = { FALSE, FALSE }; + _call_with_ice_video(caller_policy, callee_policy, TRUE, FALSE, FALSE, FALSE); +} + + +static void video_call_with_early_media_no_matching_audio_codecs(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *out_call, *pauline_call; + LinphoneVideoPolicy vpol={0}; + + 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); + + vpol.automatically_initiate=TRUE; + vpol.automatically_accept=TRUE; + linphone_core_set_video_policy(pauline->lc,&vpol); + linphone_core_set_video_policy(marie->lc,&vpol); + + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, 1), FALSE); /* Disable PCMU */ + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMA", 8000, 1), TRUE); /* Enable PCMA */ + + out_call = linphone_core_invite_address(marie->lc, pauline->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingInit, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1)); + + pauline_call = linphone_core_get_current_call(pauline->lc); + if (!pauline_call) goto end; + + linphone_core_accept_early_media(pauline->lc, pauline_call); + + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1)); + /*audio stream shall not have been requested to start*/ + BC_ASSERT_PTR_NULL(pauline_call->audiostream->soundread); + + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(out_call))); + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(pauline_call))); + + linphone_core_accept_call(pauline->lc, pauline_call); + + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + + linphone_core_terminate_call(marie->lc, out_call); + + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + +end: + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_limited_bandwidth(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_set_download_bandwidth(pauline->lc, 100); + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionNone,TRUE,TRUE); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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(bool_t random_ports) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok; + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + if (random_ports){ + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + } + + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + liblinphone_tester_check_rtcp(pauline,marie); + +#ifdef VIDEO_ENABLED + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + liblinphone_tester_check_rtcp(pauline,marie); +#endif + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_media_relay(void) { + _call_with_media_relay(FALSE); +} + +static void call_with_media_relay_random_ports(void) { + _call_with_media_relay(TRUE); +} + +static void call_with_privacy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_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); + + BC_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); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + if (c1 && c2){ + /*make sure local identity is unchanged*/ + BC_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*/ + BC_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId, int, "%d"); + } + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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); + + BC_ASSERT_TRUE(call(pauline,marie)); + + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + if (c1 && c2){ + + /*make sure remote identity is hidden*/ + BC_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId, int, "%d"); + } + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,2)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +/*this ones makes call with privacy without previous registration*/ +static void call_with_privacy2(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new2(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", FALSE); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + LinphoneProxyConfig* pauline_proxy; + params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_set_privacy(params,LinphonePrivacyId); + + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_edit(pauline_proxy); + linphone_proxy_config_enable_register(pauline_proxy,FALSE); + linphone_proxy_config_done(pauline_proxy); + + BC_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); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + + if (c1 && c2){ + /*make sure local identity is unchanged*/ + BC_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*/ + BC_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId, int, "%d"); + } + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + /*test proxy config privacy*/ + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + BC_ASSERT_TRUE(call(pauline,marie)); + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + + if (c1 && c2){ + /*make sure remote identity is hidden*/ + BC_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId, int, "%d"); + } + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); + BC_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 srtp_call() { + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void zrtp_call() { + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void zrtp_sas_call() { + call_base_with_configfile(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE, "marie_zrtp_b256_rc", "pauline_zrtp_b256_rc"); + call_base_with_configfile(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE, "marie_zrtp_b256_rc", "pauline_tcp_rc"); +} + +static void zrtp_cipher_call() { + call_base_with_configfile(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE, "marie_zrtp_srtpsuite_aes256_rc", "pauline_zrtp_srtpsuite_aes256_rc"); + call_base_with_configfile(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE, "marie_zrtp_aes256_rc", "pauline_zrtp_aes256_rc"); + call_base_with_configfile(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE, "marie_zrtp_aes256_rc", "pauline_tcp_rc"); +} + +static void zrtp_video_call() { + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_call() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_call_with_media_realy() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,TRUE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_ice_call() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyUseIce,FALSE); +} +#ifdef VIDEO_ENABLED +static void dtls_srtp_video_call() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + +static void dtls_srtp_ice_video_call() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,FALSE); +} +static void dtls_srtp_ice_video_call_with_relay() { + call_base(LinphoneMediaEncryptionDTLS,TRUE,TRUE,LinphonePolicyUseIce,FALSE); +} +#endif +static void call_with_declined_srtp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + BC_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_srtp_paused_and_resumed(void) { + /* + * This test was made to evidence a bug due to internal usage of current_params while not yet filled by linphone_call_get_current_params(). + * As a result it must not use the call() function because it calls linphone_call_get_current_params(). + */ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + const LinphoneCallParams *params; + LinphoneCall *pauline_call; + + if (!linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) goto end; + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + linphone_core_invite_address(pauline->lc, marie->identity); + + if (!BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1))) goto end; + pauline_call = linphone_core_get_current_call(pauline->lc); + linphone_core_accept_call(marie->lc, linphone_core_get_current_call(marie->lc)); + + if (!BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1))) goto end; + if (!BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1))) goto end; + + linphone_core_pause_call(pauline->lc, pauline_call); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + + linphone_core_resume_call(pauline->lc, pauline_call); + if (!BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2))) goto end; + if (!BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2))) goto end; + + /*assert that after pause and resume, SRTP is still being used*/ + params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(params) , LinphoneMediaEncryptionSRTP, int, "%d"); + params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(params) , LinphoneMediaEncryptionSRTP, int, "%d"); + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void on_eof(LinphonePlayer *player, void *user_data){ + LinphoneCoreManager *marie=(LinphoneCoreManager*)user_data; + marie->stat.number_of_player_eof++; +} + +static void call_with_file_player(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphonePlayer *player; + char *hellopath = bc_tester_res("sounds/ahbahouaismaisbon.wav"); + char *recordpath = create_filepath(bc_tester_get_writable_dir_prefix(), "record-call_with_file_player", "wav"); + bool_t call_ok; + int attempts; + double similar=1; + const double threshold = 0.9; + + /*this test is actually attempted three times in case of failure, because the audio comparison at the end is very sensitive to + * jitter buffer drifts, which sometimes happen if the machine is unable to run the test in good realtime conditions */ + for (attempts=0; attempts<3; attempts++){ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ + unlink(recordpath); + /*caller uses files instead of soundcard in order to avoid mixing soundcard input with file played using call's player*/ + linphone_core_use_files(marie->lc,TRUE); + linphone_core_set_play_file(marie->lc,NULL); + + /*callee is recording and plays file*/ + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(pauline->lc,NULL); + linphone_core_set_record_file(pauline->lc,recordpath); + + BC_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (!call_ok) goto end; + player=linphone_call_get_player(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_PTR_NOT_NULL(player); + if (player){ + BC_ASSERT_EQUAL(linphone_player_open(player,hellopath,on_eof,marie),0, int, "%d"); + BC_ASSERT_EQUAL(linphone_player_start(player),0, int, "%d"); + } + /* This assert should be modified to be at least as long as the WAV file */ + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,10000)); + /*wait one second more for transmission to be fully ended (transmission time + jitter buffer)*/ + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); + + end_call(marie, pauline); + /*cannot run on iphone simulator because locks main loop beyond permitted time (should run + on another thread) */ + BC_ASSERT_EQUAL(ms_audio_diff(hellopath,recordpath,&similar,audio_cmp_max_shift,NULL,NULL), 0, int, "%d"); + if (similar>=threshold) + break; + } + BC_ASSERT_GREATER(similar, threshold, double, "%g"); + BC_ASSERT_LOWER(similar, 1.0, double, "%g"); + if (similar >= threshold && similar <= 1.0) { + remove(recordpath); + } + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(recordpath); + ms_free(hellopath); +} + +static bool_t is_format_supported(LinphoneCore *lc, const char *fmt){ + const char **formats=linphone_core_get_supported_file_formats(lc); + for(;*formats!=NULL;++formats){ + if (strcasecmp(*formats,fmt)==0) return TRUE; + } + return FALSE; +} + +static void call_with_mkv_file_player(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphonePlayer *player; + char *hellomkv; + char *hellowav; + char *recordpath; + bool_t call_ok; +#if !defined(__arm__) && !defined(__arm64__) && !TARGET_IPHONE_SIMULATOR && !defined(ANDROID) + double similar; + const double threshold = 0.9; +#define DO_AUDIO_CMP +#endif + hellowav = bc_tester_res("sounds/hello8000_mkv_ref.wav"); + hellomkv = bc_tester_res("sounds/hello8000.mkv"); + + if (!is_format_supported(marie->lc,"mkv")){ + ms_warning("Test skipped, no mkv support."); + goto end; + } + recordpath = create_filepath(bc_tester_get_writable_dir_prefix(), "record-call_with_mkv_file_player", "wav"); + /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ + unlink(recordpath); + + + /*caller uses files instead of soundcard in order to avoid mixing soundcard input with file played using call's player*/ + linphone_core_use_files(marie->lc,TRUE); + linphone_core_set_play_file(marie->lc,NULL); + /*callee is recording and plays file*/ + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(pauline->lc,hellowav); /*just to send something but we are not testing what is sent by pauline*/ + linphone_core_set_record_file(pauline->lc,recordpath); + + BC_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (!call_ok) goto end; + player=linphone_call_get_player(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_PTR_NOT_NULL(player); + if (player){ + int res = linphone_player_open(player,hellomkv,on_eof,marie); + if(!ms_filter_codec_supported("opus")) { + BC_ASSERT_EQUAL(res, -1, int, "%d"); + goto end; + } + BC_ASSERT_EQUAL(res, 0, int, "%d"); + BC_ASSERT_EQUAL(linphone_player_start(player),0,int,"%d"); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,12000)); + linphone_player_close(player); + /*wait for one second more so that last RTP packets can arrive*/ + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); + } + end_call(marie, pauline); +#ifdef DO_AUDIO_CMP + BC_ASSERT_EQUAL(ms_audio_diff(hellowav,recordpath,&similar,audio_cmp_max_shift,NULL,NULL),0,int,"%d"); + BC_ASSERT_GREATER(similar,threshold,double,"%f"); + BC_ASSERT_LOWER(similar,1.0,double,"%f"); + if(similar>threshold && similar<=1.0) { + remove(recordpath); + } +#else + /*inter-correlation process is too much CPU consuming ending in a 20 minutes test on arm...*/ + remove(recordpath); +#endif + ms_free(recordpath); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(hellomkv); + ms_free(hellowav); +} + +void call_base_with_configfile(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel, const char *marie_rc, const char *pauline_rc) { + LinphoneCoreManager* marie = linphone_core_manager_new(marie_rc); + LinphoneCoreManager* pauline = linphone_core_manager_new(pauline_rc); + bool_t call_ok; + + if (enable_relay) { + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + } + if (enable_tunnel) { + int i; + LinphoneTunnelConfig * tunnel_config = linphone_tunnel_config_new(); + linphone_tunnel_config_set_host(tunnel_config,"tunnel.linphone.org"); + linphone_tunnel_config_set_port(tunnel_config,443); + linphone_tunnel_add_server(linphone_core_get_tunnel(marie->lc),tunnel_config); + linphone_tunnel_enable_sip(linphone_core_get_tunnel(marie->lc),FALSE); + linphone_tunnel_set_mode(linphone_core_get_tunnel(marie->lc),LinphoneTunnelModeEnable); + for (i=0;i<100;i++) { + if (linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))) { + break; + } + linphone_core_iterate(marie->lc); + ms_usleep(20000); + } + BC_ASSERT_TRUE(linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))); + + } + if (linphone_core_media_encryption_supported(marie->lc,mode)) { + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); + if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ + marie->lc->user_certificates_path = bc_tester_file("certificates-marie"); + pauline->lc->user_certificates_path = bc_tester_file("certificates-pauline"); + belle_sip_mkdir(marie->lc->user_certificates_path); + belle_sip_mkdir(pauline->lc->user_certificates_path); + } + + linphone_core_set_firewall_policy(marie->lc,policy); + linphone_core_set_firewall_policy(pauline->lc,policy); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP + && linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { + /*wait for SAS*/ + int i; + for (i=0;i<100;i++) { + if (linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) + && + linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))) { + /*check SAS*/ + BC_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) + ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); + liblinphone_tester_check_rtcp(pauline,marie); + break; + } + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + ms_usleep(20000); + } + + } + + if (policy == LinphonePolicyUseIce){ + BC_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); + wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000);/*fixme to workaround a crash*/ + } +#ifdef VIDEO_ENABLED + if (enable_video) { + if (linphone_core_video_supported(marie->lc)) { + add_video(pauline,marie, TRUE); + if (policy == LinphonePolicyUseIce) + BC_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); + + liblinphone_tester_check_rtcp(marie,pauline); + /*wait for ice to found the direct path*/ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); + } else { + ms_warning ("not tested because video not available"); + } + } +#endif + + + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because %s not available", linphone_media_encryption_to_string(mode)); + } +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel) { + call_base_with_configfile(mode, enable_video, enable_relay, policy, enable_tunnel, "marie_rc", "pauline_tcp_rc"); +} + +#ifdef VIDEO_ENABLED +static void srtp_video_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); +} +static void zrtp_video_ice_call(void) { + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); +} +#endif + +static void srtp_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); +} + +static void zrtp_ice_call(void) { + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); +} +static void zrtp_ice_call_with_relay(void) { + call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce,FALSE); +} + +static void dtls_ice_call_with_relay(void) { + call_base(LinphoneMediaEncryptionDTLS,FALSE,TRUE,LinphonePolicyUseIce,FALSE); +} + +static void early_media_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + BC_ASSERT_TRUE(call(pauline,marie)); + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1, int, "%d"); + + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); + + /*added because a bug related to early-media caused the Connected state to be reached two times*/ + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected,1, int, "%d"); + + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_with_ringing(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); + MSList* lcs = NULL; + LinphoneCall* marie_call; + LinphoneCallLog *marie_call_log; + uint64_t connected_time=0; + uint64_t ended_time=0; + int dummy=0; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + marie_call_log = linphone_call_get_call_log(marie_call); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + + if (linphone_core_inc_invite_pending(pauline->lc)) { + /* send a 183 to initiate the early media */ + + linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + liblinphone_tester_check_rtcp(marie, pauline); + + linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); + connected_time=ms_get_cur_time_ms(); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + BC_ASSERT_PTR_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, pauline); + /*just to have a call duration !=0*/ + wait_for_list(lcs,&dummy,1,2000); + + linphone_core_terminate_all_calls(pauline->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + ended_time=ms_get_cur_time_ms(); + BC_ASSERT_LOWER( labs((long)((linphone_call_log_get_duration(marie_call_log)*1000) - (int64_t)(ended_time - connected_time))), 1000, long, "%ld"); + ms_list_free(lcs); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void early_media_call_with_update_base(bool_t media_change){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + MSList* lcs = NULL; + LinphoneCall *marie_call, *pauline_call; + LinphoneCallParams *pauline_params; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + if (media_change) { + disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcmu",-1); + } + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,5000)); + + pauline_call = linphone_core_get_current_call(pauline->lc); + if (!pauline_call) goto end; + /* send a 183 to initiate the early media */ + linphone_core_accept_early_media(pauline->lc, pauline_call); + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,5000) ); + + + pauline_params = linphone_call_params_copy(linphone_call_get_current_params(pauline_call)); + + if (media_change) { + disable_all_audio_codecs_except_one(marie->lc,"pcma",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1); + } + #define UPDATED_SESSION_NAME "nouveau nom de session" + + linphone_call_params_set_session_name(pauline_params,UPDATED_SESSION_NAME); + linphone_core_update_call(pauline->lc, pauline_call, pauline_params); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEarlyUpdating,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEarlyUpdatedByRemote,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000)); + + /*just to wait 2s*/ + liblinphone_tester_check_rtcp(marie, pauline); + + BC_ASSERT_STRING_EQUAL( linphone_call_params_get_session_name(linphone_call_get_remote_params(marie_call)) + , UPDATED_SESSION_NAME); + + linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallConnected, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + liblinphone_tester_check_rtcp(marie, pauline); + + linphone_core_terminate_all_calls(pauline->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + +end: + + ms_list_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void early_media_call_with_session_update(void){ + early_media_call_with_update_base(FALSE); +} + +static void early_media_call_with_codec_update(void){ + early_media_call_with_update_base(TRUE); +} + + +static void check_call_state(LinphoneCoreManager* mgr,LinphoneCallState state) { + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(mgr->lc)); + if (linphone_core_get_current_call(mgr->lc)) + BC_ASSERT_EQUAL(linphone_call_get_state(linphone_core_get_current_call(mgr->lc)),state, int, "%d"); +} + +static void call_established_with_rejected_info(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + int dummy=0; + bool_t call_ok=FALSE; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (call_ok){ + + 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)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_inforeceived,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_inforeceived,1, int, "%d"); + + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_complex_rejected_operation(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=FALSE; + LinphoneCallParams *params; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (call_ok){ + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1)); + + 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_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + /*just to authenticate marie*/ + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_inforeceived,1, int, "%d"); + /*to give time for 200ok to arrive*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + + + 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))); + + + linphone_core_update_call( marie->lc + ,linphone_core_get_current_call(marie->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonTemporarilyUnavailable, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonTemporarilyUnavailable, int, "%d"); + + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + 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))); + + + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + + + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + sal_enable_pending_trans_checking(marie->lc->sal,FALSE); /*to allow // transactions*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),TRUE); + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),FALSE); + + linphone_core_update_call( marie->lc + ,linphone_core_get_current_call(marie->lc) + ,params); + + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3)); + + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonTemporarilyUnavailable, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonTemporarilyUnavailable, int, "%d"); + + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_info_during_reinvite(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=FALSE; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (call_ok){ + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1)); + + 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_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + /*just to authenticate marie*/ + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_inforeceived,1, int, "%d"); + /*to give time for 200ok to arrive*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + + //sal_enable_pending_trans_checking(marie->lc->sal,FALSE); /*to allow // transactions*/ + + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + + //sal_set_send_error(marie->lc->sal, -1); /*to avoid 491 pending to be sent*/ + + 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))); + + + + wait_for_until(pauline->lc,pauline->lc,NULL,0,2000); /*to avoid 491 pending to be sent to early*/ + + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=FALSE; + + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (call_ok){ + 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))); + + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNotAcceptable, int, "%d"); + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1, int, "%d"); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_incoming_reinvite(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=FALSE; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (call_ok){ + + /*wait for ACK to be transmitted before going to reINVITE*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + 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(marie->lc + ,linphone_core_get_current_call(marie->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); + + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(marie->lc)),LinphoneReasonNotAcceptable, int, "%d"); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallStreamsRunning,1, int, "%d"); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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_redirect(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new("laure_rc"); + MSList* lcs = NULL; + char *margaux_url = NULL; + LinphoneCall* marie_call; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + lcs = ms_list_append(lcs,laure->lc); + /* + Marie calls Pauline, which will redirect the call to Laure via a 302 + */ + + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,6000)); + + if (linphone_core_get_current_call(pauline->lc)){ + margaux_url = linphone_address_as_string(laure->identity); + linphone_core_redirect_call(pauline->lc, linphone_core_get_current_call(pauline->lc), margaux_url); + ms_free(margaux_url); + + /* laure should be ringing now */ + BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived,1,6000)); + /* pauline should have ended the call */ + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,1,1000)); + /* the call should still be ringing on marie's side */ + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1,1000)); + + linphone_core_accept_call(laure->lc, linphone_core_get_current_call(laure->lc)); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + BC_ASSERT_PTR_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, laure); + + linphone_core_terminate_all_calls(laure->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + } + + ms_list_free(lcs); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + +} + +static void call_established_with_rejected_reinvite_with_error_base(bool_t trans_pending) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=TRUE; + int result; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (call_ok){ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*add PCMA*/ + + if (trans_pending) { + LinphoneInfoMessage * info = linphone_core_create_info_message(pauline->lc); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),info); + + } else + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + + result = 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))); + + if (trans_pending) + BC_ASSERT_NOT_EQUAL(result,0, int, "%d"); + else + BC_ASSERT_EQUAL(result,0,int, "%d"); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + BC_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonTemporarilyUnavailable, int, "%d"); /*might be change later*/ + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1, int, "%d"); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + if (!trans_pending) + sal_enable_unconditional_answer(marie->lc->sal,FALSE); + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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) { + call_established_with_rejected_reinvite_with_error_base(FALSE); +} + +static void call_established_with_rejected_reinvite_with_trans_pending_error(void) { + call_established_with_rejected_reinvite_with_error_base(TRUE); +} + +static void call_rejected_because_wrong_credentials_with_params(const char* user_agent,bool_t enable_auth_req_cb) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone(linphone_core_find_auth_info(marie->lc,NULL,linphone_address_get_username(marie->identity),NULL)); + LinphoneAuthInfo* wrong_auth_info=linphone_auth_info_clone(good_auth_info); + bool_t result=FALSE; + linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout"); + linphone_core_clear_all_auth_info(marie->lc); + + if (user_agent) { + linphone_core_set_user_agent(marie->lc,user_agent,NULL); + } + if (!enable_auth_req_cb) { + ((VTableReference*)(marie->lc->vtable_refs->data))->vtable->auth_info_requested=NULL; + linphone_core_add_auth_info(marie->lc,wrong_auth_info); + } + + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,marie->identity)); + + result=wait_for(marie->lc,marie->lc,&marie->stat.number_of_auth_info_requested,1); + + if (enable_auth_req_cb) { + BC_ASSERT_TRUE(result); + /*automatically re-inititae the call*/ + linphone_core_add_auth_info(marie->lc,wrong_auth_info); + } + + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1)); + if (enable_auth_req_cb) { + BC_ASSERT_EQUAL(marie->stat.number_of_auth_info_requested,2, int, "%d"); + } + /*to make sure unregister will work*/ + linphone_core_clear_all_auth_info(marie->lc); + linphone_core_add_auth_info(marie->lc,good_auth_info); + linphone_auth_info_destroy(good_auth_info); + linphone_core_manager_destroy(marie); +} + +static void call_rejected_because_wrong_credentials() { + call_rejected_because_wrong_credentials_with_params(NULL,TRUE); +} + +static void call_rejected_without_403_because_wrong_credentials() { + call_rejected_because_wrong_credentials_with_params("tester-no-403",TRUE); +} + +static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb() { + call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE); +} + +#ifdef VIDEO_ENABLED +/*this is call forking with early media managed at client side (not by flexisip server)*/ +static void multiple_early_media(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_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; + LinphoneInfoMessage *info; + int dummy=0; + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + + linphone_core_enable_video(marie1->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie1->lc,&pol); + + 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); + + 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); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000)); + + 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); + + BC_ASSERT_PTR_NOT_NULL(pauline_call); + BC_ASSERT_PTR_NOT_NULL(marie1_call); + BC_ASSERT_PTR_NOT_NULL(marie2_call); + + if (pauline_call && marie1_call && marie2_call){ + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,6000); + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(pauline),70,int,"%i"); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); + BC_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)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + + /*marie2 should get her call terminated*/ + BC_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,3000); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + + /*send an INFO in reverse side to check that dialogs are properly established*/ + info=linphone_core_create_info_message(marie1->lc); + linphone_call_send_info_message(marie1_call,info); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_inforeceived,1,3000)); + } + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,3000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} +#endif + +void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir) { + BC_ASSERT_PTR_NOT_NULL(call); + if (call) { + const LinphoneCallParams *params = linphone_call_get_current_params(call); +#ifdef VIDEO_ENABLED + if (video_dir != LinphoneMediaDirectionInvalid){ + int current_recv_iframe = mgr->stat.number_of_IframeDecoded; + int expected_recv_iframe=0; + int dummy = 0; + + if (video_dir != LinphoneMediaDirectionInactive){ + BC_ASSERT_TRUE(linphone_call_params_video_enabled(params)); + } + BC_ASSERT_EQUAL(linphone_call_params_get_video_direction(params), video_dir, int, "%d"); + linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc); + linphone_call_send_vfu_request(call); + + + wait_for_list(lcs,&dummy,1,2000); /*on some device, it may take 3 to 4s to get audio from mic*/ + + switch (video_dir) { + case LinphoneMediaDirectionInactive: + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendOnly: + expected_recv_iframe = 0; + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5); + break; + case LinphoneMediaDirectionRecvOnly: + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendRecv: + expected_recv_iframe = 1; + break; + default: + break; + } + + BC_ASSERT_TRUE(wait_for_list(lcs, &mgr->stat.number_of_IframeDecoded,current_recv_iframe + expected_recv_iframe,3000)); + } +#endif + if (audio_dir != LinphoneMediaDirectionInvalid){ + BC_ASSERT_EQUAL(linphone_call_params_get_audio_direction(params), audio_dir, int, "%d"); + switch (audio_dir) { + case LinphoneMediaDirectionInactive: + BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendOnly: + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5); + if (audio_dir == LinphoneMediaDirectionSendOnly) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); + break; + case LinphoneMediaDirectionRecvOnly: + BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendRecv: + BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_download_bandwidth,70,4000)); + if (audio_dir == LinphoneMediaDirectionSendRecv) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); + break; + default: + break; + } + } + } + +} +#ifdef VIDEO_ENABLED +static void accept_call_in_send_only_base(LinphoneCoreManager* pauline, LinphoneCoreManager *marie, MSList *lcs) { +#define DEFAULT_WAIT_FOR 10000 + LinphoneCallParams *params; + LinphoneVideoPolicy pol; + LinphoneCall *call; + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + linphone_core_set_video_policy(pauline->lc,&pol); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); + + linphone_core_enable_video(marie->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie->lc,&pol); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); + + linphone_call_set_next_video_frame_decoded_callback(linphone_core_invite_address(pauline->lc,marie->identity) + ,linphone_call_iframe_decoded_cb + ,pauline->lc); + + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingReceived,1,DEFAULT_WAIT_FOR)); + + { + char* remote_uri = linphone_address_as_string_uri_only(pauline->identity); + call = linphone_core_find_call_from_uri(marie->lc,remote_uri); + ms_free(remote_uri); + } + + if (call) { + params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendOnly); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendOnly); + linphone_core_accept_call_with_params(marie->lc,call,params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning,1,DEFAULT_WAIT_FOR)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallPausedByRemote,1,DEFAULT_WAIT_FOR)); + + check_media_direction(marie,call,lcs,LinphoneMediaDirectionSendOnly,LinphoneMediaDirectionSendOnly); + } + + + call=linphone_core_get_current_call(pauline->lc); + if (call) { + check_media_direction(pauline,call,lcs,LinphoneMediaDirectionRecvOnly,LinphoneMediaDirectionRecvOnly); + } + +} +static void accept_call_in_send_base(bool_t caller_has_ice) { + int begin; + int leaked_objects; + LinphoneCoreManager *pauline, *marie; + MSList *lcs=NULL;; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + if (caller_has_ice) { + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + } + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + + accept_call_in_send_only_base(pauline,marie,lcs); + + + end_call(marie,pauline); + ms_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void accept_call_in_send_only(void) { + accept_call_in_send_base(FALSE); +} + +static void accept_call_in_send_only_with_ice(void) { + accept_call_in_send_base(TRUE); +} + +void two_accepted_call_in_send_only() { + int begin; + int leaked_objects; + LinphoneCoreManager *pauline, *marie, *laure; + MSList *lcs=NULL; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + laure = linphone_core_manager_new("laure_rc"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,laure->lc); + + accept_call_in_send_only_base(pauline,marie,lcs); + + + reset_counters(&marie->stat); + accept_call_in_send_only_base(laure,marie,lcs); + + end_call(marie,pauline); + end_call(laure,marie); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + + leaked_objects=belle_sip_object_get_object_count()-begin; + + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + +} +#endif + +static char *create_filepath(const char *dir, const char *filename, const char *ext) { + return ms_strdup_printf("%s/%s.%s",dir,filename,ext); +} + +static void record_call(const char *filename, bool_t enableVideo) { + LinphoneCoreManager *marie = NULL; + LinphoneCoreManager *pauline = NULL; + LinphoneCallParams *marieParams = NULL; + LinphoneCallParams *paulineParams = NULL; + LinphoneCall *callInst = NULL; + const char **formats, *format; + char *filepath; + int dummy=0, i; + bool_t call_succeeded = FALSE; + +#if defined(HAVE_OPENH264) && defined(ANDROID) + ms_init(); + libmsopenh264_init(); +#endif + + + marie = linphone_core_manager_new("marie_h264_rc"); + pauline = linphone_core_manager_new("pauline_h264_rc"); + marieParams = linphone_core_create_default_call_parameters(marie->lc); + paulineParams = linphone_core_create_default_call_parameters(pauline->lc); + +#ifdef VIDEO_ENABLED + if(enableVideo) { + if((linphone_core_find_payload_type(marie->lc, "H264", -1, -1) != NULL) + && (linphone_core_find_payload_type(pauline->lc, "H264", -1, -1) != NULL)) { + linphone_call_params_enable_video(marieParams, TRUE); + linphone_call_params_enable_video(paulineParams, TRUE); + disable_all_video_codecs_except_one(marie->lc, "H264"); + disable_all_video_codecs_except_one(pauline->lc, "H264"); + } else { + ms_warning("call_recording(): the H264 payload has not been found. Only sound will be recorded"); + } + } +#endif + + formats = linphone_core_get_supported_file_formats(marie->lc); + + for(i=0, format = formats[0]; format != NULL; i++, format = formats[i]) { + filepath = create_filepath(bc_tester_get_writable_dir_prefix(), filename, format); + remove(filepath); + linphone_call_params_set_record_file(marieParams, filepath); + BC_ASSERT_TRUE(call_succeeded = call_with_params(marie, pauline, marieParams, paulineParams)); + BC_ASSERT_PTR_NOT_NULL(callInst = linphone_core_get_current_call(marie->lc)); + if ((call_succeeded == TRUE) && (callInst != NULL)) { + ms_message("call_recording(): start recording into %s", filepath); + linphone_call_start_recording(callInst); + wait_for_until(marie->lc,pauline->lc,&dummy,1,5000); + linphone_call_stop_recording(callInst); + end_call(marie, pauline); + BC_ASSERT_EQUAL(access(filepath, F_OK), 0, int, "%d"); + } + remove(filepath); + ms_free(filepath); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +#if defined(HAVE_OPENH264) && defined(ANDROID) + ms_exit(); +#endif +} + +static void audio_call_recording_test(void) { + record_call("recording", FALSE); +} + +#ifdef VIDEO_ENABLED +static void video_call_recording_test(void) { + record_call("recording", TRUE); +} + +static void video_call_snapshot(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCallParams *marieParams = linphone_core_create_default_call_parameters(marie->lc); + LinphoneCallParams *paulineParams = linphone_core_create_default_call_parameters(pauline->lc); + LinphoneCall *callInst = NULL; + char *filename = create_filepath(bc_tester_get_writable_dir_prefix(), "snapshot", "jpeg"); + int dummy = 0; + bool_t call_succeeded = FALSE; + + 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); + linphone_call_params_enable_video(marieParams, TRUE); + linphone_call_params_enable_video(paulineParams, TRUE); + + BC_ASSERT_TRUE(call_succeeded = call_with_params(marie, pauline, marieParams, paulineParams)); + BC_ASSERT_PTR_NOT_NULL(callInst = linphone_core_get_current_call(marie->lc)); + if((call_succeeded == TRUE) && (callInst != NULL)) { + linphone_call_take_video_snapshot(callInst, filename); + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 5000); + BC_ASSERT_EQUAL(access(filename, F_OK), 0, int, "%d"); + remove(filename); + } + ms_free(filename); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#endif + +static void call_with_in_dialog_update(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCallParams *params; + bool_t call_ok; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + + liblinphone_tester_check_rtcp(marie,pauline); + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + params->no_user_consent=TRUE; + linphone_core_update_call(marie->lc,linphone_core_get_current_call(marie->lc),params); + linphone_call_params_destroy(params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + end_call(marie,pauline); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} +static void call_with_in_dialog_codec_change_base(bool_t no_sdp) { + int begin; + int leaked_objects; + int dummy=0; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCallParams *params; + bool_t call_ok; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + + liblinphone_tester_check_rtcp(marie,pauline); + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + + 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(marie->lc,linphone_core_find_payload_type(marie->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_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + if (no_sdp) { + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + } + linphone_core_update_call(marie->lc,linphone_core_get_current_call(marie->lc),params); + linphone_call_params_destroy(params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_STRING_EQUAL("PCMA",linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_codec(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))))); + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 5000); + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie),70,int,"%i"); + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(pauline),70,int,"%i"); + + end_call(marie,pauline); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} +static void call_with_in_dialog_codec_change(void) { + call_with_in_dialog_codec_change_base(FALSE); +} +static void call_with_in_dialog_codec_change_no_sdp(void) { + call_with_in_dialog_codec_change_base(TRUE); +} +static void call_with_custom_supported_tags(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + const LinphoneCallParams *remote_params; + const char *recv_supported; + bool_t call_ok; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_add_supported_tag(marie->lc,"pouet-tag"); + BC_ASSERT_TRUE(call_ok=call(pauline,marie)); + if (!call_ok) goto end; + liblinphone_tester_check_rtcp(marie,pauline); + remote_params=linphone_call_get_remote_params(linphone_core_get_current_call(pauline->lc)); + recv_supported=linphone_call_params_get_custom_header(remote_params,"supported"); + BC_ASSERT_PTR_NOT_NULL(recv_supported); + if (recv_supported){ + BC_ASSERT_PTR_NOT_NULL(strstr(recv_supported,"pouet-tag")); + } + end_call(marie,pauline); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void call_log_from_taken_from_p_asserted_id(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + const char* paulie_asserted_id ="\"Paupauche\" "; + LinphoneAddress *paulie_asserted_id_addr = linphone_address_new(paulie_asserted_id); + LpConfig *marie_lp; + bool_t call_ok; + + params=linphone_core_create_default_call_parameters(pauline->lc); + + linphone_call_params_add_custom_header(params,"P-Asserted-Identity",paulie_asserted_id); + /*fixme, should be able to add several time the same header linphone_call_params_add_custom_header(params,"P-Asserted-Identity","\"Paupauche\" ");*/ + + marie_lp = linphone_core_get_config(marie->lc); + lp_config_set_int(marie_lp,"sip","call_logs_use_asserted_id_instead_of_from",1); + + + BC_ASSERT_TRUE(call_ok=call_with_caller_params(pauline,marie,params)); + + if (!call_ok) goto end; + + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + BC_ASSERT_PTR_NOT_NULL(c1); + BC_ASSERT_PTR_NOT_NULL(c2); + + /*make sure remote identity is hidden*/ + BC_ASSERT_TRUE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),paulie_asserted_id_addr)); + + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); +end: + linphone_call_params_destroy(params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void incoming_invite_with_invalid_sdp() { + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + + callee_test_params.sdp_simulate_error = TRUE; + BC_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); + + BC_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); + BC_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallError,1, int, "%d"); + /*call will be drop before presented to the application, because it is invalid*/ + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallIncomingReceived,0, int, "%d"); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +} + +static void outgoing_invite_with_invalid_sdp() { + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCallTestParams caller_test_params = {0}, callee_test_params = {0}; + + caller_test_params.sdp_simulate_error = TRUE; + BC_ASSERT_FALSE(call_with_params2(caller,callee,&caller_test_params, &callee_test_params, FALSE)); + + BC_ASSERT_PTR_NULL(linphone_core_get_current_call(callee->lc)); + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallIncomingReceived,1, int, "%d"); + BC_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallError,1, int, "%d"); + // actually callee does not receive error, because it just get a BYE from the other part + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,0, int, "%d"); + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallEnd,1, int, "%d"); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +} + +static void incoming_reinvite_with_invalid_ack_sdp(){ +#ifdef VIDEO_ENABLED + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCall * inc_call; + BC_ASSERT_TRUE(call(caller,callee)); + inc_call = linphone_core_get_current_call(callee->lc); + + BC_ASSERT_PTR_NOT_NULL(inc_call); + if (inc_call) { + const LinphoneCallParams *caller_params; + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + sal_call_set_sdp_handling(inc_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + BC_ASSERT_PTR_NOT_NULL(setup_video(caller, callee, TRUE)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); + /*Basically the negotiation failed but since the call was already running, we expect it to restore to + the previous state so error stats should not be changed*/ + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,initial_callee_stat.number_of_LinphoneCallError, int, "%d"); + /*and remote should have received an update notification*/ + BC_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1, int, "%d"); + + + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + caller_params = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,(int*)&caller_params->has_video,FALSE)); + + sal_call_set_sdp_handling(inc_call->op, SalOpSDPNormal); + } + linphone_core_terminate_all_calls(caller->lc); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +#else + ms_warning("not tested because video not available"); +#endif +} + +static void outgoing_reinvite_with_invalid_ack_sdp() { +#ifdef VIDEO_ENABLED + LinphoneCoreManager* caller = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* callee = linphone_core_manager_new( "marie_rc"); + LinphoneCall * out_call; + BC_ASSERT_TRUE(call(caller,callee)); + out_call = linphone_core_get_current_call(caller->lc); + + BC_ASSERT_PTR_NOT_NULL(out_call); + if (out_call) { + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + sal_call_set_sdp_handling(out_call->op, SalOpSDPSimulateError); /* will force a parse error for the ACK SDP*/ + BC_ASSERT_PTR_NOT_NULL(setup_video(caller, callee, TRUE)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning)); + /*Basically the negotiation failed but since the call was already running, we expect it to restore to + the previous state so error stats should not be changed*/ + BC_ASSERT_EQUAL(callee->stat.number_of_LinphoneCallError,initial_callee_stat.number_of_LinphoneCallError, int, "%d"); + /*and remote should not have received any update notification*/ + BC_ASSERT_EQUAL(caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote, int, "%d"); + + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + + sal_call_set_sdp_handling(out_call->op, SalOpSDPNormal); + } + linphone_core_terminate_all_calls(caller->lc); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(callee); + linphone_core_manager_destroy(caller); +#else + ms_warning("not tested because video not available"); +#endif +} + + +static void call_with_paused_no_sdp_on_resume() { + int begin; + int leaked_objects; + int dummy=0; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall* call_marie = NULL; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + BC_ASSERT_TRUE(call(pauline,marie)); + liblinphone_tester_check_rtcp(marie,pauline); + + call_marie = linphone_core_get_current_call(marie->lc); + BC_ASSERT_PTR_NOT_NULL(call_marie); + if (!call_marie) goto end; + + ms_message("== Call is OK =="); + + /* the called party pause the call */ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + linphone_core_pause_call(marie->lc,call_marie); + ms_message("== Call pausing =="); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + ms_message("== Call paused, marie call: %p ==", call_marie); + + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + + linphone_core_resume_call(marie->lc,call_marie); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000); + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie),70,int,"%i"); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70); +end: + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void early_media_without_sdp_in_200_base( bool_t use_video, bool_t use_ice ){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + MSList* lcs = NULL; + LinphoneCall* marie_call; + LinphoneCallParams* params = NULL; + LinphoneCallLog *marie_call_log; + uint64_t connected_time=0; + uint64_t ended_time=0; + int dummy=0; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + if (use_ice){ + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + } + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + params = linphone_core_create_default_call_parameters(marie->lc); + + if( use_video){ + + linphone_call_params_enable_video(params, TRUE); + + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + } + + marie_call = linphone_core_invite_address_with_params(marie->lc, pauline->identity, params); + marie_call_log = linphone_call_get_call_log(marie_call); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + if (linphone_core_inc_invite_pending(pauline->lc)) { + LinphoneCall* pauline_call = linphone_core_get_current_call(pauline->lc); + + /* send a 183 to initiate the early media */ + linphone_core_accept_early_media(pauline->lc, pauline_call); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + liblinphone_tester_check_rtcp(marie, pauline); + + /* will send the 200OK _without_ SDP. We expect the early-media SDP to be used instead */ + sal_call_set_sdp_handling(pauline_call->op, SalOpSDPSimulateRemove); + linphone_core_accept_call(pauline->lc, pauline_call); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); + connected_time=ms_get_cur_time_ms(); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,3000)); + + BC_ASSERT_PTR_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, pauline); + /*just to have a call duration !=0*/ + wait_for_list(lcs,&dummy,1,2000); + + linphone_core_terminate_all_calls(pauline->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + ended_time=ms_get_cur_time_ms(); + BC_ASSERT_LOWER(labs((long)((linphone_call_log_get_duration(marie_call_log)*1000) - (int64_t)(ended_time - connected_time))), 1000, long, "%ld"); + ms_list_free(lcs); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_early_media_and_no_sdp_in_200_with_video(){ + early_media_without_sdp_in_200_base(TRUE, FALSE); +} + +static void call_with_early_media_and_no_sdp_in_200(){ + early_media_without_sdp_in_200_base(FALSE, FALSE); +} + +static void call_with_early_media_ice_and_no_sdp_in_200(){ + early_media_without_sdp_in_200_base(FALSE, TRUE); +} + +static void call_with_generic_cn(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall *pauline_call; + char *audio_file_with_silence=bc_tester_res("sounds/ahbahouaismaisbon.wav"); + char *recorded_file=bc_tester_file("result.wav"); + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + remove(recorded_file); + + linphone_core_use_files(marie->lc,TRUE); + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(marie->lc, audio_file_with_silence); + /*linphone_core_set_play_file(pauline->lc, NULL);*/ + linphone_core_set_record_file(pauline->lc, recorded_file); + linphone_core_enable_generic_confort_noise(marie->lc, TRUE); + linphone_core_enable_generic_confort_noise(pauline->lc, TRUE); + BC_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + const rtp_stats_t *rtps; + + wait_for_until(marie->lc, pauline->lc, NULL, 0, 8000); + rtps=rtp_session_get_stats(pauline_call->audiostream->ms.sessions.rtp_session); + BC_ASSERT_TRUE(rtps->packet_recv<=300 && rtps->packet_recv>=200); + } + end_call(marie,pauline); + + if (pauline_call){ + struct stat stbuf; + int err; + + err=stat(recorded_file,&stbuf); + BC_ASSERT_EQUAL(err, 0, int, "%d"); + if (err==0){ + BC_ASSERT_GREATER(stbuf.st_size,120000,int, "%d"); + } + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + ms_free(audio_file_with_silence); + ms_free(recorded_file); +} +void static call_state_changed_2(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + LCSipTransports sip_tr; + if (cstate==LinphoneCallReleased) { + /*to make sure transport is changed*/ + sip_tr.udp_port = 0; + sip_tr.tcp_port = 45876; + sip_tr.tls_port = 0; + + linphone_core_set_sip_transports(lc,&sip_tr); + } +} +void static call_state_changed_3(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ +/*just to check multi listener in such situation*/ + 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); + ms_message("Third call listener reports: %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); +} + + +static void call_with_transport_change_base(bool_t succesfull_call) { + int begin; + int leaked_objects; + LCSipTransports sip_tr; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCoreVTable * v_table; + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + v_table = linphone_core_v_table_new(); + v_table->call_state_changed=call_state_changed_2; + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + linphone_core_add_listener(marie->lc,v_table); + v_table = linphone_core_v_table_new(); + v_table->call_state_changed=call_state_changed_3; + linphone_core_add_listener(marie->lc,v_table); + + sip_tr.udp_port = 0; + sip_tr.tcp_port = 45875; + sip_tr.tls_port = 0; + linphone_core_set_sip_transports(marie->lc,&sip_tr); + if (succesfull_call) { + BC_ASSERT_TRUE(call(marie,pauline)); + linphone_core_terminate_all_calls(marie->lc); + } + else + linphone_core_invite(marie->lc,"nexiste_pas"); + + if (succesfull_call) + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + if (succesfull_call) { + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects,0,int,"%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + +} +static void call_with_transport_change_after_released(void) { + call_with_transport_change_base(TRUE); +} +static void unsucessfull_call_with_transport_change_after_released(void) { + call_with_transport_change_base(FALSE); +} +#ifdef VIDEO_ENABLED + +static void video_call_with_re_invite_inactive_followed_by_re_invite_base(LinphoneMediaEncryption mode, bool_t no_sdp) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCallParams *params; + const LinphoneCallParams *current_params; + MSList *lcs=NULL; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + linphone_core_set_avpf_mode(pauline->lc,TRUE); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); + linphone_core_set_avpf_mode(marie->lc,TRUE); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + + video_call_base_2(marie,pauline,TRUE,mode,TRUE,TRUE); + + if (linphone_core_get_current_call(marie->lc)) { + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive); + + linphone_core_update_call(marie->lc, linphone_core_get_current_call(marie->lc),params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + + check_media_direction(marie,linphone_core_get_current_call(marie->lc),lcs,LinphoneMediaDirectionInactive,LinphoneMediaDirectionInactive); + check_media_direction(pauline,linphone_core_get_current_call(pauline->lc), lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInactive); + + if (no_sdp) { + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + } + + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendRecv); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendRecv); + linphone_core_update_call(marie->lc,linphone_core_get_current_call(marie->lc),params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + check_media_direction(marie,linphone_core_get_current_call(marie->lc),lcs,LinphoneMediaDirectionSendRecv,LinphoneMediaDirectionSendRecv); + check_media_direction(pauline,linphone_core_get_current_call(pauline->lc),lcs,LinphoneMediaDirectionSendRecv,LinphoneMediaDirectionSendRecv); + + /*assert that after pause and resume, SRTP is still being used*/ + current_params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(current_params) , mode, int, "%d"); + current_params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(current_params) , mode, int, "%d"); + + } + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void video_call_with_re_invite_inactive_followed_by_re_invite() { + video_call_with_re_invite_inactive_followed_by_re_invite_base(LinphoneMediaEncryptionNone,FALSE); +} + +static void video_call_with_re_invite_inactive_followed_by_re_invite_no_sdp() { + video_call_with_re_invite_inactive_followed_by_re_invite_base(LinphoneMediaEncryptionNone, TRUE); +} +static void srtp_video_call_with_re_invite_inactive_followed_by_re_invite() { + if (ms_srtp_supported()) + video_call_with_re_invite_inactive_followed_by_re_invite_base(LinphoneMediaEncryptionSRTP,FALSE); + else + ms_message("srtp_video_call_with_re_invite_inactive_followed_by_re_invite skipped, missing srtp support"); +} +static void srtp_video_call_with_re_invite_inactive_followed_by_re_invite_no_sdp() { + if (ms_srtp_supported()) + video_call_with_re_invite_inactive_followed_by_re_invite_base(LinphoneMediaEncryptionSRTP, TRUE); + else + ms_message("srtp_video_call_with_re_invite_inactive_followed_by_re_invite_no_sdp skipped, missing srtp support"); +} +static void video_call_ice_params() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + video_call_base(marie,pauline,FALSE,LinphoneMediaEncryptionNone,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#endif + +static void completion_cb(void *user_data, int percentage){ + fprintf(stdout,"%i %% completed\r",percentage); + fflush(stdout); +} + +static void simple_stereo_call(const char *codec_name, int clock_rate, int bitrate_override, bool_t stereo) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + PayloadType *pt; + char *stereo_file = bc_tester_res("sounds/vrroom.wav"); + char *recordpath = bc_tester_file("stereo-record.wav"); + bool_t audio_cmp_failed = FALSE; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + /*make sure we have opus*/ + pt = linphone_core_find_payload_type(marie->lc, codec_name, clock_rate, 2); + if (!pt) { + ms_warning("%s not available, stereo with %s not tested.",codec_name, codec_name); + goto end; + } + if (stereo) payload_type_set_recv_fmtp(pt, "stereo=1;sprop-stereo=1"); + if (bitrate_override) linphone_core_set_payload_type_bitrate(marie->lc, pt, bitrate_override); + pt = linphone_core_find_payload_type(pauline->lc, codec_name, clock_rate, 2); + if (stereo) payload_type_set_recv_fmtp(pt, "stereo=1;sprop-stereo=1"); + if (bitrate_override) linphone_core_set_payload_type_bitrate(pauline->lc, pt, bitrate_override); + + disable_all_audio_codecs_except_one(marie->lc, codec_name, clock_rate); + disable_all_audio_codecs_except_one(pauline->lc, codec_name, clock_rate); + + linphone_core_set_use_files(marie->lc, TRUE); + linphone_core_set_play_file(marie->lc, stereo_file); + linphone_core_set_use_files(pauline->lc, TRUE); + linphone_core_set_record_file(pauline->lc, recordpath); + + /*stereo is supported only without volume control, echo canceller...*/ + lp_config_set_string(marie->lc->config,"sound","features","NONE"); + lp_config_set_string(pauline->lc->config,"sound","features","NONE"); + + if (!BC_ASSERT_TRUE(call(pauline,marie))) goto end; + wait_for_until(marie->lc, pauline->lc, NULL, 0, 6000); + end_call(pauline, marie); + + + if (clock_rate!=48000) { + ms_warning("Similarity checking not implemented for files not having the same sampling rate"); + }else{ +#if !defined(__arm__) && !defined(__arm64__) && !TARGET_IPHONE_SIMULATOR && !defined(ANDROID) + double similar; + double min_threshold = .7f; + double max_threshold = 1.f; + if (!stereo){ + /*when opus doesn't transmit stereo, the cross correlation is around 0.54 : as expected, it is not as good as in full stereo mode*/ + min_threshold = .4f; + max_threshold = .6f; + } + BC_ASSERT_EQUAL(ms_audio_diff(recordpath, stereo_file,&similar,audio_cmp_max_shift,completion_cb,NULL), 0, int, "%d"); + BC_ASSERT_GREATER(similar, min_threshold, double, "%g"); + BC_ASSERT_LOWER(similar, max_threshold, double, "%g"); + if (similarmax_threshold){ + audio_cmp_failed = TRUE; + } +#endif + } + if (!audio_cmp_failed) unlink(recordpath); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(stereo_file); + ms_free(recordpath); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void simple_stereo_call_l16(void){ + simple_stereo_call("L16", 44100, 0, TRUE); +} + +static void simple_stereo_call_opus(void){ + simple_stereo_call("opus", 48000, 150, TRUE); +} + +static void call_with_complex_late_offering(void){ + LinphoneCallParams *params; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline; + LinphoneCall* call_marie; + LinphoneVideoPolicy vpol = {TRUE, TRUE}; + bool_t call_ok; + + linphone_core_enable_video(pauline->lc, TRUE, TRUE); + linphone_core_enable_video(marie->lc, TRUE, TRUE); + linphone_core_set_video_policy(pauline->lc, &vpol); + linphone_core_set_video_policy(marie->lc, &vpol); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + + call_pauline = linphone_core_get_current_call(pauline->lc); + call_marie = linphone_core_get_current_call(marie->lc); + + //Invite inactive Audio/video (Marie pause Pauline) + ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive"); + params=linphone_core_create_call_params(marie->lc,call_marie); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive); + + linphone_core_update_call(marie->lc, call_marie ,params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + //Marie sends INVITE without SDP + ms_message("CONTEXT: Marie sends INVITE without SDP for setting streams in send-only mode"); + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + params=linphone_core_create_call_params(marie->lc,call_marie); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendOnly); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendOnly); + linphone_core_update_call(marie->lc, call_marie , params); + linphone_call_params_destroy(params); + + //Pauline OK with sendonly + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,2)); + + linphone_core_enable_sdp_200_ack(marie->lc,FALSE); + + //Pauline pause Marie + ms_message("CONTEXT: Pauline pauses the call"); + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + + //Pauline resume Marie + ms_message("CONTEXT: Pauline resumes the call"); + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + linphone_core_resume_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,4)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallResuming,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,3)); + + wait_for_until(pauline->lc, marie->lc, NULL, 0, 2000); + + //Marie invite inactive Audio/Video + ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive"); + params=linphone_core_create_call_params(marie->lc,call_marie); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive); + + linphone_core_update_call(marie->lc, call_marie,params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3)); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,4)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5)); + + //Marie sends INVITE without SDP + ms_message("CONTEXT: Marie sends INVITE without SDP in the purpose of re-enabling streams in sendrecv mode"); + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + params=linphone_core_create_call_params(marie->lc,call_marie); + linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendRecv); + linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendRecv); + linphone_core_update_call(marie->lc, call_marie,params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3)); + linphone_call_params_destroy(params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5)); + + linphone_core_enable_sdp_200_ack(marie->lc,FALSE); + + + end_call(marie,pauline); + +end: + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + +static void simple_mono_call_opus(void){ + /*actually a call where input/output is made with stereo but opus transmits everything as mono*/ + simple_stereo_call("opus", 48000, 150, FALSE); +} + +/* because SIP ALG (like in android phones) crash when seing a domain name in SDP, we prefer using SIP/TLS for both participants*/ +static void call_with_fqdn_in_sdp(void) { + bool_t tls_supported = transport_supported(LinphoneTransportTls); + LinphoneCoreManager* marie = linphone_core_manager_new(tls_supported ? "marie_sips_rc" : "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(tls_supported ? "pauline_rc" : "pauline_tcp_rc"); + LpConfig *lp; + bool_t call_ok; + + lp = linphone_core_get_config(marie->lc); + lp_config_set_string(lp,"rtp","bind_address","localhost"); + lp = linphone_core_get_config(pauline->lc); + lp_config_set_string(lp,"rtp","bind_address","localhost"); + + + BC_ASSERT_TRUE(call_ok=call(marie,pauline)); + if (!call_ok) goto end; + liblinphone_tester_check_rtcp(pauline,marie); + +#ifdef VIDEO_ENABLED + BC_ASSERT_TRUE(add_video(pauline,marie, TRUE)); + liblinphone_tester_check_rtcp(pauline,marie); +#endif + end_call(pauline, marie); +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_rtp_io_mode(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphonePlayer *player; + char *hellopath = bc_tester_res("sounds/ahbahouaismaisbon.wav"); + char *recordpath = create_filepath(bc_tester_get_writable_dir_prefix(), "record-call_with_rtp_io_mode", "wav"); + bool_t call_ok; + int attempts; + double similar=1; + const double threshold = 0.9; + + /*this test is actually attempted three times in case of failure, because the audio comparison at the end is very sensitive to + * jitter buffer drifts, which sometimes happen if the machine is unable to run the test in good realtime conditions */ + for (attempts=0; attempts<3; attempts++){ + /* Make sure that the record file doesn't already exists, otherwise this test will append new samples to it. */ + unlink(recordpath); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* The caller uses files instead of soundcard in order to avoid mixing soundcard input with file played using call's player. */ + linphone_core_use_files(marie->lc, TRUE); + linphone_core_set_play_file(marie->lc, NULL); + linphone_core_set_record_file(marie->lc, recordpath); + linphone_core_use_files(pauline->lc, FALSE); + + /* The callee uses the RTP IO mode with the PCMU codec to send back audio to the caller. */ + disable_all_audio_codecs_except_one(pauline->lc, "pcmu", -1); + lp_config_set_int(pauline->lc->config, "sound", "rtp_io", 1); + lp_config_set_string(pauline->lc->config, "sound", "rtp_local_addr", "127.0.0.1"); + lp_config_set_string(pauline->lc->config, "sound", "rtp_remote_addr", "127.0.0.1"); + lp_config_set_int(pauline->lc->config, "sound", "rtp_local_port", 17076); + lp_config_set_int(pauline->lc->config, "sound", "rtp_remote_port", 17076); + lp_config_set_string(pauline->lc->config, "sound", "rtp_map", "pcmu/8000/1"); + + BC_ASSERT_TRUE((call_ok = call(marie, pauline))); + if (!call_ok) goto end; + player = linphone_call_get_player(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_PTR_NOT_NULL(player); + if (player) { + BC_ASSERT_EQUAL(linphone_player_open(player, hellopath, on_eof, marie) , 0, int, "%d"); + BC_ASSERT_EQUAL(linphone_player_start(player) , 0, int, "%d"); + } + + /* This assert should be modified to be at least as long as the WAV file */ + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_player_eof, 1, 10000)); + /*wait for one second more so that last RTP packets can arrive*/ + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); + end_call(pauline,marie); + + BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, audio_cmp_max_shift, NULL, NULL), 0, int, "%d"); + if (similar>=threshold) break; + } + BC_ASSERT_GREATER(similar, threshold, double, "%g"); + BC_ASSERT_LOWER(similar, 1.0, double, "%g"); + if (similar >= threshold && similar <= 1.0) { + remove(recordpath); + } + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(recordpath); + ms_free(hellopath); +} + +static void generic_nack_received(const OrtpEventData *evd, stats *st) { + if (rtcp_is_RTPFB(evd->packet)) { + switch (rtcp_RTPFB_get_type(evd->packet)) { + case RTCP_RTPFB_NACK: + st->number_of_rtcp_generic_nack++; + break; + default: + break; + } + } +} + +static void call_with_generic_nack_rtcp_feedback(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LpConfig *lp; + LinphoneCall *call_marie; + bool_t call_ok; + OrtpNetworkSimulatorParams params = { 0 }; + + params.enabled = TRUE; + params.loss_rate = 10; + params.consecutive_loss_probability = 0.75; + params.mode = OrtpNetworkSimulatorOutbound; + linphone_core_set_avpf_mode(marie->lc, LinphoneAVPFEnabled); + linphone_core_set_avpf_mode(pauline->lc, LinphoneAVPFEnabled); + lp = linphone_core_get_config(pauline->lc); + lp_config_set_int(lp, "rtp", "rtcp_fb_generic_nack_enabled", 1); + + + BC_ASSERT_TRUE(call_ok = call(pauline, marie)); + if (!call_ok) goto end; + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + call_marie = linphone_core_get_current_call(marie->lc); + if (call_marie) { + rtp_session_enable_network_simulation(call_marie->audiostream->ms.sessions.rtp_session, ¶ms); + ortp_ev_dispatcher_connect(media_stream_get_event_dispatcher(&call_marie->audiostream->ms), + ORTP_EVENT_RTCP_PACKET_RECEIVED, RTCP_RTPFB, (OrtpEvDispatcherCb)generic_nack_received, &marie->stat); + } + + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &marie->stat.number_of_rtcp_generic_nack, 5, 5000)); + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +// This is a custom structure used for the tests using custom RTP transport modifier. +// It is only used to count the number of sent and received packets +typedef struct _RtpTransportModifierData { + uint64_t packetSentCount; + uint64_t packetReceivedCount; +} RtpTransportModifierData; + +const char *XOR_KEY = "BELLEDONNECOMMUNICATIONS"; + +// Callback called when a packet is on it's way to be sent +// This is where we can do some changes on it, like encrypt it +static int rtptm_on_send(RtpTransportModifier *rtptm, mblk_t *msg) { + RtpTransportModifierData *data = rtptm->data; + rtp_header_t *rtp = (rtp_header_t*)msg->b_rptr; + int i = 0; + unsigned char *src; + int size = 0; + + if (rtp->version == 0) { + // This is probably a STUN packet, so don't count it (oRTP won't) and don't encrypt it either + return msgdsize(msg); + } + + // Mediastream can create a mblk_t with only the RTP header and setting the b_cont pointer to the actual RTP content buffer + // In this scenario, the result of rtp_get_payload will be 0, and we won't be able to do our XOR encryption on the payload + // The call to msgpullup will trigger a memcpy of the header and the payload in the same buffer in the msg mblk_t + msgpullup(msg, -1); + // Now that the mblk_t buffer directly contains the header and the payload, we can get the size of the payload and a pointer to it's start (we don't encrypt the RTP header) + size = rtp_get_payload(msg, &src); + + // Just for fun, let's do a XOR encryption + for (i = 0; i < size; i++) { + src[i] ^= (unsigned char) XOR_KEY[i % strlen(XOR_KEY)]; + } + + data->packetSentCount += 1; + + /* /!\ DO NOT RETURN 0 or the packet will never leave /!\ */ + return msgdsize(msg); +} + +// Callback called when a packet is on it's way to be received +// This is where we can do some changes on it, like decrypt it +static int rtptm_on_receive(RtpTransportModifier *rtptm, mblk_t *msg) { + RtpTransportModifierData *data = rtptm->data; + rtp_header_t *rtp = (rtp_header_t*)msg->b_rptr; + int i = 0; + unsigned char *src; + int size = 0; + + if (rtp->version == 0) { + // This is probably a STUN packet, so don't count it (oRTP won't) and don't decrypt it either + return msgdsize(msg); + } + + // On the receiving side, there is no need for a msgpullup, the mblk_t contains the header and the payload in the same buffer + // We just ask for the size and a pointer to the payload buffer + size = rtp_get_payload(msg, &src); + + // Since we did a XOR encryption on the send side, we have to do it again to decrypt the payload + for (i = 0; i < size; i++) { + src[i] ^= (unsigned char) XOR_KEY[i % strlen(XOR_KEY)]; + } + + data->packetReceivedCount += 1; + + /* /!\ DO NOT RETURN 0 or the packet will be dropped /!\ */ + return msgdsize(msg); +} + +// This callback is called when the transport modifier is being destroyed +// It is a good place to free the resources allocated for the transport modifier +static void rtptm_destroy(RtpTransportModifier *rtptm) { + // Do nothing, we'll free it later because we need to access the RtpTransportModifierData structure after the call is ended +} + +// This is the callback called when the state of the call change +void static call_state_changed_4(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + int i = 0; + + // To add a custom RTP transport modifier, we have to do it before the call is running, but after the RTP session is created. + if (cstate == LinphoneCallIncomingReceived || cstate == LinphoneCallOutgoingProgress) { + RtpTransport *rtpt = NULL; + RtpTransportModifierData *data = ms_new0(RtpTransportModifierData, 1); + RtpTransportModifier *rtptm = ms_new0(RtpTransportModifier, 1); + rtptm->data = data; + rtptm->t_process_on_send = rtptm_on_send; + rtptm->t_process_on_receive = rtptm_on_receive; + rtptm->t_destroy = rtptm_destroy; + + // Here we iterate on each meta rtp transport available + for (i = 0; i < linphone_call_get_stream_count(call); i++) { + MSFormatType type; + + rtpt = linphone_call_get_meta_rtp_transport(call, i); + + // If we wanted, we also could get the RTCP meta transports like this: + // rtcpt = linphone_call_get_meta_rtcp_transport(call, i); + + // If you want to know which stream meta RTP transport is the current one, you can use + type = linphone_call_get_stream_type(call, i); + // Currently there is only MSAudio and MSVideo types, but this could change later + if (type == MSAudio) { + // And now we append our RTP transport modifier to the current list of modifiers + meta_rtp_transport_append_modifier(rtpt, rtptm); + } else if (type == MSVideo) { + // Because the call of this test is audio only, we don't have to append our modifier to the meta RTP transport from the video stream + } + + } + // We save the pointer to our RtpTransportModifier in the call user_data to be able to get to it later + call->user_data = rtptm; + } +} + +static void custom_rtp_modifier(bool_t pauseResumeTest, bool_t recordTest) { + // This will initialize two linphone core using information contained in the marie_rc and pauline_rc files and wait for them to be correctly registered + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline = NULL; + LinphoneCall* call_marie = NULL; + const rtp_stats_t * stats; + bool_t call_ok; + LinphoneCoreVTable * v_table; + RtpTransportModifier *rtptm_marie = NULL; + RtpTransportModifier *rtptm_pauline = NULL; + RtpTransportModifierData *data_marie = NULL; + RtpTransportModifierData *data_pauline = NULL; + // The following are only used for the record test + LinphonePlayer *player; + char *hellopath = bc_tester_res("sounds/ahbahouaismaisbon.wav"); // File to be played + char *recordpath = create_filepath(bc_tester_get_writable_dir_prefix(), "record-call_with_file_player", "wav"); // File to record the received sound + double similar = 1; // The factor of similarity between the played file and the one recorded + const double threshold = 0.9; // Minimum similarity value to consider the record file equal to the one sent + + // We create a new vtable to listen only to the call state changes, in order to plug our RTP Transport Modifier when the call will be established + v_table = linphone_core_v_table_new(); + v_table->call_state_changed = call_state_changed_4; + linphone_core_add_listener(pauline->lc,v_table); + v_table = linphone_core_v_table_new(); + v_table->call_state_changed = call_state_changed_4; + linphone_core_add_listener(marie->lc,v_table); + + if (recordTest) { // When we do the record test, we need a file player to play the content of a sound file + /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ + unlink(recordpath); + + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(pauline->lc,NULL); + linphone_core_set_record_file(pauline->lc,NULL); + + /*callee is recording and plays file*/ + linphone_core_use_files(marie->lc,TRUE); + linphone_core_set_play_file(marie->lc,NULL); + linphone_core_set_record_file(marie->lc,recordpath); + } + + // Now the the call should be running (call state StreamsRunning) + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (!call_ok) goto end; + + // Ref the call to keep the pointer valid even after the call is release + call_pauline = linphone_call_ref(linphone_core_get_current_call(pauline->lc)); + call_marie = linphone_call_ref(linphone_core_get_current_call(marie->lc)); + + // This is for the pause/resume test, we don't do it in the call record test to be able to check the recorded call matches the file played + if (pauseResumeTest) { + // This only wait for 3 seconds in order to generate traffic for the test + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallPausing, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallPausedByRemote, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallPaused, 1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_resume_call(pauline->lc,call_pauline); + + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); + + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + end_call(pauline, marie); + } else if (recordTest) { + player = linphone_call_get_player(call_pauline); + BC_ASSERT_PTR_NOT_NULL(player); + if (player) { + // This will ask pauline to play the file + BC_ASSERT_EQUAL(linphone_player_open(player, hellopath, on_eof, pauline),0, int, "%d"); + BC_ASSERT_EQUAL(linphone_player_start(player), 0, int, "%d"); + } + /* This assert should be modified to be at least as long as the WAV file */ + BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_player_eof, 1, 10000)); + /*wait one second more for transmission to be fully ended (transmission time + jitter buffer)*/ + wait_for_until(pauline->lc, marie->lc, NULL, 0, 1000); + + end_call(pauline, marie); + + // Now we compute a similarity factor between the original file and the one we recorded on the callee side + BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, audio_cmp_max_shift, NULL, NULL), 0, int, "%d"); + + BC_ASSERT_GREATER(similar, threshold, double, "%g"); + BC_ASSERT_LOWER(similar, 1.0, double, "%g"); + if (similar >= threshold && similar <= 1.0) { + // If the similarity value is between perfect (1) and our threshold (0.9), then we delete the file used for the record + remove(recordpath); + } + } else { + // This only wait for 3 seconds in order to generate traffic for the test + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + // We termine the call and check the stats to see if the call is correctly ended on both sides + end_call(pauline, marie); + } + + // Now we can go fetch our custom structure and check the number of packets sent/received is the same on both sides + rtptm_marie = (RtpTransportModifier *)call_marie->user_data; + rtptm_pauline = (RtpTransportModifier *)call_pauline->user_data; + data_marie = (RtpTransportModifierData *)rtptm_marie->data; + data_pauline = (RtpTransportModifierData *)rtptm_pauline->data; + + BC_ASSERT_PTR_NOT_NULL(data_marie); + BC_ASSERT_PTR_NOT_NULL(data_pauline); + ms_message("Marie sent %i RTP packets and received %i (through our modifier)", (int)data_marie->packetSentCount, (int)data_marie->packetReceivedCount); + ms_message("Pauline sent %i RTP packets and received %i (through our modifier)", (int)data_pauline->packetSentCount, (int)data_pauline->packetReceivedCount); + // There will be a few RTP packets sent on marie's side before the call is ended at pauline's request, so we need the threshold + BC_ASSERT_TRUE(data_marie->packetSentCount - data_pauline->packetReceivedCount < 50); + BC_ASSERT_TRUE(data_marie->packetReceivedCount == data_pauline->packetSentCount); + // At this point, we know each packet that has been processed in the send callback of our RTP modifier also go through the recv callback of the remote. + + // Now we want to ensure that all sent RTP packets actually go through our RTP transport modifier and thus no packet leave without being processed (by any operation we might want to do on it) + { + const LinphoneCallStats *marie_stats = linphone_call_get_audio_stats(call_marie); + const LinphoneCallStats *pauline_stats = linphone_call_get_audio_stats(call_pauline); + rtp_stats_t marie_rtp_stats = linphone_call_stats_get_rtp_stats(marie_stats); + rtp_stats_t pauline_rtp_stats = linphone_call_stats_get_rtp_stats(pauline_stats); + ms_message("Marie sent %i RTP packets and received %i (for real)", (int)marie_rtp_stats.packet_sent, (int)marie_rtp_stats.packet_recv); + ms_message("Pauline sent %i RTP packets and received %i (for real)", (int)pauline_rtp_stats.packet_sent, (int)pauline_rtp_stats.packet_recv); + BC_ASSERT_TRUE(data_marie->packetReceivedCount == marie_rtp_stats.packet_recv); + BC_ASSERT_TRUE(data_marie->packetSentCount == marie_rtp_stats.packet_sent); + BC_ASSERT_TRUE(data_pauline->packetReceivedCount == pauline_rtp_stats.packet_recv); + BC_ASSERT_TRUE(data_pauline->packetSentCount == pauline_rtp_stats.packet_sent); + } + +end: + // Since we didn't free the resources of our RTP transport modifier in the rtptm_destroy callback, we'll do it here + if (data_pauline) { + ms_free(data_pauline); + } + ms_free(rtptm_pauline); + if (data_marie) { + ms_free(data_marie); + } + ms_free(rtptm_marie); + + // Unref the previously ref calls + if (call_marie) { + linphone_call_unref(call_marie); + } + if (call_pauline) { + linphone_call_unref(call_pauline); + } + + // The test is finished, the linphone core are no longer needed, we can safely free them + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + ms_free(recordpath); + ms_free(hellopath); +} + +static void call_with_custom_rtp_modifier(void) { + custom_rtp_modifier(FALSE, FALSE); +} + +static void call_paused_resumed_with_custom_rtp_modifier(void) { + custom_rtp_modifier(TRUE, FALSE); +} + +static void call_record_with_custom_rtp_modifier(void) { + custom_rtp_modifier(FALSE, TRUE); +} + +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 busy when calling self", call_busy_when_calling_self}, + { "Simple call", simple_call }, + { "Call with timeouted bye", call_with_timeouted_bye }, + { "Direct call over IPv6", direct_call_over_ipv6}, + { "Outbound call with multiple proxy possible", call_outbound_with_multiple_proxy }, + { "Audio call recording", audio_call_recording_test }, +#if 0 /* not yet activated because not implemented */ + { "Multiple answers to a call", multiple_answers_call }, +#endif + { "Multiple answers to a call with media relay", multiple_answers_call_with_media_relay }, + { "Call with media relay", call_with_media_relay}, + { "Call with media relay (random ports)", call_with_media_relay_random_ports}, + { "Simple call compatibility mode", simple_call_compatibility_mode }, + { "Early-media call", early_media_call }, + { "Early-media call with ringing", early_media_call_with_ringing }, + { "Early-media call with updated media session", early_media_call_with_session_update}, + { "Early-media call with updated codec", early_media_call_with_codec_update}, + { "Call terminated by caller", call_terminated_by_caller }, + { "Call without SDP", call_with_no_sdp}, + { "Call without SDP and ACK without SDP", call_with_no_sdp_ack_without_sdp}, + { "Call paused resumed", call_paused_resumed }, + { "Call paused by both parties", call_paused_by_both }, + { "Call paused resumed with loss", call_paused_resumed_with_loss }, + { "Call paused resumed from callee", call_paused_resumed_from_callee }, + { "SRTP call", srtp_call }, + { "ZRTP call",zrtp_call}, + { "ZRTP SAS call",zrtp_sas_call}, + { "ZRTP Cipher call",zrtp_cipher_call}, + { "DTLS SRTP call",dtls_srtp_call}, + { "DTLS SRTP call with media relay", dtls_srtp_call_with_media_realy}, + { "ZRTP video call",zrtp_video_call}, + { "SRTP call with declined srtp", call_with_declined_srtp }, + { "SRTP call paused and resumed", call_srtp_paused_and_resumed }, + { "Call with file player", call_with_file_player}, + { "Call with mkv file player", call_with_mkv_file_player}, + { "Audio call with ICE no matching audio codecs", audio_call_with_ice_no_matching_audio_codecs }, +#ifdef VIDEO_ENABLED + { "Simple video call",video_call}, + { "Simple ZRTP video call",video_call_zrtp}, + { "Simple DTLS video call",video_call_dtls}, + { "Simple video call using policy",video_call_using_policy}, + { "Video call using policy with callee video disabled", video_call_using_policy_with_callee_video_disabled }, + { "Video call using policy with caller video disabled", video_call_using_policy_with_caller_video_disabled }, + { "Video call without SDP",video_call_no_sdp}, + { "SRTP ice video call", srtp_video_ice_call }, + { "ZRTP ice video call", zrtp_video_ice_call }, + { "Call with video added", call_with_video_added }, + { "Call with video added 2", call_with_video_added_2 }, + { "Call with video added (random ports)", call_with_video_added_random_ports }, + { "Call with several video switches", call_with_several_video_switches }, + { "SRTP call with several video switches", srtp_call_with_several_video_switches }, + { "Call with video declined", call_with_declined_video}, + { "Call with video declined using policy", call_with_declined_video_using_policy}, + { "Call with multiple early media", multiple_early_media }, + { "Call with ICE from video to non-video", call_with_ice_video_to_novideo}, + { "Call with ICE and video added", call_with_ice_video_added }, + { "Call with ICE and video added 2", call_with_ice_video_added_2 }, + { "Call with ICE and video added 3", call_with_ice_video_added_3 }, + { "Call with ICE and video added and refused", call_with_ice_video_added_and_refused }, + { "Video call with ICE accepted using call params",video_call_ice_params}, + { "Video call recording", video_call_recording_test }, + { "Snapshot", video_call_snapshot }, + { "Video call with early media and no matching audio codecs", video_call_with_early_media_no_matching_audio_codecs }, + { "DTLS SRTP video call",dtls_srtp_video_call}, + { "DTLS SRTP ice video call",dtls_srtp_ice_video_call}, + { "DTLS SRTP ice video call with relay",dtls_srtp_ice_video_call_with_relay}, + { "Video call with limited bandwidth", video_call_limited_bandwidth}, + { "Video call accepted in send only", accept_call_in_send_only}, + { "Video call accepted in send only with ice", accept_call_in_send_only_with_ice}, + { "2 Video call accepted in send only", two_accepted_call_in_send_only}, + { "Video call with re-invite(inactive) followed by re-invite", video_call_with_re_invite_inactive_followed_by_re_invite}, + { "Video call with re-invite(inactive) followed by re-invite(no sdp)", video_call_with_re_invite_inactive_followed_by_re_invite_no_sdp}, + { "SRTP Video call with re-invite(inactive) followed by re-invite", srtp_video_call_with_re_invite_inactive_followed_by_re_invite}, + { "SRTP Video call with re-invite(inactive) followed by re-invite(no sdp)", srtp_video_call_with_re_invite_inactive_followed_by_re_invite_no_sdp}, + #endif + { "SRTP ice call", srtp_ice_call }, + { "ZRTP ice call", zrtp_ice_call }, + { "ZRTP ice call with relay", zrtp_ice_call_with_relay}, + { "DTLS SRTP ice call",dtls_srtp_ice_call}, + { "DTLS ice call with relay", dtls_ice_call_with_relay}, + { "Call with privacy", call_with_privacy }, + { "Call with privacy 2", call_with_privacy2 }, + { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, + { "Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials}, + { "Call rejected without 403 because of wrong credential and no auth req cb", call_rejected_without_403_because_wrong_credentials_no_auth_req_cb}, + { "Call with ICE", call_with_ice }, + { "Call with ICE without SDP", call_with_ice_no_sdp }, + { "Call with ICE (random ports)", call_with_ice_random_ports }, + { "Call from ICE to not ICE",ice_to_not_ice}, + { "Call from not ICE to ICE",not_ice_to_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 incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, + { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, + { "Call established with rejected RE-INVITE with trans pending error", call_established_with_rejected_reinvite_with_trans_pending_error}, + { "Call established with complex rejected operation",call_established_with_complex_rejected_operation}, + { "Call established with rejected info during re-invite",call_established_with_rejected_info_during_reinvite}, + { "Call redirected by callee", call_redirect}, + { "Call with specified codec bitrate", call_with_specified_codec_bitrate}, + { "Call with in-dialog UPDATE request", call_with_in_dialog_update }, + { "Call with in-dialog codec change", call_with_in_dialog_codec_change }, + { "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp }, + { "Call with pause no SDP on resume", call_with_paused_no_sdp_on_resume }, + { "Call with early media and no SDP in 200 Ok", call_with_early_media_and_no_sdp_in_200 }, + { "Call with early media and no SDP in 200 Ok with video", call_with_early_media_and_no_sdp_in_200_with_video }, + { "Call with ICE and no SDP in 200 OK", call_with_early_media_ice_and_no_sdp_in_200}, + { "Call with custom supported tags", call_with_custom_supported_tags }, + { "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id}, + { "Incoming INVITE with invalid SDP",incoming_invite_with_invalid_sdp}, + { "Outgoing INVITE with invalid ACK SDP",outgoing_invite_with_invalid_sdp}, + { "Incoming REINVITE with invalid SDP in ACK",incoming_reinvite_with_invalid_ack_sdp}, + { "Outgoing REINVITE with invalid SDP in ACK",outgoing_reinvite_with_invalid_ack_sdp}, + { "Call with generic CN", call_with_generic_cn }, + { "Call with transport change after released", call_with_transport_change_after_released }, + { "Unsuccessful call with transport change after released",unsucessfull_call_with_transport_change_after_released}, + { "Simple stereo call with L16", simple_stereo_call_l16 }, + { "Simple stereo call with opus", simple_stereo_call_opus }, + { "Simple mono call with opus", simple_mono_call_opus }, + { "Call with FQDN in SDP", call_with_fqdn_in_sdp}, + { "Call with RTP IO mode", call_with_rtp_io_mode }, + { "Call with generic NACK RTCP feedback", call_with_generic_nack_rtcp_feedback }, + { "Call with complex late offering", call_with_complex_late_offering }, + { "Call with custom RTP Modifier", call_with_custom_rtp_modifier }, + { "Call paused resumed with custom RTP Modifier", call_paused_resumed_with_custom_rtp_modifier }, + { "Call record with custom RTP Modifier", call_record_with_custom_rtp_modifier } +}; + +test_suite_t call_test_suite = { + "Single Call", + liblinphone_tester_setup, + 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..edb7c9fa1 --- /dev/null +++ b/tester/certificates/altname/agent.pem @@ -0,0 +1,75 @@ +-----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: 9 (0x9) + 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 25 16:12:35 2014 GMT + Not After : Sep 22 16:12:35 2024 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/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 + 56:f5:23:64:4c:8d:85:6e:05:d6:42:a3:41:b2:6a:ab:a1:cd: + be:ae:4a:38:c5:23:4c:62:2c:06:4d:49:b7:fc:ad:86:1d:9b: + c0:7e:33:80:fa:7d:31:8b:ca:9c:28:44:b2:1c:f1:ed:73:5b: + d3:80:72:b0:6c:0b:20:2b:e5:2b:02:c6:be:14:ad:55:34:2f: + 6f:8e:bb:7b:61:ce:9c:af:85:a7:b0:cd:d1:4e:1e:17:e9:7e: + 61:ed:50:60:9a:de:d0:7a:6d:a5:ee:04:9a:5c:41:94:21:e5: + 05:61:a8:17:ab:eb:b4:cc:7f:90:9b:3a:0e:ca:31:fb:65:40: + 11:2d +-----BEGIN CERTIFICATE----- +MIIDPzCCAqigAwIBAgIBCTANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTQwOTI1MTYxMjM1WhcN +MjQwOTIyMTYxMjM1WjCBtzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh +dGlvbnMxDDAKBgNVBAsMA0xBQjEWMBQGA1UEAwwNSmVoYW4gTW9ubmllcjE6MDgG +CSqGSIb3DQEJARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRp +b25zLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx2Ru/IsJJMSXqt2T +7kMGPQ33XDQrx12slvuaeVVFC1edKISSrSSc4aecrKuFR+6v3ZjpzJ22EwAp6lUp +aYfPM0XUCXf4NIek+A8lmuScXvkdYcC1lX4Hkl7LQivJvUsMSqp6gOZj2cXwEV4N +6+F1pFCtgNZViFwpGVNzDA+CSeECAwEAAaNVMFMwCQYDVR0TBAIwADALBgNVHQ8E +BAMCBeAwOQYDVR0RBDIwMIIUYWx0bmFtZS5saW5waG9uZS5vcmeCGCoud2lsZGNh +cmQyLmxpbnBob25lLm9yZzANBgkqhkiG9w0BAQUFAAOBgQBW9SNkTI2FbgXWQqNB +smqroc2+rko4xSNMYiwGTUm3/K2GHZvAfjOA+n0xi8qcKESyHPHtc1vTgHKwbAsg +K+UrAsa+FK1VNC9vjrt7Yc6cr4WnsM3RTh4X6X5h7VBgmt7Qem2l7gSaXEGUIeUF +YagXq+u0zH+QmzoOyjH7ZUARLQ== +-----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..0dc82fbe7 --- /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 = . # 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..43437333b --- /dev/null +++ b/tester/certificates/cn/cafile.pem @@ -0,0 +1,46 @@ +-----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----- + +UTN USERFirst Hardware Root CA, used for *.linphone.org +============================== +-----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----- diff --git a/tester/certificates/cn/openssl-cn.cnf b/tester/certificates/cn/openssl-cn.cnf new file mode 100644 index 000000000..908f6ed4c --- /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 = . # 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/common/bc_completion b/tester/common/bc_completion new file mode 100644 index 000000000..c5bd543d2 --- /dev/null +++ b/tester/common/bc_completion @@ -0,0 +1,115 @@ +# Copyright (C) 2012 Belledonne Comunications, 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. + +# Created by Gautier Pelloux-Prayer on 2014/10/24. +# This script adds auto-completion for liblinphone_tester binary for Bash and +# Zsh. To use it, just type: `source liblinphone_completion`, then for each +# supported exectuable (see end of file), you will get auto-completions. +# To use it permanently, source this file in your .rc file (.bashrc or .zshrc). + +_liblinphone_complete() { + local completions command_requiring_argument prev_arg latest_arg available_tasks has_not_set_suite suite_name + + if [ -n "$BASH_VERSION" ]; then + set -- "${COMP_WORDS[@]}" #convert them to arguments (eg $1,$#,$@,etc.) + elif [ -n "$ZSH_VERSION" ]; then + local args + read -cA args #read list of arguments user entered + set -- "${args[@]}" #convert them to arguments (eg $1,$#,$@,etc.) + fi + #skip program name + program=$1 + shift + + # if user required help, do not complete anything + if ! grep -q -- "--help" <<< "$@"; then + # retrieve the last argument + latest_arg="" + prev_arg="" + latest_is_empty=0 + for arg in "$@"; do + if [ ! -z "$arg" ]; then + prev_arg="$latest_arg" + latest_arg="$arg" + else + latest_is_empty=1 + fi + done + + # get the tasks available, from --help + available_tasks="$($program 2>&1 --help | sed -nE "s/.*--([^ ]*).*/--\\1/p")" + + # these commands expect an argument + command_requiring_argument="$($program 2>&1 --help | sed -nE "s/.*--(.*) <.*/--\\1/p")" + + # remove all already provided tasks (it's useless to provide them twice) + if [[ ! -z "$@" ]]; then + current_tasks=$(echo $@ | grep -Eo -- "--([^ ])*" | tr '\n' '|' | sed 's/|/$|/g')--$ + if [ ! -z "$current_tasks" ]; then + available_tasks=$(echo "$available_tasks" | grep -vE -- "(${current_tasks})") + fi + fi + # remove --test option if --suite is not provided yet! + has_not_set_suite=$(grep -q -- "--suite" <<< "$@"; echo $?) + if [ $has_not_set_suite = 1 ]; then + available_tasks=$(echo "$available_tasks" | grep -v -- --test) + fi + + # if latest arg does not start with '--', it is a custom value + if [ $latest_is_empty = 0 ] && ! grep -q -- '^--' <<< "$latest_arg"; then + if [ "$prev_arg" = "--test" ] && [ $has_not_set_suite = 0 ]; then + suite_name=$(echo $@ | sed -nE 's/.*--suite ([^(--)]*) (--.*)$/\1/p' |sed "s@\\\\@@g") + completions="$($program --list-tests $suite_name)" + elif [ "$prev_arg" = "--suite" ] || [ "$prev_arg" = "--list-tests" ]; then + completions="$($program --list-suites)" + fi + elif [ "$latest_arg" = "--test" ]; then + # list available tests if --suite was provided + if [ $has_not_set_suite = 0 ]; then + suite_name=$(echo $@ | sed -nE 's/.*--suite ([^(--)]*) (--.*)/\1/p' |sed "s@\\\\@@g") + completions="$($program --list-tests $suite_name)" + fi + elif [ "$latest_arg" = "--suite" ] || [ "$latest_arg" = "--list-tests" ]; then + completions="$($program --list-suites)" + # we are waiting for a custom value, so do not hint anything + elif [[ ! -z "$latest_arg" ]] && grep -q -- "^$latest_arg$" <<< "$command_requiring_argument"; then + completions="" + else + completions="$available_tasks" + fi + fi + + if [ ! -z "$completions" ]; then + if [ -n "$BASH_VERSION" ]; then + IFS=$'\n' #if that even necessary? + COMPREPLY=($(compgen -W "${completions}" -- ${COMP_WORDS[COMP_CWORD]})) + elif [ -n "$ZSH_VERSION" ]; then + reply=( "${(ps:\n:)completions}" ) + fi + fi +} + +for tester in liblinphone_tester mediastreamer2_tester belle_sip_tester pcap_playback \ + bench mediastream msaudiocmp mtudiscover videodisplay linphone lpc2xml_test \ + lp-gen-wrappers xml2lpc_test; do + if [ -n "$BASH_VERSION" ]; then + complete -F _liblinphone_complete $tester + elif [ -n "$ZSH_VERSION" ]; then + compctl -K _liblinphone_complete $tester + else + echo "Your shell might be not supported! Only bash and zsh tested." + fi +done diff --git a/tester/common/bc_tester_utils.c b/tester/common/bc_tester_utils.c new file mode 100644 index 000000000..ba5e6b811 --- /dev/null +++ b/tester/common/bc_tester_utils.c @@ -0,0 +1,442 @@ +/* +tester - liblinphone test suite +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, see . +*/ + + +/* this must be provided at compile time*/ +#include BC_CONFIG_FILE + +#include "bc_tester_utils.h" + +#include +#include + +#include "CUnit/Basic.h" +#include "CUnit/Automated.h" +#ifdef _WIN32 +#if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP) +#define BC_TESTER_WINDOWS_DESKTOP 1 +#elif defined(WINAPI_FAMILY_PARTITION) +#if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define BC_TESTER_WINDOWS_DESKTOP 1 +#endif +#if defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +#define BC_TESTER_WINDOWS_PHONE 1 +#endif +#if defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define BC_TESTER_WINDOWS_UNIVERSAL 1 +#endif +#endif +#endif + + +static char *bc_tester_resource_dir_prefix = NULL; +static char *bc_tester_writable_dir_prefix = NULL; + +int bc_printf_verbosity_info; +int bc_printf_verbosity_error; + +static test_suite_t **test_suite = NULL; +static int nb_test_suites = 0; + +#ifdef HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +static unsigned char curses = 0; +#endif + +char* xml_file = "CUnitAutomated-Results.xml"; +int xml_enabled = 0; +char * suite_name; +char * test_name; +void (*tester_printf_va)(int level, const char *fmt, va_list args); + +void bc_tester_printf(int level, const char *fmt, ...) { + va_list args; + va_start (args, fmt); + tester_printf_va(level, fmt, args); + va_end (args); +} + +int bc_tester_run_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; +} + +const char * bc_tester_suite_name(int suite_index) { + if (suite_index >= nb_test_suites) return NULL; + return test_suite[suite_index]->name; +} + +int bc_tester_suite_index(const char *suite_name) { + int i; + + for (i = 0; i < 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; +} + +int bc_tester_nb_suites(void) { + return nb_test_suites; +} + +const char * bc_tester_test_name(const char *suite_name, int test_index) { + int suite_index = bc_tester_suite_index(suite_name); + if ((suite_index < 0) || (suite_index >= 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; +} + +int bc_tester_nb_tests(const char *suite_name) { + int i = bc_tester_suite_index(suite_name); + if (i < 0) return 0; + return test_suite[i]->nb_tests; +} + +void bc_tester_list_suites(void) { + int j; + for(j=0;jpName); +} + +static void suite_cleanup_failure_message_handler(const CU_pSuite pSuite) { + bc_tester_printf(bc_printf_verbosity_error,"Suite cleanup failed for [%s]", pSuite->pName); +} + +#ifdef HAVE_CU_GET_SUITE +static time_t suite_start_time = 0; +static void suite_start_message_handler(const CU_pSuite pSuite) { + bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] started\n", pSuite->pName); + suite_start_time = time(NULL); +} +static void suite_complete_message_handler(const CU_pSuite pSuite, const CU_pFailureRecord pFailure) { + bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] ended in %lu sec\n", pSuite->pName, time(NULL) - suite_start_time); +} + +static time_t test_start_time = 0; +static void test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite) { + bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] Test [%s] started", pSuite->pName,pTest->pName); + test_start_time = time(NULL); +} + +/*derivated from cunit*/ +static void test_complete_message_handler(const CU_pTest pTest, + const CU_pSuite pSuite, + const CU_pFailureRecord pFailureList) { + int i; + char result[2048]; + char buffer[2048]; + CU_pFailureRecord pFailure = pFailureList; + snprintf(result, sizeof(result), "Suite [%s] Test [%s] %s in %lu secs" + , pSuite->pName, pTest->pName, pFailure?"failed":"passed",(unsigned long)(time(NULL) - test_start_time)); + if (pFailure) { + for (i = 1 ; (NULL != pFailure) ; pFailure = pFailure->pNext, i++) { + snprintf(buffer, sizeof(buffer), "\n %d. %s:%u - %s", i, + (NULL != pFailure->strFileName) ? pFailure->strFileName : "", + pFailure->uiLineNumber, + (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); + strncat(result, buffer, strlen(buffer)); + } + } + bc_tester_printf(bc_printf_verbosity_info,"%s\n", result); +} +#endif + +int bc_tester_run_tests(const char *suite_name, const char *test_name) { + int i; + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + for (i = 0; i < nb_test_suites; i++) { + bc_tester_run_suite(test_suite[i]); + } +#ifdef HAVE_CU_GET_SUITE + CU_set_suite_start_handler(suite_start_message_handler); + CU_set_suite_complete_handler(suite_complete_message_handler); + CU_set_test_start_handler(test_start_message_handler); + CU_set_test_complete_handler(test_complete_message_handler); +#endif + CU_set_all_test_complete_handler(all_complete_message_handler); + CU_set_suite_init_failure_handler(suite_init_failure_message_handler); + CU_set_suite_cleanup_failure_handler(suite_cleanup_failure_message_handler); + + if( xml_enabled != 0 ){ + CU_automated_run_tests(); + } else { + +#ifndef HAVE_CU_GET_SUITE + if( suite_name ){ + bc_tester_printf(bc_printf_verbosity_info, "Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'", suite_name); + } +#else + if (suite_name){ + CU_pSuite suite; + suite=CU_get_suite(suite_name); + if (!suite) { + bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name); + bc_tester_list_suites(); + return -1; + } else if (test_name) { + CU_pTest test=CU_get_test_by_name(test_name, suite); + if (!test) { + bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name); + // do not use suite_name here, since this method is case sensitive + bc_tester_list_tests(suite->pName); + return -2; + } else { + CU_ErrorCode err= CU_run_test(suite, test); + if (err != CUE_SUCCESS) bc_tester_printf(bc_printf_verbosity_error, "CU_basic_run_test error %d", err); + } + } else { + CU_run_suite(suite); + } + } + else +#endif + { +#ifdef 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_run_all_tests(); + } + } + } + return CU_get_number_of_tests_failed()!=0; + +} + + +void bc_tester_helper(const char *name, const char* additionnal_helper) { + bc_tester_printf(bc_printf_verbosity_info,"%s --help\n" + "\t\t\t--list-suites\n" + "\t\t\t--list-tests \n" + "\t\t\t--suite \n" + "\t\t\t--test \n" +#ifdef HAVE_CU_CURSES + "\t\t\t--curses\n" +#endif + "\t\t\t--xml\n" + "\t\t\t--xml-file \n" + "And additionally:\n" + "%s" + , name + , additionnal_helper); +} + +void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args), int iverbosity_info, int iverbosity_error) { +#if defined(BC_TESTER_WINDOWS_PHONE) || defined(BC_TESTER_WINDOWS_UNIVERSAL) + bc_tester_set_resource_dir_prefix("Assets"); +#elif defined(__QNX__) + bc_tester_set_resource_dir_prefix("./app/native/assets/"); +#else + bc_tester_set_resource_dir_prefix("."); +#endif + +#ifdef ANDROID + bc_tester_set_writable_dir_prefix("/data/data/org.linphone.tester/cache"); +#elif defined(__QNX__) + bc_tester_set_writable_dir_prefix("./tmp"); +#else + bc_tester_set_writable_dir_prefix("."); +#endif + + tester_printf_va = ftester_printf; + bc_printf_verbosity_error = iverbosity_error; + bc_printf_verbosity_info = iverbosity_info; +} + +int bc_tester_parse_args(int argc, char **argv, int argid) +{ + int i = argid; + if (strcmp(argv[i],"--help")==0){ + return -1; + } else if (strcmp(argv[i],"--test")==0){ + CHECK_ARG("--test", ++i, argc); + test_name=argv[i]; + }else if (strcmp(argv[i],"--suite")==0){ + CHECK_ARG("--suite", ++i, argc); + suite_name=argv[i]; + } else if (strcmp(argv[i],"--list-suites")==0){ + bc_tester_list_suites(); + return 0; + } else if (strcmp(argv[i],"--list-tests")==0){ + CHECK_ARG("--list-tests", ++i, argc); + suite_name = argv[i]; + bc_tester_list_tests(suite_name); + return 0; + } else if (strcmp(argv[i], "--xml-file") == 0){ + CHECK_ARG("--xml-file", ++i, argc); + xml_file = argv[i]; + xml_enabled = 1; + } else if (strcmp(argv[i], "--xml") == 0){ + xml_enabled = 1; + }else { + bc_tester_printf(bc_printf_verbosity_error, "Unknown option \"%s\"\n", argv[i]); + return -1; + } + + if( xml_enabled && (suite_name || test_name) ){ + bc_tester_printf(bc_printf_verbosity_error, "Cannot use both XML and specific test suite\n"); + return -1; + } + + /* returns number of arguments read + 1 */ + return i - argid + 1; +} + +int bc_tester_start(void) { + int ret; + if( xml_enabled ){ + size_t size = strlen(xml_file) + strlen(".tmp") + 1; + char * xml_tmp_file = malloc(sizeof(char) * size); + snprintf(xml_tmp_file, size, "%s.tmp", xml_file); + CU_set_output_filename(xml_tmp_file); + free(xml_tmp_file); + } + + ret = bc_tester_run_tests(suite_name, test_name); + + return ret; +} +void bc_tester_add_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 *)); + } +} + +void bc_tester_uninit(void) { + /* Redisplay list of failed tests on end */ + if (CU_get_number_of_failure_records()){ + CU_basic_show_failures(CU_get_failure_list()); + } + CU_cleanup_registry(); + /*add missing final newline*/ + bc_tester_printf(bc_printf_verbosity_info,""); + + if( xml_enabled ){ + /*create real xml file only if tester did not crash*/ + size_t size = strlen(xml_file) + strlen(".tmp-Results.xml") + 1; + char * xml_tmp_file = malloc(sizeof(char) * size); + snprintf(xml_tmp_file, size, "%s.tmp-Results.xml", xml_file); + rename(xml_tmp_file, xml_file); + free(xml_tmp_file); + } + + if (test_suite != NULL) { + free(test_suite); + test_suite = NULL; + nb_test_suites = 0; + } + + if (bc_tester_resource_dir_prefix != NULL) { + free(bc_tester_resource_dir_prefix); + bc_tester_resource_dir_prefix = NULL; + } + if (bc_tester_writable_dir_prefix != NULL) { + free(bc_tester_writable_dir_prefix); + bc_tester_writable_dir_prefix = NULL; + } +} + +static void bc_tester_set_dir_prefix(char **prefix, const char *name) { + size_t len = strlen(name); + if (*prefix != NULL) free(*prefix); + *prefix = malloc(len + 1); + strncpy(*prefix, name, len); + (*prefix)[len] = '\0'; +} + +const char * bc_tester_get_resource_dir_prefix(void) { + return bc_tester_resource_dir_prefix; +} + +void bc_tester_set_resource_dir_prefix(const char *name) { + bc_tester_set_dir_prefix(&bc_tester_resource_dir_prefix, name); +} + +const char * bc_tester_get_writable_dir_prefix(void) { + return bc_tester_writable_dir_prefix; +} + +void bc_tester_set_writable_dir_prefix(const char *name) { + bc_tester_set_dir_prefix(&bc_tester_writable_dir_prefix, name); +} + +static char * bc_tester_path(const char *prefix, const char *name) { + char* file = NULL; + if (name) { + size_t len = strlen(prefix) + 1 + strlen(name) + 1; + file = malloc(len); + snprintf(file, len, "%s/%s", prefix, name); + file[strlen(file)] = '\0'; + } + return file; +} + +char * bc_tester_res(const char *name) { + return bc_tester_path(bc_tester_resource_dir_prefix, name); +} + +char * bc_tester_file(const char *name) { + return bc_tester_path(bc_tester_writable_dir_prefix, name); +} diff --git a/tester/common/bc_tester_utils.h b/tester/common/bc_tester_utils.h new file mode 100644 index 000000000..b3c1deaae --- /dev/null +++ b/tester/common/bc_tester_utils.h @@ -0,0 +1,166 @@ +/* + tester - liblinphone test suite + 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, see . +*/ + + +#ifndef TESTER_UTILS_H +#define TESTER_UTILS_H + +#include +#include +#include +#include + +#ifdef _WIN32 +#ifndef snprintf +#define snprintf _snprintf +#endif +#endif + +extern int bc_printf_verbosity_info; +extern int bc_printf_verbosity_error; + +typedef void (*test_function_t)(void); +typedef int (*init_function_t)(void); +typedef int (*cleanup_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; + init_function_t init_func; + cleanup_function_t cleanup_func; + int nb_tests; + test_t *tests; +} test_suite_t; + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CHECK_ARG(argument, index, argc) \ +if(index >= argc) { \ +fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ +return -1; \ +} \ + +void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args) + , int verbosity_info, int verbosity_error); +void bc_tester_helper(const char *name, const char* additionnal_helper); +int bc_tester_parse_args(int argc, char** argv, int argid); +int bc_tester_start(void); +void bc_tester_add_suite(test_suite_t *suite); +void bc_tester_uninit(void); +void bc_tester_printf(int level, const char *fmt, ...); +const char * bc_tester_get_resource_dir_prefix(void); +void bc_tester_set_resource_dir_prefix(const char *name); +const char * bc_tester_get_writable_dir_prefix(void); +void bc_tester_set_writable_dir_prefix(const char *name); + +int bc_tester_nb_suites(void); +int bc_tester_nb_tests(const char* name); +void bc_tester_list_suites(void); +void bc_tester_list_tests(const char *suite_name); +const char * bc_tester_suite_name(int suite_index); +const char * bc_tester_test_name(const char *suite_name, int test_index); +int bc_tester_run_suite(test_suite_t *suite); +int bc_tester_run_tests(const char *suite_name, const char *test_name); +int bc_tester_suite_index(const char *suite_name); + + +/** + * Get full path to the given resource + * + * @param name relative resource path + * @return path to the resource. Must be freed by caller. +*/ +char * bc_tester_res(const char *name); + +/** +* Get full path to the given writable_file +* +* @param name relative writable file path +* @return path to the writable file. Must be freed by caller. +*/ +char * bc_tester_file(const char *name); + + +/*Redefine the CU_... macros WITHOUT final ';' semicolon, to allow IF conditions and with smarter error message */ +extern int CU_assertImplementation(int bValue, + unsigned int uiLine, + const char *strCondition, + const char *strFile, + const char *strFunction, + int bFatal); + +#define _BC_ASSERT(pred, format, fatal) CU_assertImplementation(pred, __LINE__, format, __FILE__, "", fatal) +#define _BC_ASSERT_PRED(name, pred, actual, expected, type, fatal, ...) \ + do { \ + char format[4096] = {0}; \ + type cactual = (actual); \ + type cexpected = (expected); \ + snprintf(format, 4096, name "(" #actual ", " #expected ") - " __VA_ARGS__); \ + _BC_ASSERT(pred, format, fatal); \ + } while (0) +#define BC_PASS(msg) _BC_ASSERT(TRUE, "BC_PASS(" #msg ").", FALSE) +#define BC_FAIL(msg) _BC_ASSERT(FALSE, "BC_FAIL(" #msg ").", FALSE) +#define BC_ASSERT(value) _BC_ASSERT((value), #value, FALSE) +#define BC_ASSERT_FATAL(value) _BC_ASSERT((value), #value, TRUE) +#define BC_TEST(value) _BC_ASSERT((value), #value, FALSE) +#define BC_TEST_FATAL(value) _BC_ASSERT((value), #value, TRUE) +#define BC_ASSERT_TRUE(value) _BC_ASSERT((value), ("BC_ASSERT_TRUE(" #value ")"), FALSE) +#define BC_ASSERT_TRUE_FATAL(value) _BC_ASSERT((value), ("BC_ASSERT_TRUE_FATAL(" #value ")"), TRUE) +#define BC_ASSERT_FALSE(value) _BC_ASSERT(!(value), ("BC_ASSERT_FALSE(" #value ")"), FALSE) +#define BC_ASSERT_FALSE_FATAL(value) _BC_ASSERT(!(value), ("BC_ASSERT_FALSE_FATAL(" #value ")"), TRUE) +#define BC_ASSERT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_EQUAL", ((cactual) == (cexpected)), actual, expected, type, FALSE, "Expected " type_format " but was " type_format ".", cexpected, cactual) +#define BC_ASSERT_EQUAL_FATAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_EQUAL_FATAL", ((cactual) == (cexpected)), actual, expected, type, TRUE, "Expected " type_format " but was " type_format ".", cexpected, cactual) +#define BC_ASSERT_NOT_EQUAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_NOT_EQUAL", ((cactual) != (cexpected)), actual, expected, type, FALSE, "Expected NOT " type_format " but it was.", cexpected) +#define BC_ASSERT_NOT_EQUAL_FATAL(actual, expected, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_NOT_EQUAL_FATAL", ((cactual) != (cexpected)), actual, expected, type, TRUE, "Expected NOT " type_format " but it was.", cexpected) +#define BC_ASSERT_PTR_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_PTR_EQUAL", ((cactual) == (cexpected)), (const void*)(actual), (const void*)(expected), const void*, FALSE, "Expected %p but was %p.", cexpected, cactual) +#define BC_ASSERT_PTR_EQUAL_FATAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_PTR_EQUAL_FATAL", ((cactual) == (cexpected)), (const void*)(actual), (const void*)(expected), const void*, TRUE, "Expected %p but was %p.", cexpected, cactual) +#define BC_ASSERT_PTR_NOT_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_PTR_NOT_EQUAL", ((cactual) != (cexpected)), (const void*)(actual), (const void*)(expected), const void*, FALSE, "Expected NOT %p but it was.", cexpected) +#define BC_ASSERT_PTR_NOT_EQUAL_FATAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_PTR_NOT_EQUAL_FATAL", ((cactual) != (cexpected)), (const void*)(actual), (const void*)(expected), const void*, TRUE, "Expected NOT %p but it was.", cexpected) +#define BC_ASSERT_PTR_NULL(value) _BC_ASSERT_PRED("BC_ASSERT_PTR_NULL", ((cactual) == (cexpected)), (const void*)(value), (const void*)NULL, const void*, FALSE, "Expected NULL but was %p.", cactual) +#define BC_ASSERT_PTR_NULL_FATAL(value) _BC_ASSERT_PRED("BC_ASSERT_PTR_NULL_FATAL", ((cactual) == (cexpected)), (const void*)(value), (const void*)NULL, const void*, TRUE, "Expected NULL but was %p.", cactual) +#define BC_ASSERT_PTR_NOT_NULL(value) _BC_ASSERT_PRED("BC_ASSERT_PTR_NOT_NULL", ((cactual) != (cexpected)), (const void*)(value), (const void*)NULL, const void*, FALSE, "Expected NOT NULL but it was.") +#define BC_ASSERT_PTR_NOT_NULL_FATAL(value) _BC_ASSERT_PRED("BC_ASSERT_PTR_NOT_NULL_FATAL", ((cactual) != (cexpected)), (const void*)(value), (const void*)NULL, const void*, TRUE, "Expected NOT NULL but it was.") +#define BC_ASSERT_STRING_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_EQUAL", !(strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, FALSE, "Expected %s but was %s.", cexpected, cactual) +#define BC_ASSERT_STRING_EQUAL_FATAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_EQUAL_FATAL", !(strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, TRUE, "Expected %s but was %s.", cexpected, cactual) +#define BC_ASSERT_STRING_NOT_EQUAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_NOT_EQUAL", (strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, FALSE, "Expected NOT %s but it was.", cexpected) +#define BC_ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected) _BC_ASSERT_PRED("BC_ASSERT_STRING_NOT_EQUAL_FATAL", (strcmp((const char*)(cactual), (const char*)(cexpected))), actual, expected, const char*, TRUE, "Expected NOT %s but it was.", cexpected) +#define BC_ASSERT_NSTRING_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_EQUAL", !(strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, FALSE, "Expected %*s but was %*s.", (int)(count), cexpected, (int)(count), cactual) +#define BC_ASSERT_NSTRING_EQUAL_FATAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_EQUAL_FATAL", !(strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, TRUE, "Expected %*s but was %*s.", (int)count, cexpected, (int)count, cactual) +#define BC_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_NOT_EQUAL", (strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, FALSE, "Expected %*s but it was.", (int)count, cexpected) +#define BC_ASSERT_NSTRING_NOT_EQUAL_FATAL(actual, expected, count) _BC_ASSERT_PRED("BC_ASSERT_NSTRING_NOT_EQUAL_FATAL", (strncmp((const char*)(cactual), (const char*)(cexpected), (size_t)(count))), actual, expected, const char*, TRUE, "Expected %*s but it was.", (int)count, cexpected) +#define BC_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_EQUAL", ((fabs((double)(cactual) - (cexpected)) <= fabs((double)(granularity)))), actual, expected, double, FALSE, "Expected %f but was %f.", cexpected, cactual) +#define BC_ASSERT_DOUBLE_EQUAL_FATAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_EQUAL_FATAL", ((fabs((double)(cactual) - (cexpected)) <= fabs((double)(granularity)))), actual, expected, double, TRUE, "Expected %f but was %f.", cexpected, cactual) +#define BC_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_NOT_EQUAL", ((fabs((double)(cactual) - (cexpected)) > fabs((double)(granularity)))), actual, expected, double, FALSE, "Expected %f but was %f.", cexpected, cactual) +#define BC_ASSERT_DOUBLE_NOT_EQUAL_FATAL(actual, expected, granularity) _BC_ASSERT_PRED("BC_ASSERT_DOUBLE_NOT_EQUAL_FATAL", ((fabs((double)(cactual) - (cexpected)) > fabs((double)(granularity)))), actual, expected, double, TRUE, "Expected %f but was %f.", cexpected, cactual) + +/*Custom defines*/ +#define BC_ASSERT_GREATER(actual, lower, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_GREATER", ((cactual) >= (cexpected)), actual, lower, type, FALSE, "Expected at least " type_format " but was " type_format ".", cexpected, cactual) +#define BC_ASSERT_LOWER(actual, lower, type, type_format) _BC_ASSERT_PRED("BC_ASSERT_LOWER", ((cactual) <= (cexpected)), actual, lower, type, FALSE, "Expected at most " type_format " but was " type_format ".", cexpected, cactual) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tester/dtmf_tester.c b/tester/dtmf_tester.c new file mode 100644 index 000000000..38d6c3579 --- /dev/null +++ b/tester/dtmf_tester.c @@ -0,0 +1,180 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include "liblinphone_tester.h" +#include "private.h" + +void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) { + stats* counters = get_stats(lc); + char** dst = &counters->dtmf_list_received; + *dst = *dst ? + ms_strcat_printf(*dst, "%c", dtmf) + : ms_strdup_printf("%c", dtmf); + counters->dtmf_count++; +} + +void send_dtmf_base(LinphoneCoreManager **pmarie, LinphoneCoreManager **ppauline, bool_t use_rfc2833, bool_t use_sipinfo, char dtmf, char* dtmf_seq, bool_t use_opus) { + char* expected = NULL; + int dtmf_count_prev; + LinphoneCoreManager *marie = *pmarie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager *pauline = *ppauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall *marie_call = NULL; + + if (use_opus) { + if (!ms_filter_codec_supported("opus")) { + ms_warning("Opus not supported, skipping test."); + return; + } + disable_all_audio_codecs_except_one(marie->lc, "opus", 48000); + disable_all_audio_codecs_except_one(pauline->lc, "opus", 48000); + } + + linphone_core_set_use_rfc2833_for_dtmf(marie->lc, use_rfc2833); + linphone_core_set_use_info_for_dtmf(marie->lc, use_sipinfo); + linphone_core_set_use_rfc2833_for_dtmf(pauline->lc, use_rfc2833); + linphone_core_set_use_info_for_dtmf(pauline->lc, use_sipinfo); + + BC_ASSERT_TRUE(call(pauline,marie)); + + marie_call = linphone_core_get_current_call(marie->lc); + + BC_ASSERT_PTR_NOT_NULL(marie_call); + + if (!marie_call) return; + + if (dtmf != '\0') { + dtmf_count_prev = pauline->stat.dtmf_count; + linphone_call_send_dtmf(marie_call, dtmf); + + /*wait for the DTMF to be received from pauline*/ + BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.dtmf_count, dtmf_count_prev+1, 10000)); + expected = ms_strdup_printf("%c", dtmf); + } + + if (dtmf_seq != NULL) { + int dtmf_delay_ms = lp_config_get_int(marie_call->core->config,"net","dtmf_delay_ms",200); + dtmf_count_prev = pauline->stat.dtmf_count; + linphone_call_send_dtmfs(marie_call, dtmf_seq); + + /*wait for the DTMF sequence to be received from pauline*/ + BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &pauline->stat.dtmf_count, dtmf_count_prev + strlen(dtmf_seq), 10000 + dtmf_delay_ms * strlen(dtmf_seq))); + expected = (dtmf!='\0')?ms_strdup_printf("%c%s",dtmf,dtmf_seq):ms_strdup(dtmf_seq); + } + + if (expected != NULL) { + BC_ASSERT_PTR_NOT_NULL(pauline->stat.dtmf_list_received); + if (pauline->stat.dtmf_list_received) { + BC_ASSERT_STRING_EQUAL(pauline->stat.dtmf_list_received, expected); + } + ms_free(expected); + } else { + BC_ASSERT_PTR_NULL(pauline->stat.dtmf_list_received); + } +} + +void send_dtmf_cleanup(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) { + LinphoneCall *marie_call = linphone_core_get_current_call(marie->lc); + if (marie_call) { + BC_ASSERT_PTR_NULL(marie_call->dtmfs_timer); + BC_ASSERT_PTR_NULL(marie_call->dtmf_sequence); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_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 send_dtmf_rfc2833() { + LinphoneCoreManager *marie, *pauline; + send_dtmf_base(&marie, &pauline, TRUE,FALSE,'1',NULL,FALSE); + send_dtmf_cleanup(marie, pauline); +} + +static void send_dtmf_sip_info() { + LinphoneCoreManager *marie, *pauline; + send_dtmf_base(&marie, &pauline, FALSE,TRUE,'#',NULL,FALSE); + send_dtmf_cleanup(marie, pauline); +} + +static void send_dtmfs_sequence_rfc2833() { + LinphoneCoreManager *marie, *pauline; + send_dtmf_base(&marie, &pauline, TRUE,FALSE,'\0',"1230#",FALSE); + send_dtmf_cleanup(marie, pauline); +} + +static void send_dtmfs_sequence_sip_info() { + LinphoneCoreManager *marie, *pauline; + send_dtmf_base(&marie, &pauline, FALSE,TRUE,'\0',"1230#",FALSE); + send_dtmf_cleanup(marie, pauline); +} + +static void send_dtmfs_sequence_not_ready() { + LinphoneCoreManager *marie; + marie = linphone_core_manager_new( "marie_rc"); + BC_ASSERT_EQUAL(linphone_call_send_dtmfs(linphone_core_get_current_call(marie->lc), "123"), -1, int, "%d"); + linphone_core_manager_destroy(marie); +} + +static void send_dtmfs_sequence_call_state_changed() { + LinphoneCoreManager *marie, *pauline; + LinphoneCall *marie_call = NULL; + send_dtmf_base(&marie, &pauline, FALSE,TRUE,'\0',NULL,FALSE); + + marie_call = linphone_core_get_current_call(marie->lc); + if (marie_call) { + /*very long DTMF(around 4 sec to be sent)*/ + linphone_call_send_dtmfs(marie_call, "123456789123456789"); + /*just after, change call state, and expect DTMF to be canceled*/ + linphone_core_pause_call(marie_call->core,marie_call); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + /*wait a few time to ensure that no DTMF are received*/ + wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000); + + BC_ASSERT_PTR_NULL(pauline->stat.dtmf_list_received); + } + send_dtmf_cleanup(marie, pauline); +} + +static void send_dtmf_rfc2833_opus() { + LinphoneCoreManager *marie, *pauline; + send_dtmf_base(&marie, &pauline, TRUE,FALSE,'1',NULL,TRUE); + send_dtmf_cleanup(marie, pauline); +} + +test_t dtmf_tests[] = { + { "Send DTMF using RFC2833",send_dtmf_rfc2833}, + { "Send DTMF using SIP INFO",send_dtmf_sip_info}, + { "Send DTMF sequence using RFC2833",send_dtmfs_sequence_rfc2833}, + { "Send DTMF sequence using SIP INFO",send_dtmfs_sequence_sip_info}, + { "DTMF sequence not sent if invalid call",send_dtmfs_sequence_not_ready}, + { "DTMF sequence canceled if call state changed",send_dtmfs_sequence_call_state_changed}, + { "Send DTMF using RFC2833 using Opus",send_dtmf_rfc2833_opus}, +}; + +test_suite_t dtmf_test_suite = { + "DTMF", + liblinphone_tester_setup, + NULL, + sizeof(dtmf_tests) / sizeof(dtmf_tests[0]), + dtmf_tests +}; diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c new file mode 100644 index 000000000..b196652db --- /dev/null +++ b/tester/eventapi_tester.c @@ -0,0 +1,377 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + + +#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"; + +const char *liblinphone_tester_get_subscribe_content(void){ + return subscribe_content; +} + +const char *liblinphone_tester_get_notify_content(void){ + return notify_content; +} + +void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ + LinphoneCoreManager *mgr; + BC_ASSERT_PTR_NOT_NULL_FATAL(content); + BC_ASSERT_STRING_EQUAL(notify_content,(const char*)linphone_content_get_buffer(content)); + 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; + const LinphoneAddress* from_addr = linphone_event_get_from(lev); + char* from = linphone_address_as_string(from_addr); + content = linphone_core_create_content(lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml2"); + linphone_content_set_buffer(content,notify_content,strlen(notify_content)); + + ms_message("Subscription state [%s] from [%s]",linphone_subscription_state_to_string(state),from); + ms_free(from); + + switch(state){ + case LinphoneSubscriptionNone: + break; + case LinphoneSubscriptionIncomingReceived: + counters->number_of_LinphoneSubscriptionIncomingReceived++; + mgr->lev=lev; + if (!mgr->decline_subscribe) + linphone_event_accept_subscription(lev); + else + linphone_event_deny_subscription(lev, LinphoneReasonDeclined); + break; + case LinphoneSubscriptionOutgoingInit: + 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; + case LinphoneSubscriptionExpiring: + counters->number_of_LinphoneSubscriptionExpiring++; + mgr->lev=NULL; + break; + } + linphone_content_unref(content); +} + +void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + stats* counters = get_stats(lc); + const LinphoneAddress* from_addr = linphone_event_get_from(ev); + char* from = linphone_address_as_string(from_addr); + ms_message("Publish state [%s] from [%s]",linphone_publish_state_to_string(state),from); + ms_free(from); + switch(state){ + case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break; + case LinphonePublishOk: + /*make sure custom header access API is working*/ + BC_ASSERT_PTR_NOT_NULL(linphone_event_get_custom_header(ev,"From")); + 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_tcp_rc"); + LinphoneContent* content; + LinphoneEvent *lev; + const LinphoneErrorInfo *ei; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + + pauline->decline_subscribe=TRUE; + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,content); + linphone_event_ref(lev); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/ + ei=linphone_event_get_error_info(lev); + BC_ASSERT_PTR_NOT_NULL(ei); + if (ei){ + BC_ASSERT_EQUAL(linphone_error_info_get_protocol_code(ei),603, int, "%d"); + BC_ASSERT_PTR_NOT_NULL(linphone_error_info_get_phrase(ei)); + } + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_content_unref(content); + linphone_event_unref(lev); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +typedef enum RefreshTestType{ + NoRefresh, + AutoRefresh, + ManualRefresh +}RefreshTestType; + +static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneContent* content; + LinphoneEvent *lev; + int expires= refresh_type!=NoRefresh ? 4 : 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + + if (refresh_type==ManualRefresh){ + lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + } + + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + + /*make sure marie receives first notification before terminating*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); + + if (refresh_type==AutoRefresh){ + wait_for_list(lcs,NULL,0,6000); + BC_ASSERT_EQUAL(linphone_event_get_subscription_state(pauline->lev), LinphoneSubscriptionActive, int, "%d"); + }else if (refresh_type==ManualRefresh){ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); + linphone_event_update_subscribe(lev,NULL); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,2000)); + } + + if (terminated_by_subscriber){ + linphone_event_terminate(lev); + }else{ + BC_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); + linphone_event_terminate(pauline->lev); + } + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneContent* content; + LinphoneEvent *lev; + int expires= refresh_type!=NoRefresh ? 4 : 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + + if (refresh_type==ManualRefresh){ + lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + } + + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + + lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); + linphone_event_add_custom_header(lev,"My-Header","pouet"); + linphone_event_add_custom_header(lev,"My-Header2","pimpon"); + linphone_event_send_subscribe(lev,content); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); + + if (pauline->stat.number_of_LinphoneSubscriptionIncomingReceived == 1) { + /*check good receipt of custom headers*/ + BC_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header"),"pouet"); + BC_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header2"),"pimpon"); + } + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,5000)); + + /*make sure marie receives first notification before terminating*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,5000)); + + if (refresh_type==AutoRefresh){ + wait_for_list(lcs,NULL,0,6000); + BC_ASSERT_EQUAL(linphone_event_get_subscription_state(pauline->lev), LinphoneSubscriptionActive, int, "%d"); + }else if (refresh_type==ManualRefresh){ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); + linphone_event_update_subscribe(lev,NULL); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,5000)); + } + + if (terminated_by_subscriber){ + linphone_event_terminate(lev); + }else{ + BC_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); + linphone_event_terminate(pauline->lev); + } + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,5000)); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void subscribe_test_terminated_by_subscriber(void){ + subscribe_test_with_args(TRUE,NoRefresh); +} + +static void subscribe_test_terminated_by_notifier(void){ + subscribe_test_with_args(FALSE,NoRefresh); +} + +/* 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,AutoRefresh); +} + +static void subscribe_test_with_custom_header(void){ + subscribe_test_with_args2(TRUE,NoRefresh); +} + +static void subscribe_test_manually_refreshed(void){ + subscribe_test_with_args(TRUE,ManualRefresh); +} + +static void publish_test_with_args(bool_t refresh, int expires){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneContent* content; + LinphoneEvent *lev; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content)); + + lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",refresh); + + lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",expires); + linphone_event_add_custom_header(lev,"CustomHeader","someValue"); + linphone_event_send_publish(lev,content); + linphone_event_ref(lev); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); + + if (!refresh){ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishExpiring,1,5000)); + linphone_event_update_publish(lev,content); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); + }else{ + + } + + linphone_event_terminate(lev); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,3000)); + + linphone_event_unref(lev); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void publish_test(){ + publish_test_with_args(TRUE,5); +} + +static void publish_no_auto_test(){ + publish_test_with_args(FALSE,5); +} + +static void publish_without_expires(){ + publish_test_with_args(TRUE,-1); +} + +test_t event_tests[] = { + { "Subscribe declined" , subscribe_test_declined }, + { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, + { "Subscribe with custom headers", subscribe_test_with_custom_header }, + { "Subscribe refreshed", subscribe_test_refreshed }, + { "Subscribe manually refreshed", subscribe_test_manually_refreshed }, + { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, + { "Publish", publish_test }, + { "Publish without expires", publish_without_expires }, + { "Publish without automatic refresh",publish_no_auto_test } +}; + +test_suite_t event_test_suite = { + "Event", + liblinphone_tester_setup, + NULL, + sizeof(event_tests) / sizeof(event_tests[0]), + event_tests +}; + diff --git a/tester/flexisip/flexisip.conf b/tester/flexisip/flexisip.conf new file mode 100644 index 000000000..7fe250368 --- /dev/null +++ b/tester/flexisip/flexisip.conf @@ -0,0 +1,617 @@ +## +## 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 sip2.linphone.org 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 + +#note: the ip addresses are explicitely specified here because the machine has several interfaces. In a simple case, using '*' instead of the explicit ip address is sufficient, +#and there is no need to specify the ipv6 transport addresses. +transports=sip:94.23.19.176:5060 sips:94.23.19.176:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:94.23.19.176:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:94.23.19.176:5063;require-peer-certificate=1 sip:94.23.19.176:5064 sip:[2001:41d0:2:14b0::1]:5060 sips:[2001:41d0:2:14b0::1]:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:[2001:41d0:2:14b0::1]:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:[2001:41d0:2:14b0::1]:5063;require-peer-certificate=1 sip:[2001:41d0:2:14b0::1]:5064 + + +# 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 + + + +## +## 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 + + +no-403=user-agent contains 'tester-no-403' + +# 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' || from.uri.domain contains 'anonymous.invalid' + +# 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 + + +# Use pooling in odbc +# Default value: true +odbc-pooling=true + + +# Duration of the validity of the credentials added to the cache +# in seconds. +# Default value: 1800 +cache-expire=1800 + + +# 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 + +enable-test-accounts-creation=true + +## +## ... +## +[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=true + +call-fork-timeout=20 + + + +# 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=60 +## +## 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 client.example.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: +sip.instance +#unique-id-parameters= + +# Maximum expire time for a REGISTER, in seconds. +# Default value: 86400 +max-expires=60 + +# 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= + + +[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 + +# Sends a ACK and BYE to 200 Ok for INVITEs not belonging to any established call. +bye-orphan-dialogs=true + + +## +## 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 + +[module::Redirect] +enabled=true +filter = (user-agent contains 'redirect') && !(request.uri.params contains 'redirected') +contact= + +## +## The purpose of the StatisticsCollector module is to collect call +## statistics (RFC 6035) and store them on the server. +## +[module::StatisticsCollector] +# 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= + +# SIP URI of the statistics collector. Note that the messages destinated +# to this address will be deleted by this module and thus not be +# delivered. +# Default value: +collector-address=sip:sip.example.org + +## +## This module performs push notifications to mobile phone notification +## systems: apple, android, windows, as well as a generic http get/post +## to a custom server to which actual sending of the notification +## is delegated. The push notification is sent when an INVITE or +## MESSAGE request is not answered by the destination of the request +## within a certain period of time, configurable hereunder as 'timeout' +## parameter. +## + + + +[module::PushNotification] +# 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= + +# 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=false + +# 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=false + +# List of couples projectId:ApiKey for each android project that +# supports push notifications +# Default value: +google-projects-api-keys= + +# Enable push notification for windows phone 8 devices +# Default value: true +windowsphone=false + +# Set the badge value to 0 for apple push +# Default value: false +no-badge=false + +# Instead of having Flexisip sending the push notification directly +# to the Google/Apple/Microsoft push servers, send an http request +# to an http server with all required information encoded in URL, +# to which the actual sending of the push notification is delegated. +# The following arguments can be substitued in the http request +# uri, with the following values: +# - $type : apple, google, wp +# - $event : call, message +# - $from-name : the display name in the from header +# - $from-uri : the sip uri of the from header +# - $from-tag : the tag of the from header +# - $call-id : the call-id of the INVITE or MESSAGE request +# - $to-uri : the sip uri of the to header +# - $api-key : the api key to use (google only) +# - $msgid : the message id to put in the notification +# - $sound : the sound file to play with the notification +# + The content of the text message is put in the body of the http +# request as text/plain, if any. +# Example: http://192.168.0.2/$type/$event?from-uri=$from-uri&tag=$from-tag&callid=$callid&to=$to-uri +# Default value: +external-push-uri=http://127.0.0.1:80/$type/$event?from-uri=$from-uri&tag=$from-tag&callid=$callid&to=$to-uri + +# Method for reaching external-push-uri, typically GET or POST +# Default value: GET +external-push-method=GET + +## +## This module bans user when they are sending too much packets on +## a given timelapseTo see the list of currently banned ips/ports, +## use iptables -LYou can also check the queue of unban commands +## using atq +## +[module::DoSProtection] + +# 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= + +# Number of milliseconds to consider to compute the packet rate +# Default value: 3000 +time-period=15000 + +# Maximum packet rate received in [time-period] millisecond(s) to +# consider it as a DoS attack. +# Default value: 20 +packet-rate-limit=5 + +# Number of minutes to ban the ip/port using iptables (might be +# less because it justs uses the minutes of the clock, not the seconds. +# So if the unban command is queued at 13:11:56 and scheduled and +# the ban time is 1 minute, it will be executed at 13:12:00) +# Default value: 2 +ban-time=1 + diff --git a/tester/flexisip/userdb.conf b/tester/flexisip/userdb.conf new file mode 100644 index 000000000..3ee1b7e0a --- /dev/null +++ b/tester/flexisip/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/tester/flexisip_tester.c b/tester/flexisip_tester.c new file mode 100644 index 000000000..c2bb8b780 --- /dev/null +++ b/tester/flexisip_tester.c @@ -0,0 +1,938 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static void subscribe_forking(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneContent* content; + LinphoneEvent *lev; + int expires= 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + content = linphone_core_create_content(marie->lc); + linphone_content_set_type(content,"application"); + linphone_content_set_subtype(content,"somexml"); + linphone_content_set_buffer(content, liblinphone_tester_get_subscribe_content(), strlen(liblinphone_tester_get_subscribe_content())); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,content); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline2->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); + + /*make sure marie receives first notification before terminating*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); + + linphone_event_terminate(lev); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); +} + +static void message_forking(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + +static void message_forking_with_unreachable_recipients(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + /*marie2 and marie3 go offline*/ + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(marie2->stat.number_of_LinphoneMessageReceived, 0, int, "%d"); + BC_ASSERT_EQUAL(marie3->stat.number_of_LinphoneMessageReceived, 0, int, "%d"); + /*marie 2 goes online */ + linphone_core_set_network_reachable(marie2->lc,TRUE); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,3000)); + + /*wait a long time so that all transactions are expired*/ + wait_for_list(lcs,NULL,0,32000); + + /*marie 3 goes online now*/ + linphone_core_set_network_reachable(marie3->lc,TRUE); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,3000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + +static void message_forking_with_all_recipients_unreachable(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + /*All marie's device go offline*/ + linphone_core_set_network_reachable(marie->lc,FALSE); + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageInProgress,1,5000)); + /*flexisip will accept the message with 202 after 16 seconds*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,18000)); + BC_ASSERT_EQUAL( marie->stat.number_of_LinphoneMessageReceived, 0, int, "%d"); + BC_ASSERT_EQUAL( marie2->stat.number_of_LinphoneMessageReceived, 0, int, "%d"); + BC_ASSERT_EQUAL( marie3->stat.number_of_LinphoneMessageReceived, 0, int, "%d"); + + /*marie 1 goes online */ + linphone_core_set_network_reachable(marie->lc,TRUE); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); + + /*marie 2 goes online */ + linphone_core_set_network_reachable(marie2->lc,TRUE); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,3000)); + + /*wait a long time so that all transactions are expired*/ + wait_for_list(lcs,NULL,0,32000); + + /*marie 3 goes online now*/ + linphone_core_set_network_reachable(marie3->lc,TRUE); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,3000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + +static void call_forking(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + + /*marie accepts the call on its first device*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*other devices should stop ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_with_urgent_reply(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + BC_ASSERT_TRUE(linphone_core_media_encryption_supported(pauline->lc,LinphoneMediaEncryptionSRTP)); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback, after 5 seconds, when it will retry without SRTP*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,9000)); + /*Marie should be ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie accepts the call on its first device*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_cancelled(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*pauline finally cancels the call*/ + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + + /*all devices should stop ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_declined(bool_t declined_globaly){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie finally declines the call*/ + linphone_core_decline_call(marie->lc,linphone_core_get_current_call(marie->lc), + declined_globaly ? LinphoneReasonDeclined : LinphoneReasonBusy + ); + + if (declined_globaly){ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + /*all devices should stop ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + }else{ + /*pauline should continue ringing and be able to hear a call taken by marie2 */ + linphone_core_accept_call(marie2->lc, linphone_core_get_current_call(marie2->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + liblinphone_tester_check_rtcp(pauline,marie2); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,3000)); + linphone_core_terminate_call(marie2->lc,linphone_core_get_current_call(marie2->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,3000)); + } + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_declined_globaly(void){ + call_forking_declined(TRUE); +} + +static void call_forking_declined_localy(void){ + call_forking_declined(FALSE); +} + +static void call_forking_with_push_notification_single(void){ + MSList* lcs; + LinphoneCoreManager* marie = linphone_core_manager_new2( "marie_rc", FALSE); + LinphoneCoreManager* pauline = linphone_core_manager_new2( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc",FALSE); + int dummy=0; + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + linphone_proxy_config_set_contact_uri_parameters( + linphone_core_get_default_proxy_config(marie->lc), + "app-id=org.linphonetester;pn-tok=aaabbb;pn-type=apple;pn-msg-str=33;pn-call-str=34;"); + + lcs=ms_list_append(NULL,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneRegistrationOk,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneRegistrationOk,1,5000)); + + /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ + linphone_core_set_network_reachable(marie->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + + /*After 5 seconds the server is expected to send a push notification to marie, this will wake up linphone, that will reconnect:*/ + wait_for_list(lcs,&dummy,1,6000); + linphone_core_set_network_reachable(marie->lc,TRUE); + + /*Marie shall receive the call immediately*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000)); + /*pauline should hear ringback as well*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + /*marie accepts the call*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + liblinphone_tester_check_rtcp(pauline,marie); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + ms_list_free(lcs); +} + +static void call_forking_with_push_notification_multiple(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ + linphone_core_set_network_reachable(marie2->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + + /*marie will ring*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000)); + /*pauline should hear ringback as well*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + /*the server is expected to send a push notification to marie2, this will wake up linphone, that will reconnect:*/ + linphone_core_set_network_reachable(marie2->lc,TRUE); + + /*Marie shall receive the call immediately*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,5000)); + + /*marie2 accepts the call*/ + linphone_core_accept_call(marie2->lc,linphone_core_get_current_call(marie2->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*call to marie should be cancelled*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + liblinphone_tester_check_rtcp(pauline,marie2); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); +} + +static void call_forking_not_responded(void){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*nobody answers, flexisip should close the call after XX seconds*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,22000)); + /*all devices should stop ringing*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void early_media_call_forking(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_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; + + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_set_user_agent(marie->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(marie->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie->lc,&pol); + + 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); + + lcs=ms_list_append(lcs,marie->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,marie->identity,params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1, int, "%d"); + + pauline_call=linphone_core_get_current_call(pauline->lc); + marie1_call=linphone_core_get_current_call(marie->lc); + marie2_call=linphone_core_get_current_call(marie2->lc); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,6000); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 60, int, "%d"); + BC_ASSERT_LOWER(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 99, int, "%d"); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 60, int, "%d"); + BC_ASSERT_LOWER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 99, int, "%d"); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(marie2_call)->download_bandwidth, 60, int, "%d"); + BC_ASSERT_LOWER(linphone_call_get_audio_stats(marie2_call)->download_bandwidth, 99, int, "%d"); + + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + + /*marie2 should get her call terminated*/ + BC_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,3000); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 60, int, "%d"); + BC_ASSERT_LOWER(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 99, int, "%d"); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 60, int, "%d"); + BC_ASSERT_LOWER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 99, int, "%d"); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie); +} + +static void call_with_sips(void){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc"); + LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_sips_rc"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline1->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline1->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline2->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(marie->lc,pauline1->identity); + + /*marie should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*Only the sips registered device from pauline should ring*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*pauline accepts the call */ + linphone_core_accept_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*pauline2 should not have ring*/ + BC_ASSERT_EQUAL(pauline2->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); + + linphone_core_terminate_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallEnd,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,3000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline1); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); + } +} + +static void call_with_sips_not_achievable(void){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc"); + LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + LinphoneAddress *dest; + LinphoneCall *call; + const LinphoneErrorInfo *ei; + + lcs=ms_list_append(lcs,pauline1->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + + dest=linphone_address_clone(pauline1->identity); + linphone_address_set_secure(dest,TRUE); + call=linphone_core_invite_address(marie->lc,dest); + linphone_call_ref(call); + linphone_address_unref(dest); + + /*Call should be rejected by server with 480*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallError,1,6000)); + ei=linphone_call_get_error_info(call); + BC_ASSERT_PTR_NOT_NULL(ei); + if (ei){ + BC_ASSERT_EQUAL(linphone_error_info_get_reason(ei), LinphoneReasonTemporarilyUnavailable, int, "%d"); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline1); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); + } +} + +static void call_with_ipv6(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall *pauline_call; + + /*calling ortp_init() here is done to have WSAStartup() done, otherwise liblinphone_tester_ipv6_available() will not work.*/ + ortp_init(); + + if (!liblinphone_tester_ipv6_available()){ + ms_warning("Call with ipv6 not tested, no ipv6 connectivity"); + return; + } + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + liblinphone_tester_enable_ipv6(TRUE); + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + BC_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + /*check that the remote contact is IPv6*/ + const char *contact=linphone_call_get_remote_contact(pauline_call); + LinphoneAddress *ct_addr; + + BC_ASSERT_PTR_NOT_NULL(contact); + if (contact){ + ct_addr=linphone_address_new(contact); + BC_ASSERT_PTR_NOT_NULL(ct_addr); + if (ct_addr){ + BC_ASSERT_PTR_NOT_NULL(strchr(linphone_address_get_domain(ct_addr),':')); + } + linphone_address_destroy(ct_addr); + } + + } + + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + liblinphone_tester_enable_ipv6(FALSE); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + ortp_exit(); +} + +static void file_transfer_message_rcs_to_external_body_client(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc"); + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + FILE *file_to_send = NULL; + size_t file_size; + char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg"); + char *receive_filepath = bc_tester_file("receive_file.dump"); + LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc"); + + linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_core_manager_start(marie, "marie_rc", TRUE); + + linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + linphone_core_manager_start(pauline, "pauline_rc", TRUE); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + file_to_send = fopen(send_filepath, "rb"); + fseek(file_to_send, 0, SEEK_END); + file_size = ftell(file_to_send); + fseek(file_to_send, 0, SEEK_SET); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"image"); + linphone_content_set_subtype(content,"jpeg"); + linphone_content_set_size(content,file_size); /*total size to be transfered*/ + linphone_content_set_name(content,"nowebcamCIF.jpg"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + linphone_chat_message_set_user_data(message, file_to_send); + cbs = linphone_chat_message_get_callbacks(message); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_file_transfer_send); + linphone_chat_room_send_chat_message(chat_room,message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); + fclose(file_to_send); + if (marie->stat.last_received_chat_message ) { + cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageFileTransferDone,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1, int, "%d"); + BC_ASSERT_TRUE(compare_files(send_filepath, receive_filepath)); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(send_filepath); + ms_free(receive_filepath); + } +} + +void send_file_transfer_message_using_external_body_url(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) { + LinphoneChatMessageCbs *cbs; + LinphoneChatRoom *chat_room; + LinphoneChatMessage *message; + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + message = linphone_chat_room_create_message(chat_room, NULL); + + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + + linphone_chat_message_set_external_body_url(message, "https://www.linphone.org:444//tmp/54ec58280ace9_c30709218df8eaba61d1.jpg"); + linphone_chat_room_send_chat_message(chat_room, message); + + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1)); + if (marie->stat.last_received_chat_message) { + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageExtBodyReceived, 1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress, 1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived, 1, int, "%d"); +} + +static void file_transfer_message_external_body_to_external_body_client(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc"); + + linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_core_manager_start(marie, "marie_rc", TRUE); + + linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp"); + linphone_core_manager_start(pauline, "pauline_rc", TRUE); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + linphone_core_refresh_registers(marie->lc); + linphone_core_refresh_registers(pauline->lc); + + send_file_transfer_message_using_external_body_url(marie, pauline); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + +static void file_transfer_message_external_body_to_rcs_client(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc"); + + linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp"); + linphone_core_manager_start(marie, "marie_rc", TRUE); + + linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml"); + linphone_core_manager_start(pauline, "pauline_rc", TRUE); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + send_file_transfer_message_using_external_body_url(marie, pauline); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + +static void dos_module_trigger(void) { + LinphoneChatRoom *chat_room; + int i = 0; + const char* passmsg = "This one should pass through"; + int number_of_messge_to_send = 100; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + do { + char msg[128]; + sprintf(msg, "Flood message number %i", i); + linphone_chat_room_send_message(chat_room, msg); + ms_usleep(10000); + i++; + } while (i < number_of_messge_to_send); + // At this point we should be banned for a minute + + ms_usleep(65000000); // Wait several seconds to ensure we are not banned anymore + BC_ASSERT_LOWER(marie->stat.number_of_LinphoneMessageReceived, number_of_messge_to_send, int, "%d"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + linphone_chat_room_send_message(chat_room, passmsg); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived, 1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceived, 1, int, "%d"); + if (marie->stat.last_received_chat_message) { + BC_ASSERT_NSTRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), passmsg, strlen(passmsg)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +test_t flexisip_tests[] = { + { "Subscribe forking", subscribe_forking }, + { "Message forking", message_forking }, + { "Message forking with unreachable recipients", message_forking_with_unreachable_recipients }, + { "Message forking with all recipients unreachable", message_forking_with_all_recipients_unreachable}, + { "Call forking", call_forking }, + { "Call forking cancelled", call_forking_cancelled }, + { "Call forking declined globaly", call_forking_declined_globaly }, + { "Call forking declined localy", call_forking_declined_localy }, + { "Call forking with urgent reply", call_forking_with_urgent_reply }, + { "Call forking with push notification (single)", call_forking_with_push_notification_single }, + { "Call forking with push notification (multiple)", call_forking_with_push_notification_multiple }, + { "Call forking not responded", call_forking_not_responded }, + { "Early-media call forking", early_media_call_forking }, + { "Call with sips", call_with_sips }, + { "Call with sips not achievable", call_with_sips_not_achievable }, + { "Call with ipv6", call_with_ipv6 }, + { "File transfer message rcs to external body client", file_transfer_message_rcs_to_external_body_client }, + { "File transfer message external body to rcs client", file_transfer_message_external_body_to_rcs_client }, + { "File transfer message external body to external body client", file_transfer_message_external_body_to_external_body_client }, + { "DoS module trigger by sending a lot of chat messages", dos_module_trigger } +}; + + +test_suite_t flexisip_test_suite = { + "Flexisip", + liblinphone_tester_setup, + NULL, + sizeof(flexisip_tests) / sizeof(flexisip_tests[0]), + flexisip_tests +}; + + 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/liblinphone_tester.c b/tester/liblinphone_tester.c new file mode 100644 index 000000000..d49c890de --- /dev/null +++ b/tester/liblinphone_tester.c @@ -0,0 +1,252 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . + */ + + +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#if HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +#endif +#ifdef HAVE_GTK +#include +#endif + +static FILE * log_file = NULL; + +#ifdef ANDROID + +#include +#include +#include +#define CALLBACK_BUFFER_SIZE 1024 + +static JNIEnv *current_env = NULL; +static jobject current_obj = 0; +static const char* LogDomain = "liblinphone_tester"; + +int main(int argc, char** argv); + +void liblinphone_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 liblinphone_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; + } + liblinphone_android_log_handler(prio, fmt, args); +} + +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); + (*env)->DeleteLocalRef(env,cls); +} + +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\n" + "\t\t\t--config \n" + "\t\t\t--domain \n" + "\t\t\t--auth-domain \n" + "\t\t\t--dns-hosts \n" + "\t\t\t--keep-recorded-files\n"; + +int main (int argc, char *argv[]) +{ + int i; + int ret; + +#ifdef HAVE_GTK + gtk_init(&argc, &argv); +#if !GLIB_CHECK_VERSION(2,32,0) // backward compatibility with Debian 6 and CentOS 6 + g_thread_init(NULL); +#endif + gdk_threads_init(); +#endif + + liblinphone_tester_init(NULL); + + if (strstr(argv[0], ".libs")) { + char res_dir[128] = {0}; + // this allows to launch liblinphone_tester from outside of tester directory + strncpy(res_dir, argv[0], strstr(argv[0], ".libs")-argv[0]); + bc_tester_set_resource_dir_prefix(res_dir); + bc_tester_set_writable_dir_prefix(res_dir); + } + + for(i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--verbose") == 0) { + linphone_core_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + } else if (strcmp(argv[i], "--silent") == 0) { + linphone_core_set_log_level_mask(ORTP_FATAL); + } else if (strcmp(argv[i],"--log-file")==0){ + CHECK_ARG("--log-file", ++i, argc); + log_file=fopen(argv[i],"w"); + if (!log_file) { + ms_error("Cannot open file [%s] for writing logs because [%s]",argv[i],strerror(errno)); + return -2; + } else { + ms_message("Redirecting traces to file [%s]",argv[i]); + ortp_set_log_file(log_file); + } + } else if (strcmp(argv[i],"--domain")==0){ + CHECK_ARG("--domain", ++i, argc); + test_domain=argv[i]; + } else if (strcmp(argv[i],"--auth-domain")==0){ + CHECK_ARG("--auth-domain", ++i, argc); + auth_domain=argv[i]; + } else if (strcmp(argv[i],"--config")==0){ + CHECK_ARG("--config", ++i, argc); + bc_tester_set_resource_dir_prefix(argv[i]); + }else if (strcmp(argv[i],"--dns-hosts")==0){ + CHECK_ARG("--dns-hosts", ++i, argc); + userhostsfile=argv[i]; + } else if (strcmp(argv[i],"--keep-recorded-files")==0){ + liblinphone_tester_keep_recorded_files(TRUE); + } else { + int bret = bc_tester_parse_args(argc, argv, i); + if (bret>0) { + i += bret - 1; + continue; + } else if (bret<0) { + bc_tester_helper(argv[0], liblinphone_helper); + } + return bret; + } + } + + ret = bc_tester_start(); + liblinphone_tester_uninit(); + return ret; +} +#endif diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h new file mode 100644 index 000000000..c3db2bf5e --- /dev/null +++ b/tester/liblinphone_tester.h @@ -0,0 +1,345 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#ifndef LIBLINPHONE_TESTER_H_ +#define LIBLINPHONE_TESTER_H_ + + + +#include "bc_tester_utils.h" +#include "linphonecore.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +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 test_suite_t flexisip_test_suite; +extern test_suite_t stun_test_suite; +extern test_suite_t remote_provisioning_test_suite; +extern test_suite_t quality_reporting_test_suite; +extern test_suite_t log_collection_test_suite; +extern test_suite_t tunnel_test_suite; +extern test_suite_t player_test_suite; +extern test_suite_t dtmf_test_suite; +extern test_suite_t offeranswer_test_suite; +extern test_suite_t video_test_suite; +extern test_suite_t multicast_call_test_suite; +extern test_suite_t multi_call_test_suite; +extern test_suite_t proxy_config_test_suite; +extern int manager_count; + +extern int liblinphone_tester_ipv6_available(void); + +/** + * @brief Tells the tester whether or not to clean the accounts it has created between runs. + * @details Setting this to 1 will not clear the list of created accounts between successive + * calls to liblinphone_run_tests(). Some testing APIs call this function for *each* test, + * in which case we should keep the accounts that were created for further testing. + * + * You are supposed to manually call liblinphone_tester_clear_account when all the tests are + * finished. + * + * @param keep 1 to keep the accounts in-between runs, 0 to clear them after each run. + */ +extern void liblinphone_tester_keep_accounts( int keep ); + +/** + * @brief Tells the test whether to not remove recorded audio/video files after the tests. + * @details By default recorded files are erased after the test, unless the test is failed. +**/ +void liblinphone_tester_keep_recorded_files(int keep); + +/** + * @brief Clears the created accounts during the testing session. + */ +extern void liblinphone_tester_clear_accounts(void); + + +extern const char* test_domain; +extern const char* auth_domain; +extern const char* test_username; +extern const char* test_password; +extern const char* test_route; +extern const char* userhostsfile; + + +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_LinphoneCallEarlyUpdatedByRemote; + int number_of_LinphoneCallEarlyUpdating; + + 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_LinphoneMessageReceivedWithFile; + int number_of_LinphoneMessageReceivedLegacy; + int number_of_LinphoneMessageExtBodyReceived; + int number_of_LinphoneMessageInProgress; + int number_of_LinphoneMessageDelivered; + int number_of_LinphoneMessageNotDelivered; + int number_of_LinphoneMessageFileTransferDone; + int number_of_LinphoneIsComposingActiveReceived; + int number_of_LinphoneIsComposingIdleReceived; + int progress_of_LinphoneFileTransfer; + + 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_LinphoneSubscriptionExpiring; + + int number_of_LinphonePublishProgress; + int number_of_LinphonePublishOk; + int number_of_LinphonePublishExpiring; + int number_of_LinphonePublishError; + int number_of_LinphonePublishCleared; + + int number_of_LinphoneConfiguringSkipped; + int number_of_LinphoneConfiguringFailed; + int number_of_LinphoneConfiguringSuccessful; + + int number_of_LinphoneCallEncryptedOn; + int number_of_LinphoneCallEncryptedOff; + int number_of_NetworkReachableTrue; + int number_of_NetworkReachableFalse; + int number_of_player_eof; + LinphoneChatMessage* last_received_chat_message; + + char * dtmf_list_received; + int dtmf_count; + + int number_of_LinphoneCallStatsUpdated; + int number_of_rtcp_sent; + int number_of_rtcp_received; + + int number_of_video_windows_created; + + int number_of_LinphoneFileTransferDownloadSuccessful; + int number_of_LinphoneCoreLogCollectionUploadStateDelivered; + int number_of_LinphoneCoreLogCollectionUploadStateNotDelivered; + int number_of_LinphoneCoreLogCollectionUploadStateInProgress; + int audio_download_bandwidth[3]; + int *current_audio_download_bandwidth; + int audio_upload_bandwidth[3]; + int *current_audio_upload_bandwidth; + + int video_download_bandwidth[3]; + int video_upload_bandwidth[3]; + int current_bandwidth_index; + + int number_of_rtcp_generic_nack; +}stats; + + +typedef struct _LinphoneCoreManager { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + LinphoneAddress* identity; + LinphoneEvent *lev; + bool_t decline_subscribe; + int number_of_cunit_error_at_creation; +} LinphoneCoreManager; + +typedef struct _LinphoneCallTestParams { + LinphoneCallParams *base; + bool_t sdp_removal; + bool_t sdp_simulate_error; +} LinphoneCallTestParams; + + +void liblinphone_tester_add_suites(); + +LinphoneCoreManager* linphone_core_manager_init(const char* rc_file); +void linphone_core_manager_start(LinphoneCoreManager *mgr, const char* rc_file, int check_for_proxies); +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 file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer); +LinphoneBuffer * tester_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size); +LinphoneBuffer * tester_memory_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size); +void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total); +void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); +void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +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); +void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); +void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); +void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); +void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); + +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_with_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + , const LinphoneCallParams *caller_params + , const LinphoneCallParams *callee_params); +bool_t call_with_test_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + ,const LinphoneCallTestParams *caller_test_params + ,const LinphoneCallTestParams *callee_test_params); + +bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); +bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bool_t change_video_policy); +void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2); +void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); +void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime); +stats * get_stats(LinphoneCore *lc); +bool_t transport_supported(LinphoneTransportType transport); +LinphoneCoreManager *get_manager(LinphoneCore *lc); +const char *liblinphone_tester_get_subscribe_content(void); +const char *liblinphone_tester_get_notify_content(void); +void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); +void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state); +void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee); +void liblinphone_tester_clock_start(MSTimeSpec *start); +bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms); +void linphone_core_manager_check_accounts(LinphoneCoreManager *m); +void account_manager_destroy(void); +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); +void liblinphone_tester_enable_ipv6(bool_t enabled); +void linphone_call_iframe_decoded_cb(LinphoneCall *call,void * user_data); +void call_paused_resumed_base(bool_t multicast); +void simple_call_base(bool_t enable_multicast_recv_side); +void call_base_with_configfile(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel, const char *marie_rc, const char *pauline_rc); +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel); +bool_t call_with_caller_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params); +bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,LinphoneCoreManager* mgr_2,LinphoneCall* call_2); +bool_t compare_files(const char *path1, const char *path2); +void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir); + +static const int audio_cmp_max_shift=10; + +/* + * this function return max value in the last 3 seconds*/ +int linphone_core_manager_get_max_audio_down_bw(const LinphoneCoreManager *mgr); +int linphone_core_manager_get_max_audio_up_bw(const LinphoneCoreManager *mgr); +int linphone_core_manager_get_mean_audio_down_bw(const LinphoneCoreManager *mgr); +int linphone_core_manager_get_mean_audio_up_bw(const LinphoneCoreManager *mgr); + +void video_call_base_2(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t using_policy,LinphoneMediaEncryption mode, bool_t callee_video_enabled, bool_t caller_video_enabled); + +int liblinphone_tester_setup(); +void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args)); +void liblinphone_tester_uninit(void); + +extern const char *liblinphone_tester_mire_id; + + +#ifdef __cplusplus +}; +#endif + +#endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/liblinphone_tester_windows.cpp b/tester/liblinphone_tester_windows.cpp new file mode 100644 index 000000000..30b480a8c --- /dev/null +++ b/tester/liblinphone_tester_windows.cpp @@ -0,0 +1,152 @@ +#include + +#include "liblinphone_tester_windows.h" + +using namespace liblinphone_tester_runtime_component; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Storage; +using namespace Windows::System::Threading; + +#define MAX_TRACE_SIZE 2048 +#define MAX_SUITE_NAME_SIZE 128 +#define MAX_WRITABLE_DIR_SIZE 1024 + +static OutputTraceListener^ sTraceListener; + +LibLinphoneTester^ LibLinphoneTester::_instance = ref new LibLinphoneTester(); + +static void nativeOutputTraceHandler(int lev, const char *fmt, va_list args) +{ + if (sTraceListener) { + wchar_t wstr[MAX_TRACE_SIZE] = { 0 }; + std::string str; + str.resize(MAX_TRACE_SIZE); + vsnprintf((char *)str.c_str(), MAX_TRACE_SIZE, fmt, args); + mbstowcs(wstr, str.c_str(), MAX_TRACE_SIZE - 1); + String^ msg = ref new String(wstr); + String^ l; + switch (lev) { + case ORTP_FATAL: + case ORTP_ERROR: + l = ref new String(L"Error"); + break; + case ORTP_WARNING: + l = ref new String(L"Warning"); + break; + case ORTP_MESSAGE: + l = ref new String(L"Message"); + break; + default: + l = ref new String(L"Debug"); + break; + } + sTraceListener->outputTrace(l, msg); + } +} + +static void libLinphoneNativeOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +{ + nativeOutputTraceHandler((int)lev, fmt, args); +} + + +LibLinphoneTester::LibLinphoneTester() +{ + liblinphone_tester_init(nativeOutputTraceHandler); + bc_tester_set_resource_dir_prefix("Assets"); +} + +LibLinphoneTester::~LibLinphoneTester() +{ + liblinphone_tester_uninit(); +} + +void LibLinphoneTester::setWritableDirectory(StorageFolder^ folder) +{ + char writable_dir[MAX_WRITABLE_DIR_SIZE] = { 0 }; + const wchar_t *wwritable_dir = folder->Path->Data(); + wcstombs(writable_dir, wwritable_dir, sizeof(writable_dir)); + bc_tester_set_writable_dir_prefix(writable_dir); +} + +void LibLinphoneTester::setOutputTraceListener(OutputTraceListener^ traceListener) +{ + sTraceListener = traceListener; +} + +void LibLinphoneTester::init(bool verbose) +{ + if (verbose) { + linphone_core_set_log_level_mask((OrtpLogLevel)(ORTP_MESSAGE | ORTP_WARNING | ORTP_ERROR | ORTP_FATAL)); + } + else { + linphone_core_set_log_level_mask(ORTP_FATAL); + } +} + +bool LibLinphoneTester::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)); + + init(verbose); + linphone_core_set_log_handler(libLinphoneNativeOutputTraceHandler); + return bc_tester_run_tests(wssuitename == all ? 0 : csuitename, wscasename == all ? 0 : ccasename) != 0; +} + +void LibLinphoneTester::runAllToXml() +{ + auto workItem = ref new WorkItemHandler([this](IAsyncAction ^workItem) { + char *xmlFile = bc_tester_file("LibLinphoneWindows10.xml"); + char *logFile = bc_tester_file("LibLinphoneWindows10.log"); + char *args[] = { "--xml-file", xmlFile }; + bc_tester_parse_args(2, args, 0); + init(true); + FILE *f = fopen(logFile, "w"); + ortp_set_log_file(f); + bc_tester_start(); + bc_tester_uninit(); + fclose(f); + free(xmlFile); + free(logFile); + }); + _asyncAction = ThreadPool::RunAsync(workItem); +} + +unsigned int LibLinphoneTester::nbTestSuites() +{ + return bc_tester_nb_suites(); +} + +unsigned int LibLinphoneTester::nbTests(Platform::String^ suiteName) +{ + std::wstring suitename = suiteName->Data(); + char cname[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(cname, suitename.c_str(), sizeof(cname)); + return bc_tester_nb_tests(cname); +} + +Platform::String^ LibLinphoneTester::testSuiteName(int index) +{ + const char *cname = bc_tester_suite_name(index); + wchar_t wcname[MAX_SUITE_NAME_SIZE]; + mbstowcs(wcname, cname, sizeof(wcname)); + return ref new String(wcname); +} + +Platform::String^ LibLinphoneTester::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 = bc_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/tester/liblinphone_tester_windows.h b/tester/liblinphone_tester_windows.h new file mode 100644 index 000000000..08d60ddfd --- /dev/null +++ b/tester/liblinphone_tester_windows.h @@ -0,0 +1,42 @@ +#pragma once + +#include "linphonecore.h" +#include "liblinphone_tester.h" + +namespace liblinphone_tester_runtime_component +{ + public interface class OutputTraceListener + { + public: + void outputTrace(Platform::String^ lev, Platform::String^ msg); + }; + + public ref class LibLinphoneTester sealed + { + public: + void setWritableDirectory(Windows::Storage::StorageFolder^ folder); + 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); + bool run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose); + void runAllToXml(); + + static property LibLinphoneTester^ Instance + { + LibLinphoneTester^ get() { return _instance; } + } + property Windows::Foundation::IAsyncAction^ AsyncAction + { + Windows::Foundation::IAsyncAction^ get() { return _asyncAction; } + } + private: + LibLinphoneTester(); + ~LibLinphoneTester(); + void init(bool verbose); + + static LibLinphoneTester^ _instance; + Windows::Foundation::IAsyncAction^ _asyncAction; + }; +} \ No newline at end of file diff --git a/tester/local_tester_hosts b/tester/local_tester_hosts new file mode 100644 index 000000000..de1edc48c --- /dev/null +++ b/tester/local_tester_hosts @@ -0,0 +1 @@ +127.0.0.1 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/log_collection_tester.c b/tester/log_collection_tester.c new file mode 100644 index 000000000..4beabef73 --- /dev/null +++ b/tester/log_collection_tester.c @@ -0,0 +1,334 @@ +/* + Linphone + Copyright (C) 2014 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _XOPEN_SOURCE + #define _XOPEN_SOURCE 700 // To have definition of strptime, snprintf and getline +#endif +#include +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +#ifdef HAVE_ZLIB +#include +#endif + + +/*getline is POSIX 2008, not available on many systems.*/ +#if defined(ANDROID) || defined(_WIN32) +/* This code is public domain -- Will Hartung 4/9/09 */ +static size_t getline(char **lineptr, size_t *n, FILE *stream) { + char *bufptr = NULL; + char *p = bufptr; + size_t size; + int c; + + if (lineptr == NULL) { + return -1; + } + if (stream == NULL) { + return -1; + } + if (n == NULL) { + return -1; + } + bufptr = *lineptr; + size = *n; + + c = fgetc(stream); + if (c == EOF) { + return -1; + } + if (bufptr == NULL) { + bufptr = malloc(128); + if (bufptr == NULL) { + return -1; + } + size = 128; + } + p = bufptr; + while(c != EOF) { + size_t curpos = p-bufptr; + + if (curpos > (size - 1)) { + size = size + 128; + bufptr = realloc(bufptr, size); + p = bufptr + curpos; + if (bufptr == NULL) { + return -1; + } + } + *p++ = c; + if (c == '\n') { + break; + } + c = fgetc(stream); + } + + *p++ = '\0'; + *lineptr = bufptr; + *n = size; + + return p - bufptr - 1; +} +#endif + +static LinphoneLogCollectionState old_collection_state; +static void collect_init() { + old_collection_state = linphone_core_log_collection_enabled(); + linphone_core_set_log_collection_path(bc_tester_get_writable_dir_prefix()); +} + +static void collect_cleanup(LinphoneCoreManager *marie) { + linphone_core_manager_destroy(marie); + + linphone_core_enable_log_collection(old_collection_state); + linphone_core_reset_log_collection(); +} + +static LinphoneCoreManager* setup(bool_t enable_logs) { + LinphoneCoreManager *marie; + int timeout = 300; + + collect_init(); + linphone_core_enable_log_collection(enable_logs); + + marie = linphone_core_manager_new2( "marie_rc", 0); + // wait a few seconds to generate some traffic + while (--timeout){ + // Generate some logs - error logs because we must ensure that + // even if user did not enable logs, we will see them + ms_error("(test error)Timeout in %d...", timeout); + } + return marie; +} + +#if HAVE_ZLIB + +/*returns uncompressed log file*/ +static FILE* gzuncompress(const char* filepath) { + gzFile file = gzopen(filepath, "rb"); + FILE *output = NULL; + FILE *ret; + char *newname = ms_strdup_printf("%s.txt", filepath); + char buffer[512]={0}; + output = fopen(newname, "wb"); + while (gzread(file, buffer, 511) > 0) { + fputs(buffer, output); + memset(buffer, 0, strlen(buffer)); + } + fclose(output); + BC_ASSERT_EQUAL(gzclose(file), Z_OK, int, "%d"); + ret=fopen(newname, "rb"); + ms_free(newname); + return ret; +} +#endif + +static time_t get_current_time() { + struct timeval tp; + struct tm *lt; +#ifndef _WIN32 + struct tm tmbuf; +#endif + time_t tt; + ortp_gettimeofday(&tp,NULL); + tt = (time_t)tp.tv_sec; + +#ifdef _WIN32 + lt = localtime(&tt); +#else + lt = localtime_r(&tt,&tmbuf); +#endif + return mktime(lt); +} + +static time_t check_file(LinphoneCoreManager* mgr) { + + time_t cur_time = get_current_time(); + char* filepath = linphone_core_compress_log_collection(mgr->lc); + time_t log_time = -1; + uint32_t timediff = 0; + FILE *file = NULL; + + BC_ASSERT_PTR_NOT_NULL(filepath); + + if (filepath != NULL) { + int line_count = 0; + char *line = NULL; + size_t line_size = 256; +#ifndef _WIN32 + struct tm tm_curr = {0}; + time_t time_prev = 0; +#endif + +#if HAVE_ZLIB + // 0) if zlib is enabled, we must decompress the file first + file = gzuncompress(filepath); +#else + file = fopen(filepath, "rb"); +#endif + BC_ASSERT_PTR_NOT_NULL(file); + if (!file) return 0; + // 1) expect to find folder name in filename path + BC_ASSERT_PTR_NOT_NULL(strstr(filepath, bc_tester_get_writable_dir_prefix())); + + // 2) check file contents + while (getline(&line, &line_size, file) != -1) { + // a) there should be at least 25 lines + ++line_count; +#ifndef _WIN32 + // b) logs should be ordered by date (format: 2014-11-04 15:22:12:606) + if (strlen(line) > 24) { + char date[24] = {'\0'}; + memcpy(date, line, 23); + /*reset tm_curr to reset milliseconds and below fields*/ + memset(&tm_curr, 0, sizeof(struct tm)); + if (strptime(date, "%Y-%m-%d %H:%M:%S", &tm_curr) != NULL) { + tm_curr.tm_isdst = -1; // LOL + log_time = mktime(&tm_curr); + BC_ASSERT_GREATER(log_time , time_prev, long int, "%ld"); + time_prev = log_time; + } + } +#endif + } + BC_ASSERT_GREATER(line_count , 25, int, "%d"); + free(line); + fclose(file); + ms_free(filepath); + + + timediff = labs((long int)log_time - (long int)cur_time); + (void)timediff; +#ifndef _WIN32 + BC_ASSERT_LOWER(timediff, 1, unsigned, "%u"); + if( !(timediff <= 1) ){ + char buffers[2][128] = {{0}}; + strftime(buffers[0], sizeof(buffers[0]), "%Y-%m-%d %H:%M:%S", localtime(&log_time)); + strftime(buffers[1], sizeof(buffers[1]), "%Y-%m-%d %H:%M:%S", localtime(&cur_time)); + + ms_error("log_time: %ld (%s), cur_time: %ld (%s) timediff: %u" + , (long int)log_time, buffers[0] + , (long int)cur_time, buffers[1] + , timediff + ); + } +#else + ms_warning("strptime() not available for this platform, test is incomplete."); +#endif + } + // return latest time in file + return log_time; +} + +static void collect_files_disabled() { + LinphoneCoreManager* marie = setup(FALSE); + BC_ASSERT_PTR_NULL(linphone_core_compress_log_collection(marie->lc)); + collect_cleanup(marie); +} + +static void collect_files_filled() { + LinphoneCoreManager* marie = setup(TRUE); + check_file(marie); + collect_cleanup(marie); +} + +static void collect_files_small_size() { + LinphoneCoreManager* marie = setup(TRUE); + linphone_core_set_log_collection_max_file_size(5000); + check_file(marie); + collect_cleanup(marie); +} + +static void collect_files_changing_size() { + LinphoneCoreManager* marie = setup(TRUE); + int waiting = 100; + + check_file(marie); + + linphone_core_set_log_collection_max_file_size(5000); + // Generate some logs + while (--waiting) ms_error("(test error)Waiting %d...", waiting); + + check_file(marie); + + collect_cleanup(marie); +} +static void logCollectionUploadStateChangedCb(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) { + + stats* counters = get_stats(lc); + ms_message("lc [%p], logCollectionUploadStateChanged to [%s], info [%s]",lc + ,linphone_core_log_collection_upload_state_to_string(state) + ,info); + switch(state) { + case LinphoneCoreLogCollectionUploadStateInProgress: + counters->number_of_LinphoneCoreLogCollectionUploadStateInProgress++; + break; + case LinphoneCoreLogCollectionUploadStateDelivered: + counters->number_of_LinphoneCoreLogCollectionUploadStateDelivered++; + BC_ASSERT_GREATER(strlen(info), 0, int, "%d"); + break; + case LinphoneCoreLogCollectionUploadStateNotDelivered: + counters->number_of_LinphoneCoreLogCollectionUploadStateNotDelivered++; + break; + } +} +static void upload_collected_traces() { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = setup(TRUE); + int waiting = 100; + LinphoneCoreVTable *v_table = linphone_core_v_table_new(); + v_table->log_collection_upload_state_changed = logCollectionUploadStateChangedCb; + linphone_core_add_listener(marie->lc, v_table); + + linphone_core_set_log_collection_max_file_size(5000); + linphone_core_set_log_collection_upload_server_url(marie->lc,"https://www.linphone.org:444/lft.php"); + // Generate some logs + while (--waiting) ms_error("(test error)Waiting %d...", waiting); + linphone_core_compress_log_collection(marie->lc); + linphone_core_upload_log_collection(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCoreLogCollectionUploadStateDelivered,1)); + + /*try 2 times*/ + waiting=100; + linphone_core_reset_log_collection(marie->lc); + while (--waiting) ms_error("(test error)Waiting %d...", waiting); + linphone_core_compress_log_collection(marie->lc); + linphone_core_upload_log_collection(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCoreLogCollectionUploadStateDelivered,2)); + collect_cleanup(marie); + } +} + +test_t log_collection_tests[] = { + { "No file when disabled", collect_files_disabled}, + { "Collect files filled when enabled", collect_files_filled}, + { "Logs collected into small file", collect_files_small_size}, + { "Logs collected when decreasing max size", collect_files_changing_size}, + { "Upload collected traces", upload_collected_traces} +}; + +test_suite_t log_collection_test_suite = { + "LogCollection", + liblinphone_tester_setup, + NULL, + sizeof(log_collection_tests) / sizeof(log_collection_tests[0]), + log_collection_tests +}; + diff --git a/tester/marie_xml b/tester/marie_xml new file mode 100644 index 000000000..5818930ba --- /dev/null +++ b/tester/marie_xml @@ -0,0 +1,50 @@ + + +
    + -1 + -1 + -1 + 0 + 0 + 0 + 1 +
    +
    + marie + marie + secret + sip.example.org +
    +
    + sip.example.org;transport=tcp + sip.example.org;transport=tcp;lr + sip:marie@sip.example.org + 3600 + 1 + 0 + 0 +
    +
    + "Paupoche" <sip:pauline@sip.example.org> + accept + 0 +
    +
    + 8070 + 9072 +
    +
    + 0 + 0 + 0 + vga + 0 + 0 + 0 + 0 + StaticImage: Static picture +
    +
    + 0 #to not overload cpu in case of VG +
    +
    diff --git a/tester/message_tester.c b/tester/message_tester.c new file mode 100644 index 000000000..c82388235 --- /dev/null +++ b/tester/message_tester.c @@ -0,0 +1,1688 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + + +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "lime.h" + +#ifdef MSG_STORAGE_ENABLED +#include +#endif + + +static char* message_external_body_url=NULL; + +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; + const char *text=linphone_chat_message_get_text(message); + const char *external_body_url=linphone_chat_message_get_external_body_url(message); + ms_message("Message from [%s] is [%s] , external URL [%s]",from?from:"" + ,text?text:"" + ,external_body_url?external_body_url:""); + ms_free(from); + counters = get_stats(lc); + counters->number_of_LinphoneMessageReceived++; + if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message); + counters->last_received_chat_message=linphone_chat_message_ref(message); + if (linphone_chat_message_get_file_transfer_information(message)) { + counters->number_of_LinphoneMessageReceivedWithFile++; + } else if (linphone_chat_message_get_external_body_url(message)) { + counters->number_of_LinphoneMessageExtBodyReceived++; + if (message_external_body_url) { + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + message_external_body_url=NULL; + } + } +} + +/** + * function invoked when a file transfer is received. + * */ +void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer){ + FILE* file=NULL; + char *receive_file = bc_tester_file("receive_file.dump"); + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(message); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk, creating file*/ + file = fopen(receive_file,"wb"); + linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/ + } + ms_free(receive_file); + file = (FILE*)linphone_chat_message_get_user_data(message); + + if (linphone_buffer_is_empty(buffer)) { /* tranfer complete */ + stats* counters = get_stats(lc); + counters->number_of_LinphoneFileTransferDownloadSuccessful++; + fclose(file); + } else { /* store content on a file*/ + if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==-1){ + ms_error("file_transfer_received(): write() failed: %s",strerror(errno)); + } + } +} + +char big_file[128000]; /* a buffer to simulate a big file for the file transfer message test */ + +/* + * function called when the file transfer is initiated. file content should be feed into object LinphoneContent + * */ +LinphoneBuffer * tester_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){ + LinphoneBuffer *lb; + size_t file_size; + size_t size_to_send; + FILE *file_to_send; + uint8_t *buf; + + file_to_send = linphone_chat_message_get_user_data(message); + fseek(file_to_send, 0, SEEK_END); + file_size = ftell(file_to_send); + fseek(file_to_send, offset, SEEK_SET); + size_to_send = MIN(size, file_size - offset); + buf = ms_malloc(size_to_send); + if (fread(buf, size_to_send, 1, file_to_send)!=size_to_send){ + // reaching end of file + } + lb = linphone_buffer_new_from_data(buf, size_to_send); + ms_free(buf); + return lb; +} + +LinphoneBuffer * tester_memory_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size){ + size_t size_to_send = MIN(size, sizeof(big_file) - offset); + return linphone_buffer_new_from_data((uint8_t *)big_file + offset, size_to_send); +} + +/** + * function invoked to report file transfer progress. + * */ +void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(message); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + const LinphoneAddress* from_address = linphone_chat_message_get_from(message); + const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); + stats* counters = get_stats(lc); + int progress = (int)((offset * 100)/total); + ms_message(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", progress + ,(linphone_chat_message_is_outgoing(message)?"sent":"received") + , linphone_content_get_type(content) + , linphone_content_get_subtype(content) + ,(linphone_chat_message_is_outgoing(message)?"to":"from") + , address); + counters->progress_of_LinphoneFileTransfer = progress; + free(address); +} + +void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + stats *counters = get_stats(lc); + if (room->remote_is_composing == LinphoneIsComposingActive) { + counters->number_of_LinphoneIsComposingActiveReceived++; + } else { + counters->number_of_LinphoneIsComposingIdleReceived++; + } +} + +void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + liblinphone_tester_chat_message_msg_state_changed(msg, state); +} + +void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state) { + LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg); + LinphoneCore *lc = linphone_chat_room_get_core(cr); + stats* counters = get_stats(lc); + const char *text = linphone_chat_message_get_text(msg); + if (!text) text = ""; + ms_message("Message [%s] [%s]",text, linphone_chat_message_state_to_string(state)); + switch (state) { + case LinphoneChatMessageStateIdle: + return; + case LinphoneChatMessageStateDelivered: + counters->number_of_LinphoneMessageDelivered++; + return; + case LinphoneChatMessageStateNotDelivered: + counters->number_of_LinphoneMessageNotDelivered++; + return; + case LinphoneChatMessageStateInProgress: + counters->number_of_LinphoneMessageInProgress++; + return; + case LinphoneChatMessageStateFileTransferError: + counters->number_of_LinphoneMessageNotDelivered++; + return; + case LinphoneChatMessageStateFileTransferDone: + counters->number_of_LinphoneMessageFileTransferDone++; + return; + } + 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_tcp_rc"); + LinphoneChatRoom* chat_room; + + chat_room = linphone_core_get_chat_room(pauline->lc,marie->identity); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1, int, "%d"); + + BC_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_within_dialog(void) { + LinphoneChatRoom* chat_room; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1); + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + BC_ASSERT_TRUE(call(marie,pauline)); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static LinphoneAuthInfo* text_message_with_credential_from_auth_cb_auth_info; +static void text_message_with_credential_from_auth_cb_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + ms_message("text_message_with_credential_from_auth_cb:Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + linphone_core_add_auth_info(lc,text_message_with_credential_from_auth_cb_auth_info); /*add stored authentication info to LinphoneCore*/ +} + + +static void text_message_with_credential_from_auth_cb(void) { + LinphoneChatRoom* chat_room; + LinphoneCoreVTable* vtable = linphone_core_v_table_new(); + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + text_message_with_credential_from_auth_cb_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(pauline->lc)->data)); + + /*to force cb to be called*/ + linphone_core_clear_all_auth_info(pauline->lc); + vtable->auth_info_requested=text_message_with_credential_from_auth_cb_auth_info_requested; + linphone_core_add_listener(pauline->lc, vtable); + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1, int, "%d"); + + BC_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) { + LinphoneChatRoom* chat_room; + + LinphoneProxyConfig* pauline_proxy; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /*test proxy config privacy*/ + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1, int, "%d"); + + 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_tcp_rc"); + LinphoneProxyConfig* proxy; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + LinphoneChatRoom* chat_room; + + linphone_core_get_default_proxy(marie->lc,&proxy); + BC_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; + + BC_ASSERT_TRUE (wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,1)); + + chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceivedLegacy,1, int, "%d"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_ack(void) { + int leaked_objects; + int begin; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + { + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + } + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void text_message_with_external_body(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); + + linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); + + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); + + /* check transient message list: the message should be in it, and should be the only one */ + BC_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1, int, "%d"); + BC_ASSERT_PTR_EQUAL(ms_list_nth_data(chat_room->transient_messages,0), message); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1, int, "%d"); + + BC_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 0, int, "%d"); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +bool_t compare_files(const char *path1, const char *path2) { + bool_t res; + size_t size1; + size_t size2; + uint8_t *buf1; + uint8_t *buf2; + + buf1 = (uint8_t*)ms_load_path_content(path1, &size1); + buf2 = (uint8_t*)ms_load_path_content(path2, &size2); + res = buf1 && buf2 && (size1 == size2) && (memcmp(buf1, buf2, size1) == 0); + ms_free(buf1); + ms_free(buf2); + return res; +} + +static void file_transfer_message(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + FILE *file_to_send = NULL; + size_t file_size; + char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg"); + char *receive_filepath = bc_tester_file("receive_file.dump"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + file_to_send = fopen(send_filepath, "rb"); + fseek(file_to_send, 0, SEEK_END); + file_size = ftell(file_to_send); + fseek(file_to_send, 0, SEEK_SET); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"image"); + linphone_content_set_subtype(content,"jpeg"); + linphone_content_set_size(content,file_size); /*total size to be transfered*/ + linphone_content_set_name(content,"nowebcamCIF.jpg"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + linphone_chat_message_set_user_data(message, file_to_send); + cbs = linphone_chat_message_get_callbacks(message); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_file_transfer_send); + linphone_chat_room_send_chat_message(chat_room,message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + fclose(file_to_send); + if (marie->stat.last_received_chat_message ) { + cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1, int, "%d"); + BC_ASSERT_TRUE(compare_files(send_filepath, receive_filepath)); + + linphone_content_unref(content); + linphone_core_manager_destroy(pauline); + ms_free(send_filepath); + ms_free(receive_filepath); + linphone_core_manager_destroy(marie); + } +} + +/* same than previous but with a 160 characters file */ +#define SMALL_FILE_SIZE 160 +static void small_file_transfer_message(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + int i; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"text"); + linphone_content_set_subtype(content,"plain"); + linphone_content_set_size(content,SMALL_FILE_SIZE); /*total size to be transfered*/ + linphone_content_set_name(content,"bigfile.txt"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_memory_file_transfer_send); + linphone_chat_room_send_chat_message(chat_room,message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + if (marie->stat.last_received_chat_message ) { + cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1, int, "%d"); + + linphone_content_unref(content); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + +#ifdef HAVE_LIME + +static FILE* fopen_from_write_dir(const char * name, const char * mode) { + char *filepath = bc_tester_file(name); + FILE * file = fopen(filepath,mode); + ms_free(filepath); + return file; +} + +static void lime_file_transfer_message_base(bool_t encrypt_file) { + int i; + FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD; + LinphoneCoreManager *marie, *pauline; + LinphoneChatRoom *chat_room; + LinphoneContent *content; + LinphoneChatMessage *message; + LinphoneChatMessageCbs *cbs; + char *pauline_id, *marie_id; + char *filepath; + + /* setting dummy file content to something */ + const char* big_file_content="big file"; + for (i=0;istat); + reset_counters(&pauline->stat); + + /* make sure lime is enabled */ + linphone_core_enable_lime(marie->lc, 1); + linphone_core_enable_lime(pauline->lc, 1); + if (!encrypt_file) { + LpConfig *pauline_lp = linphone_core_get_config(pauline->lc); + lp_config_set_int(pauline_lp,"sip","lime_for_file_sharing",0); + } + + /* set the zid caches files : create two ZID cache from this valid one inserting the auto-generated sip URI for the peer account as keys in ZID cache are indexed by peer sip uri */ + ZIDCacheMarieFD = fopen_from_write_dir("tmpZIDCacheMarie.xml", "wb"); + ZIDCachePaulineFD = fopen_from_write_dir("tmpZIDCachePauline.xml", "wb"); + pauline_id = linphone_address_as_string_uri_only(pauline->identity); + marie_id = linphone_address_as_string_uri_only(marie->identity); + fprintf(ZIDCacheMarieFD, "\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778csal_set_uuid(lc->sal, account->instance_id);bdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000", pauline_id, pauline_id); + fprintf(ZIDCachePaulineFD, "\n005dbe0399643d953a2202ddef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001", marie_id, marie_id); + fclose(ZIDCacheMarieFD); + fclose(ZIDCachePaulineFD); + ms_free(marie_id); + ms_free(pauline_id); + + filepath = bc_tester_file("tmpZIDCacheMarie.xml"); + linphone_core_set_zrtp_secrets_file(marie->lc, filepath); + ms_free(filepath); + + filepath = bc_tester_file("tmpZIDCachePauline.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, filepath); + ms_free(filepath); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"text"); + linphone_content_set_subtype(content,"plain"); + linphone_content_set_size(content,sizeof(big_file)); /*total size to be transfered*/ + linphone_content_set_name(content,"big_file.txt"); + + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_memory_file_transfer_send); + linphone_chat_room_send_chat_message(chat_room,message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + if (marie->stat.last_received_chat_message ) { + cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1, int, "%d"); + + linphone_content_unref(content); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} +static void lime_file_transfer_message() { + lime_file_transfer_message_base(TRUE); +} + +static void lime_file_transfer_message_without_encryption() { + lime_file_transfer_message_base(FALSE); +} + +static void printHex(char *title, uint8_t *data, uint32_t length) { + int i; + char debug_string_buffer[2048]; + char *debug_string = debug_string_buffer; + sprintf (debug_string, "%s : ", title); + debug_string += strlen(title)+3; + for (i=0; i\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com963c57bb28e62068d2df23e8f9b771932d3c57bb28e62068d2df23e8f9b7719305d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b771935f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719302ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000069000001e8011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899pipo1@pipo.com123456789012345678901234567890123456765431262068d2df23e8f9b7719325d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193000000010000000001"); + fclose(CACHE); + CACHE = fopen_from_write_dir("ZIDCache.xml", "rb+"); + cacheBufferString = (uint8_t*) ms_load_file_content(CACHE, &size); + *(cacheBufferString+size) = '\0'; + fclose(CACHE); + /* parse it to an xmlDoc */ + cacheBuffer = xmlParseDoc(cacheBufferString); + ms_free(cacheBufferString); + + /* get data from cache : sender */ + associatedKeys.peerURI = (uint8_t *)malloc(15); + memcpy(associatedKeys.peerURI, "pipo1@pipo.com", 15); + associatedKeys.associatedZIDNumber = 0; + retval = lime_getCachedSndKeysByURI(cacheBuffer, &associatedKeys); + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + BC_ASSERT_EQUAL_FATAL(associatedKeys.associatedZIDNumber, 2, int, "%d"); /* there are 2 keys associated to pipo1@pipo.com address in the cache above*/ + ms_message("Get cached key by URI, for sender, return %d keys", associatedKeys.associatedZIDNumber); + + for (i=0; ipeerZID, 12); + printHex("key", associatedKeys.peerKeys[i]->key, 32); + printHex("sessionID", associatedKeys.peerKeys[i]->sessionId, 32); + ms_message("session index %d\n", associatedKeys.peerKeys[i]->sessionIndex); + } + + /* get data from cache : receiver */ + memcpy(associatedKey.peerZID, targetZID, 12); + retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + printHex("Got receiver key for ZID", targetZID, 12); + printHex("Key", associatedKey.key, 32); + printHex("sessionID", associatedKey.sessionId, 32); + ms_message("session index %d\n", associatedKey.sessionIndex); + + /* encrypt/decrypt a message */ + lime_encryptMessage(associatedKeys.peerKeys[0], (uint8_t *)PLAIN_TEXT_TEST_MESSAGE, strlen(PLAIN_TEXT_TEST_MESSAGE), senderZID, encryptedMessage); + printHex("Ciphered", encryptedMessage, strlen((char *)encryptedMessage)); + /* invert sender and receiverZID to decrypt/authenticate */ + memcpy(receiverZID, associatedKeys.peerKeys[0]->peerZID, 12); + memcpy(associatedKeys.peerKeys[0]->peerZID, senderZID, 12); + retval = lime_decryptMessage(associatedKeys.peerKeys[0], encryptedMessage, strlen(PLAIN_TEXT_TEST_MESSAGE)+16, receiverZID, plainMessage); + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + BC_ASSERT_STRING_EQUAL((char *)plainMessage, (char *)PLAIN_TEXT_TEST_MESSAGE); + ms_message("Decrypt and auth returned %d\nPlain text is %s\n", retval, plainMessage); + + /* update receiver data */ + associatedKey.sessionIndex++; + associatedKey.key[0]++; + associatedKey.sessionId[0]++; + retval = lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + + /* update sender data */ + associatedKeys.peerKeys[0]->sessionIndex++; + associatedKeys.peerKeys[0]->key[0]++; + associatedKeys.peerKeys[0]->sessionId[0]++; + retval = lime_setCachedKey(cacheBuffer, associatedKeys.peerKeys[0], LIME_SENDER); + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + + /* free memory */ + lime_freeKeys(associatedKeys); + + /* write the file */ + /* dump the xml document into a string */ + xmlDocDumpFormatMemoryEnc(cacheBuffer, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the file */ + CACHE = fopen_from_write_dir("ZIDCache.xml", "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHE); + xmlFree(xmlStringOutput); + fclose(CACHE); + xmlFreeDoc(cacheBuffer); + + /**** Higher level tests using 2 caches to encrypt/decrypt a message ****/ + /* Create Alice cache file and then load it */ + CACHE = fopen_from_write_dir("ZIDCacheAlice.xml", "wb"); + fprintf(CACHE, "\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org9111ebeb52e50edcc6fcb3eea1a2d3ae3c2c75d3668923e83c59d0f47245515060f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000080000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:pauline@sip.example.org72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000"); + fclose(CACHE); + CACHE = fopen_from_write_dir("ZIDCacheAlice.xml", "rb+"); + cacheBufferString = (uint8_t *)ms_load_file_content(CACHE, &size); + *(cacheBufferString+size) = '\0'; + fclose(CACHE); + /* parse it to an xmlDoc */ + cacheBufferAlice = xmlParseDoc(cacheBufferString); + ms_free(cacheBufferString); + + /* Create Bob cache file and then load it */ + CACHE = fopen_from_write_dir("ZIDCacheBob.xml", "wb"); + fprintf(CACHE, "\n005dbe0399643d953a2202ddef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org9111ebeb52e50edcc6fcb3eea1a2d3ae3c2c75d3668923e83c59d0f47245515060f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000080000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899sip:marie@sip.example.org81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001"); + fclose(CACHE); + CACHE = fopen_from_write_dir("ZIDCacheBob.xml", "rb+"); + cacheBufferString = (uint8_t *)ms_load_file_content(CACHE, &size); + *(cacheBufferString+size) = '\0'; + fclose(CACHE); + /* parse it to an xmlDoc */ + cacheBufferBob = xmlParseDoc(cacheBufferString); + ms_free(cacheBufferString); + + + + /* encrypt a message */ + retval = lime_createMultipartMessage(cacheBufferAlice, (uint8_t *)PLAIN_TEXT_TEST_MESSAGE, (uint8_t *)"sip:pauline@sip.example.org", &multipartMessage); + + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + if (retval == 0) { + ms_message("Encrypted message created is %s", multipartMessage); + } + + /* decrypt the multipart message */ + retval = lime_decryptMultipartMessage(cacheBufferBob, multipartMessage, &decryptedMessage); + + BC_ASSERT_EQUAL_FATAL(retval, 0, int, "%d"); + if (retval == 0) { + BC_ASSERT_STRING_EQUAL((char *)decryptedMessage, (char *)PLAIN_TEXT_TEST_MESSAGE); + ms_message("Succesfully decrypted message is %s", decryptedMessage); + } + free(multipartMessage); + free(decryptedMessage); + + /* update ZID files */ + /* dump the xml document into a string */ + xmlDocDumpFormatMemoryEnc(cacheBufferAlice, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the file */ + CACHE = fopen_from_write_dir("ZIDCacheAlice.xml", "wb+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHE); + xmlFree(xmlStringOutput); + fclose(CACHE); + + xmlDocDumpFormatMemoryEnc(cacheBufferBob, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the file */ + CACHE = fopen_from_write_dir("ZIDCacheBob.xml", "wb+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHE); + xmlFree(xmlStringOutput); + fclose(CACHE); + + + xmlFreeDoc(cacheBufferAlice); + xmlFreeDoc(cacheBufferBob); +} + +static void lime_text_message(void) { + FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD; + LinphoneChatRoom* chat_room; + char* filepath; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + /* make sure lime is enabled */ + linphone_core_enable_lime(marie->lc, 1); + linphone_core_enable_lime(pauline->lc, 1); + + /* set the zid caches files : create two ZID cache from this valid one inserting the auto-generated sip URI for the peer account as keys in ZID cache are indexed by peer sip uri */ + ZIDCacheMarieFD = fopen_from_write_dir("tmpZIDCacheMarie.xml", "w"); + ZIDCachePaulineFD = fopen_from_write_dir("tmpZIDCachePauline.xml", "w"); + fprintf(ZIDCacheMarieFD, "\nef7692d0792a67491ae2d44e005dbe0399643d953a2202dd9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a917625d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000000f00000000", linphone_address_as_string_uri_only(pauline->identity), linphone_address_as_string_uri_only(pauline->identity)); + fprintf(ZIDCachePaulineFD, "\n005dbe0399643d953a2202ddef7692d0792a67491ae2d44e9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s08df5907d30959b8cb70f6fff2d8febd88fb41b0c8afc39e4b972f86dd5cfe2d60f020a3fe11dc2cc0e1e8ed9341b4cd14944db806ca4fc95456bbe45d95c43a5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b7719300000078000001cf011234567889643d953a2202ee9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899%s81e6e6362c34dc974263d1f77cbb9a8d6d6a718330994379099a8fa19fb12faa25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b7719322ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b771930000002e0000000001", linphone_address_as_string_uri_only(marie->identity), linphone_address_as_string_uri_only(marie->identity)); + fclose(ZIDCacheMarieFD); + fclose(ZIDCachePaulineFD); + + filepath = bc_tester_file("tmpZIDCacheMarie.xml"); + linphone_core_set_zrtp_secrets_file(marie->lc, filepath); + ms_free(filepath); + + filepath = bc_tester_file("tmpZIDCachePauline.xml"); + linphone_core_set_zrtp_secrets_file(pauline->lc, filepath); + ms_free(filepath); + + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedLegacy,1)); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + /* TODO : check the message arrived correctly deciphered */ + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#endif /* HAVE_LIME */ + +static void file_transfer_message_io_error_upload(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + int i; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* setting dummy file content to something */ + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"text"); + linphone_content_set_subtype(content,"plain"); + linphone_content_set_size(content,sizeof(big_file)); /*total size to be transfered*/ + linphone_content_set_name(content,"bigfile.txt"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_memory_file_transfer_send); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + linphone_chat_room_send_chat_message(chat_room,message); + + /*wait for file to be 25% uploaded and simultate a network error*/ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer,25)); + sal_set_send_error(pauline->lc->sal, -1); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d"); + + sal_set_send_error(pauline->lc->sal, 0); + + linphone_core_refresh_registers(pauline->lc); /*to make sure registration is back in registered and so it can be later unregistered*/ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneRegistrationOk,pauline->stat.number_of_LinphoneRegistrationOk+1)); + + linphone_content_unref(content); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + + +#ifdef TEST_IS_BUGGED_NO_CALL_TO_IO_ERROR_CALLBACK +static void file_transfer_message_io_error_download(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + int i; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneContent content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* setting dummy file content to something */ + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /* create a file transfer message */ + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; + message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + /* wait for marie to receive pauline's message */ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + + + if (marie->stat.last_received_chat_message ) { /* get last message and use it to download file */ + linphone_chat_message_start_file_download(marie->stat.last_received_chat_message, liblinphone_tester_chat_message_state_change, marie->lc); + /* wait for file to be 50% downloaded */ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.progress_of_LinphoneFileTransfer, 50)); + /* and simulate network error */ + sal_set_recv_error(marie->lc->sal, -1); + } + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageNotDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d"); + + sal_set_recv_error(marie->lc->sal, 0); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} +#endif + +static void file_transfer_message_upload_cancelled(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + int i; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* setting dummy file content to something */ + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"text"); + linphone_content_set_subtype(content,"plain"); + linphone_content_set_size(content,sizeof(big_file)); /*total size to be transfered*/ + linphone_content_set_name(content,"bigfile.txt"); + message = linphone_chat_room_create_file_transfer_message(chat_room, content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_memory_file_transfer_send); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + linphone_chat_room_send_chat_message(chat_room,message); + + /*wait for file to be 50% uploaded and cancel the transfer */ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer, 50)); + linphone_chat_message_cancel_file_transfer(message); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d"); + + linphone_content_unref(content); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + +static void file_transfer_message_download_cancelled(void) { +#if 0 + int i; + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneContent content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* setting dummy file content to something */ + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); + + /* create a file transfer message */ + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; + message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + /* wait for marie to receive pauline's message */ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + + + if (marie->stat.last_received_chat_message ) { /* get last message and use it to download file */ + linphone_chat_message_start_file_download(marie->stat.last_received_chat_message, liblinphone_tester_chat_message_state_change, marie->lc); + /* wait for file to be 50% downloaded */ + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.progress_of_LinphoneFileTransfer, 50)); + /* and cancel the transfer */ + linphone_chat_message_cancel_file_transfer(marie->stat.last_received_chat_message); + } + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,0, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageNotDelivered,1, int, "%d"); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +#endif + ms_error("Test skipped"); +} + +static void file_transfer_using_external_body_url(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneChatMessageCbs *cbs; + LinphoneChatRoom *chat_room; + LinphoneChatMessage *message; + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /* make sure lime is disabled */ + linphone_core_enable_lime(marie->lc, FALSE); + linphone_core_enable_lime(pauline->lc, FALSE); + + /* create a chatroom on pauline's side */ + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + message = linphone_chat_room_create_message(chat_room, NULL); + + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + + linphone_chat_message_set_external_body_url(message, "https://www.linphone.org:444//tmp/54ec58280ace9_c30709218df8eaba61d1.jpg"); + linphone_chat_room_send_chat_message(chat_room, message); + + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1)); + if (marie->stat.last_received_chat_message) { + linphone_chat_message_download_file(marie->stat.last_received_chat_message); + } + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageExtBodyReceived, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageInProgress, 1)); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + } +} + +static void file_transfer_2_messages_simultaneously() { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneChatRoom* pauline_room; + LinphoneChatMessage* message; + LinphoneChatMessage* message2; + LinphoneChatMessageCbs *cbs; + LinphoneContent* content; + FILE *file_to_send = NULL; + size_t file_size; + char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg"); + char *receive_filepath = bc_tester_file("receive_file.dump"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + file_to_send = fopen(send_filepath, "rb"); + fseek(file_to_send, 0, SEEK_END); + file_size = ftell(file_to_send); + fseek(file_to_send, 0, SEEK_SET); + + /* Globally configure an http file transfer server. */ + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + pauline_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + /* create a file transfer message */ + content = linphone_core_create_content(pauline->lc); + linphone_content_set_type(content,"image"); + linphone_content_set_subtype(content,"jpeg"); + linphone_content_set_size(content,file_size); /*total size to be transfered*/ + linphone_content_set_name(content,"nowebcamCIF.jpg"); + message = linphone_chat_room_create_file_transfer_message(pauline_room, content); + linphone_chat_message_set_user_data(message, file_to_send); + message2 = linphone_chat_room_create_file_transfer_message(pauline_room, content); + linphone_chat_message_set_user_data(message2, file_to_send); + linphone_content_unref(content); + + + + { + /*just to have time to purge message stored in the server*/ + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_file_transfer_send); + cbs = linphone_chat_message_get_callbacks(message2); + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_file_transfer_send); + + BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_chat_rooms(marie->lc)), 0, int, "%d"); + linphone_chat_room_send_chat_message(pauline_room,message); + linphone_chat_room_send_chat_message(pauline_room,message2); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + message = linphone_chat_message_clone(marie->stat.last_received_chat_message); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,2)); + message2 = marie->stat.last_received_chat_message; + fclose(file_to_send); + BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_chat_rooms(marie->lc)), 1, int, "%d"); + if (ms_list_size(linphone_core_get_chat_rooms(marie->lc)) != 1) { + char * buf = ms_strdup_printf("Found %d rooms instead of 1: ", ms_list_size(linphone_core_get_chat_rooms(marie->lc))); + const MSList *it = linphone_core_get_chat_rooms(marie->lc); + while (it) { + const LinphoneAddress * peer = linphone_chat_room_get_peer_address(it->data); + buf = ms_strcat_printf("%s, ", linphone_address_get_username(peer)); + it = it->next; + } + ms_error("%s", buf); + } + + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(message); + + cbs = linphone_chat_message_get_callbacks(message2); + linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received); + linphone_chat_message_download_file(message2); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,2)); + + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,2, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,2, int, "%d"); + BC_ASSERT_TRUE(compare_files(send_filepath, receive_filepath)); + + linphone_chat_message_unref(message); + linphone_core_manager_destroy(pauline); + ms_free(send_filepath); + ms_free(receive_filepath); + linphone_core_manager_destroy(marie); + } +} + +static void text_message_with_send_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + /*simultate a network error*/ + sal_set_send_error(marie->lc->sal, -1); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); + + /* check transient message list: the message should be in it, and should be the only one */ + BC_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1, int, "%d"); + BC_ASSERT_PTR_EQUAL(ms_list_nth_data(chat_room->transient_messages,0), message); + + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + /*BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1, int, "%d");*/ + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0, int, "%d"); + + /* the message should have been discarded from transient list after an error */ + BC_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 0, int, "%d"); + + sal_set_send_error(marie->lc->sal, 0); + + /*give a chance to register again to allow linphone_core_manager_destroy to properly unregister*/ + linphone_core_refresh_registers(marie->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,marie->stat.number_of_LinphoneRegistrationOk + 1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_denied(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message); + + /*pauline doesn't want to be disturbed*/ + linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed); + linphone_chat_room_send_chat_message(chat_room,message); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0, int, "%d"); + 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) { + LinphoneInfoMessage *info; + const LinphoneContent *content; + const char *hvalue; + + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + BC_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=linphone_core_create_content(marie->lc); + linphone_content_set_type(ct,"application"); + linphone_content_set_subtype(ct,"somexml"); + linphone_content_set_buffer(ct,info_content,strlen(info_content)); + linphone_info_message_set_content(info,ct); + linphone_content_unref(ct); + } + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),info); + linphone_info_message_destroy(info); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + + BC_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); + + BC_ASSERT_PTR_NOT_NULL(hvalue); + if (hvalue) + BC_ASSERT_STRING_EQUAL(hvalue, "still bad"); + + if (with_content){ + BC_ASSERT_PTR_NOT_NULL(content); + if (content) { + BC_ASSERT_PTR_NOT_NULL(linphone_content_get_buffer(content)); + BC_ASSERT_PTR_NOT_NULL(linphone_content_get_type(content)); + BC_ASSERT_PTR_NOT_NULL(linphone_content_get_subtype(content)); + if (linphone_content_get_type(content)) BC_ASSERT_STRING_EQUAL(linphone_content_get_type(content),"application"); + if (linphone_content_get_subtype(content)) BC_ASSERT_STRING_EQUAL(linphone_content_get_subtype(content),"somexml"); + if (linphone_content_get_buffer(content))BC_ASSERT_STRING_EQUAL((const char*)linphone_content_get_buffer(content),info_content); + BC_ASSERT_EQUAL(linphone_content_get_size(content),strlen(info_content), int, "%d"); + } + } + 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); +} + +static void is_composing_notification(void) { + LinphoneChatRoom* chat_room; + int dummy = 0; + + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity); + + { + int dummy=0; + wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/ + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + } + linphone_chat_room_compose(chat_room); + wait_for_until(pauline->lc, marie->lc, &dummy, 1, 1500); /*just to sleep while iterating*/ + linphone_chat_room_send_message(chat_room, "Composing a message"); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingActiveReceived, 1)); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingIdleReceived, 2)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#ifdef MSG_STORAGE_ENABLED + +/* + * Copy file "from" to file "to". + * Destination file is truncated if existing. + * Return 0 on success, positive value on error. + */ +static int +message_tester_copy_file(const char *from, const char *to) +{ + FILE *in, *out; + char buf[256]; + size_t n; + + /* Open "from" file for reading */ + in=fopen(from, "rb"); + if ( in == NULL ) + { + ms_error("Can't open %s for reading: %s\n",from,strerror(errno)); + return 1; + } + + /* Open "to" file for writing (will truncate existing files) */ + out=fopen(to, "wb"); + if ( out == NULL ) + { + ms_error("Can't open %s for writing: %s\n",to,strerror(errno)); + fclose(in); + return 2; + } + + /* Copy data from "in" to "out" */ + while ( (n=fread(buf, 1, sizeof buf, in)) > 0 ) + { + if ( ! fwrite(buf, 1, n, out) ) + { + ms_error("Could not write in %s: %s\n",to,strerror(errno)); + fclose(in); + fclose(out); + return 3; + } + } + + fclose(in); + fclose(out); + + return 0; +} + +static int check_no_strange_time(void* data,int argc, char** argv,char** cNames) { + BC_ASSERT_EQUAL(argc, 1, int, "%d"); + BC_ASSERT_STRING_EQUAL(cNames[0], "COUNT(*)"); // count of non updated messages should be 0 + BC_ASSERT_STRING_EQUAL(argv[0], "0"); // count of non updated messages should be 0 + return 0; +} + +static void message_storage_migration() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + char *src_db = bc_tester_res("messages.db"); + char *tmp_db = bc_tester_file("tmp.db"); + const MSList* chatrooms; + + BC_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); + + // enable to test the performances of the migration step + //linphone_core_message_storage_set_debug(marie->lc, TRUE); + + // the messages.db has 10000 dummy messages with the very first DB scheme. + // This will test the migration procedure + linphone_core_set_chat_database_path(marie->lc, tmp_db); + + chatrooms = linphone_core_get_chat_rooms(marie->lc); + BC_ASSERT(ms_list_size(chatrooms) > 0); + + // check that all messages have been migrated to the UTC time storage + BC_ASSERT(sqlite3_exec(marie->lc->db, "SELECT COUNT(*) FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK ); + + linphone_core_manager_destroy(marie); + remove(tmp_db); + ms_free(src_db); + ms_free(tmp_db); +} + +static void history_message_count_helper(LinphoneChatRoom* chatroom, int x, int y, int expected ){ + MSList* messages = linphone_chat_room_get_history_range(chatroom, x, y); + int size = ms_list_size(messages); + if( expected != size ){ + ms_warning("History retrieved from %d to %d returned %d records, but expected %d", x, y, size, expected); + } + BC_ASSERT_EQUAL(size, expected, int, "%d"); + + ms_list_free_with_data(messages, (void (*)(void *))linphone_chat_message_unref); + +} + +static void history_range_full_test(){ + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *jehan_addr = linphone_address_new(""); + LinphoneChatRoom *chatroom; + char *src_db = bc_tester_res("messages.db"); + char *tmp_db = bc_tester_file("tmp.db"); + + BC_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); + + linphone_core_set_chat_database_path(marie->lc, tmp_db); + + chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); + BC_ASSERT_PTR_NOT_NULL(chatroom); + if (chatroom){ + // We have 20 tests to perform to fully qualify the function, here they are: + history_message_count_helper(chatroom, 0, 0, 1); + history_message_count_helper(chatroom, -1, 0, 1); + history_message_count_helper(chatroom, 0, -1, 1270); + history_message_count_helper(chatroom, 1, 3, 3); + history_message_count_helper(chatroom, 3, 1, 1270-3); + history_message_count_helper(chatroom, 10, 10, 1); + history_message_count_helper(chatroom, -1, -1, 1270); + history_message_count_helper(chatroom, -1, -2, 1270); + history_message_count_helper(chatroom, -2, -1, 1270); + history_message_count_helper(chatroom, 3, -1, 1270-3); + history_message_count_helper(chatroom, 1, -3, 1270-1); + history_message_count_helper(chatroom, 2, -2, 1270-2); + history_message_count_helper(chatroom, 2, 0, 1270-2); + history_message_count_helper(chatroom, 0, 2, 3); + history_message_count_helper(chatroom, -1, 3, 4); + history_message_count_helper(chatroom, -2, 2, 3); + history_message_count_helper(chatroom, -3, 1, 2); + } + linphone_core_manager_destroy(marie); + linphone_address_destroy(jehan_addr); + remove(tmp_db); + ms_free(src_db); + ms_free(tmp_db); +} + + +static void history_messages_count() { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneAddress *jehan_addr = linphone_address_new(""); + LinphoneChatRoom *chatroom; + MSList *messages; + char *src_db = bc_tester_res("messages.db"); + char *tmp_db = bc_tester_file("tmp.db"); + + BC_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); + + linphone_core_set_chat_database_path(marie->lc, tmp_db); + + chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); + BC_ASSERT_PTR_NOT_NULL(chatroom); + if (chatroom){ + messages=linphone_chat_room_get_history(chatroom,10); + BC_ASSERT_EQUAL(ms_list_size(messages), 10, int, "%d"); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + messages=linphone_chat_room_get_history(chatroom,1); + BC_ASSERT_EQUAL(ms_list_size(messages), 1, int, "%d"); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + messages=linphone_chat_room_get_history(chatroom,0); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(chatroom), 1270, int, "%d"); + BC_ASSERT_EQUAL(ms_list_size(messages), 1270, int, "%d"); + /*check the second most recent message*/ + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->next->data), "Fore and aft follow each other."); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + /*test offset+limit: retrieve the 42th latest message only and check its content*/ + messages=linphone_chat_room_get_history_range(chatroom, 42, 42); + BC_ASSERT_EQUAL(ms_list_size(messages), 1, int, "%d"); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->data), "If you open yourself to the Tao is intangible and evasive, yet prefers to keep us at the mercy of the kingdom, then all of the streams of hundreds of valleys because of its limitless possibilities."); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + /*test offset without limit*/ + messages = linphone_chat_room_get_history_range(chatroom, 1265, -1); + BC_ASSERT_EQUAL(ms_list_size(messages), 1270-1265, int, "%d"); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + /*test limit without offset*/ + messages = linphone_chat_room_get_history_range(chatroom, 0, 5); + BC_ASSERT_EQUAL(ms_list_size(messages), 6, int, "%d"); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + + /*test invalid start*/ + messages = linphone_chat_room_get_history_range(chatroom, 1265, 1260); + BC_ASSERT_EQUAL(ms_list_size(messages), 1270-1265, int, "%d"); + ms_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); + } + linphone_core_manager_destroy(marie); + linphone_address_destroy(jehan_addr); + remove(tmp_db); + ms_free(src_db); + ms_free(tmp_db); +} + + +#endif + +test_t message_tests[] = { + { "Text message", text_message }, + { "Text message within call's dialog", text_message_within_dialog}, + { "Text message with credentials from auth info cb", text_message_with_credential_from_auth_cb}, + { "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 }, + { "File transfer message", file_transfer_message }, + { "Small File transfer message", small_file_transfer_message}, + { "File transfer message with io error at upload", file_transfer_message_io_error_upload }, +/* { "File transfer message with io error at download", file_transfer_message_io_error_download },*/ + { "File transfer message upload cancelled", file_transfer_message_upload_cancelled }, + { "File transfer message download cancelled", file_transfer_message_download_cancelled }, + { "File transfer message using external body url", file_transfer_using_external_body_url }, + { "File transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously }, + { "Text message denied", text_message_denied }, + { "Info message", info_message }, + { "Info message with body", info_message_with_body }, + { "IsComposing notification", is_composing_notification } +#ifdef HAVE_LIME + ,{ "Lime Text Message", lime_text_message } + ,{ "Lime File transfer message", lime_file_transfer_message } + ,{ "Lime File transfer message encryption only", lime_file_transfer_message_without_encryption} + ,{ "Lime Unitary", lime_unit } +#endif /* HAVE_LIME */ +#ifdef MSG_STORAGE_ENABLED + ,{ "Database migration", message_storage_migration } + ,{ "History count", history_messages_count } + ,{ "History range", history_range_full_test } +#endif +}; + +test_suite_t message_test_suite = { + "Message", + liblinphone_tester_setup, + NULL, + sizeof(message_tests) / sizeof(message_tests[0]), + message_tests +}; + diff --git a/tester/messages.db b/tester/messages.db new file mode 100644 index 000000000..30fd10efb Binary files /dev/null and b/tester/messages.db differ diff --git a/tester/multi_call_tester.c b/tester/multi_call_tester.c new file mode 100644 index 000000000..45f7bfcbc --- /dev/null +++ b/tester/multi_call_tester.c @@ -0,0 +1,562 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#include +#include +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "mediastreamer2/msutils.h" +#include "belle-sip/sipstack.h" + +#ifdef _WIN32 +#define unlink _unlink +#endif + + +static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + MSList *iterator; + MSList* lcs; + LinphoneCall* pauline_called_by_marie; + LinphoneCall* pauline_called_by_laure=NULL; + LinphoneCallParams *laure_params=linphone_core_create_default_call_parameters(laure->lc); + LinphoneCallParams *marie_params=linphone_core_create_default_call_parameters(marie->lc); + + if (enable_caller_privacy) + linphone_call_params_set_privacy(marie_params,LinphonePrivacyId); + + lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + BC_ASSERT_TRUE(call_with_caller_params(marie,pauline,marie_params)); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + + if (enable_caller_privacy) + linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(laure->lc,pauline->identity,laure_params)); + + BC_ASSERT_TRUE(wait_for(laure->lc + ,pauline->lc + ,&pauline->stat.number_of_LinphoneCallIncomingReceived + ,2)); + + BC_ASSERT_EQUAL(laure->stat.number_of_LinphoneCallOutgoingProgress,1, int, "%d"); + + + BC_ASSERT_TRUE(wait_for(laure->lc + ,pauline->lc + ,&laure->stat.number_of_LinphoneCallOutgoingRinging + ,1)); + + for (iterator=(MSList *)linphone_core_get_calls(pauline->lc);iterator!=NULL;iterator=iterator->next) { + LinphoneCall *call=(LinphoneCall *)iterator->data; + if (call != pauline_called_by_marie) { + /*fine, this is the call waiting*/ + pauline_called_by_laure=call; + linphone_core_accept_call(pauline->lc,pauline_called_by_laure); + } + } + + BC_ASSERT_TRUE(wait_for(laure->lc + ,pauline->lc + ,&laure->stat.number_of_LinphoneCallConnected + ,1)); + + BC_ASSERT_TRUE(wait_for(pauline->lc + ,marie->lc + ,&marie->stat.number_of_LinphoneCallPausedByRemote + ,1)); + + if (pauline_called_by_laure && enable_caller_privacy ) + BC_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(pauline_called_by_laure)),LinphonePrivacyId, int, "%d"); + /*wait a bit for ACK to be sent*/ + wait_for_list(lcs,NULL,0,1000); + linphone_core_terminate_all_calls(pauline->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} +static void call_waiting_indication(void) { + call_waiting_indication_with_param(FALSE); +} + +static void call_waiting_indication_with_privacy(void) { + call_waiting_indication_with_param(TRUE); +} + +static void incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallState state) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + MSList* lcs; + LinphoneCallParams *laure_params=linphone_core_create_default_call_parameters(laure->lc); + LinphoneCallParams *marie_params=linphone_core_create_default_call_parameters(marie->lc); + + lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + + if (state==LinphoneCallOutgoingRinging || state==LinphoneCallOutgoingEarlyMedia) { + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(marie->lc,pauline->identity,marie_params)); + + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&pauline->stat.number_of_LinphoneCallIncomingReceived + ,1)); + + if (state==LinphoneCallOutgoingEarlyMedia) + linphone_core_accept_early_media(pauline->lc,linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1, int, "%d"); + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,state==LinphoneCallOutgoingEarlyMedia?&marie->stat.number_of_LinphoneCallOutgoingEarlyMedia:&marie->stat.number_of_LinphoneCallOutgoingRinging + ,1)); + } else if (state==LinphoneCallOutgoingProgress) { + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,pauline->identity)); + } else { + ms_error("Unsupported state"); + return; + } + + BC_ASSERT_TRUE(call_with_caller_params(laure,marie,laure_params)); + + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + + + linphone_core_terminate_all_calls(marie->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} +static void incoming_call_accepted_when_outgoing_call_in_progress(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingProgress); +} +static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingRinging); +} +static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media(void) { + incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingEarlyMedia); +} + +static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCoreManager* laure) { + + 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; + const MSList* calls; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + BC_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); + BC_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + BC_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); + + BC_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure); + linphone_core_add_to_conference(marie->lc,marie_call_laure); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000)); + + linphone_core_add_to_conference(marie->lc,marie_call_pauline); + + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,5000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000)); + + BC_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); + BC_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3, int, "%d"); + + /* + * FIXME: check_ice cannot work as it is today because there is no current call for the party that hosts the conference + if (linphone_core_get_firewall_policy(marie->lc) == LinphonePolicyUseIce) { + if (linphone_core_get_firewall_policy(pauline->lc) == LinphonePolicyUseIce) { + check_ice(marie,pauline,LinphoneIceStateHostConnection); + } + if (linphone_core_get_firewall_policy(laure->lc) == LinphonePolicyUseIce) { + check_ice(marie,laure,LinphoneIceStateHostConnection); + } + } + */ + for (calls=linphone_core_get_calls(marie->lc);calls!=NULL;calls=calls->next) { + LinphoneCall *call=(LinphoneCall *)calls->data; + BC_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),linphone_call_params_get_media_encryption(linphone_call_get_current_params(call)),int,"%d"); + } + + linphone_core_terminate_conference(marie->lc); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); + + + + ms_list_free(lcs); +} +static void simple_conference(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + simple_conference_base(marie,pauline,laure); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + + + +static void simple_encrypted_conference_with_ice(LinphoneMediaEncryption mode) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + + if (linphone_core_media_encryption_supported(marie->lc,mode)) { + 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"); + linphone_core_set_firewall_policy(laure->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(laure->lc,"stun.linphone.org"); + + /*work around a to avoid stun resolution to be initiate in call_received callback leading a mainloop reentrency*/ + /* + belle_sip_main_loop_iterate() at belle_sip_loop.c:369 + belle_sip_main_loop_run [inlined]() at belle_sip_loop.c:478 + belle_sip_main_loop_sleep() at belle_sip_loop.c:490 + sal_iterate() at sal_impl.c:745 + linphone_core_get_stun_server_addrinfo() at misc.c:585 + linphone_core_gather_ice_candidates() at misc.c:610 + linphone_call_prepare_ice() at linphonecall.c:1 906 + linphone_call_new_incoming() at linphonecall.c:1 101 + call_received() at callbacks.c:347 + ... + linphone_core_iterate() at linphonecore.c:2 620 + ... + + linphone_core_set_stun_server() initiates an asynchronous resolution, but it needs a few iteration before it is completed. + By calling private function linphone_core_get_stun_server_addrinfo() we make sure to wait that the resolution is done before the + test calls actually start. + */ + linphone_core_get_stun_server_addrinfo(marie->lc); + linphone_core_get_stun_server_addrinfo(pauline->lc); + linphone_core_get_stun_server_addrinfo(laure->lc); + /**/ + + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); + linphone_core_set_media_encryption(laure->lc,mode); + + simple_conference_base(marie,pauline,laure); + } else { + ms_warning("No [%s] support available",linphone_media_encryption_to_string(mode)); + BC_PASS("Passed"); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +static void simple_conference_with_ice(void) { + simple_encrypted_conference_with_ice(LinphoneMediaEncryptionNone); +} +static void simple_zrtp_conference_with_ice(void) { + simple_encrypted_conference_with_ice(LinphoneMediaEncryptionZRTP); +} + + +static void simple_call_transfer(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_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); + + + BC_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); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallRefered,1,2000)); + /*marie pausing pauline*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPausing,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausedByRemote,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); + /*marie calling laure*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + + BC_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline)); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + BC_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)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + + marie_calling_laure=linphone_core_get_current_call(marie->lc); + BC_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure); + BC_ASSERT_PTR_EQUAL(linphone_call_get_transferer_call(marie_calling_laure),marie_calling_pauline); + + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); + + /*terminate marie to pauline call*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + BC_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_tcp_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); + + + BC_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); + BC_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); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + + /*Pauline starts the transfer*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + BC_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)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + + BC_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_tcp_rc"); + LinphoneCall* pauline_called_by_marie; + bool_t call_ok=TRUE; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + + BC_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (call_ok){ + 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"); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*Pauline starts the transfer*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + /* and immediately get an error*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); + + /*the error must be reported back to marie*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); + + /*and pauline should resume the call automatically*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000)); + + /*and call should be resumed*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,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_tcp_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; + bool_t call_ok=TRUE; + const MSList* calls; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + /*marie call pauline*/ + BC_ASSERT_TRUE((call_ok=call(marie,pauline))); + if (call_ok){ + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + /*marie pause pauline*/ + BC_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + /*marie call laure*/ + BC_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 laure*/ + BC_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); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*pauline pausing marie*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausing,1,4000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPaused,1,4000)); + /*pauline calling laure*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + BC_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) { + BC_ASSERT_PTR_EQUAL(linphone_call_get_replaced_call(lcall),laure_called_by_marie); + linphone_core_accept_call(laure->lc,lcall); + break; + } + } + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,1,2000)); + + /*terminate marie to pauline/laure call*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,2000)); + BC_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); +} + +test_t multi_call_tests[] = { + { "Call waiting indication", call_waiting_indication }, + { "Call waiting indication with privacy", call_waiting_indication_with_privacy }, + { "Simple conference", simple_conference }, + { "Simple conference with ICE",simple_conference_with_ice}, + { "Simple ZRTP conference with ICE",simple_zrtp_conference_with_ice}, + { "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 }, + { "Incoming call accepted when outgoing call in progress",incoming_call_accepted_when_outgoing_call_in_progress}, + { "Incoming call accepted when outgoing call in outgoing ringing",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing}, + { "Incoming call accepted when outgoing call in outgoing ringing early media",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media}, +}; + +test_suite_t multi_call_test_suite = { + "Multi call", + liblinphone_tester_setup, + NULL, + sizeof(multi_call_tests) / sizeof(multi_call_tests[0]), + multi_call_tests +}; diff --git a/tester/multicast_call_tester.c b/tester/multicast_call_tester.c new file mode 100644 index 000000000..437867329 --- /dev/null +++ b/tester/multicast_call_tester.c @@ -0,0 +1,278 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2014 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include "liblinphone_tester.h" +#include "linphonecore.h" +#include "belle-sip/belle-sip.h" + + +static void call_multicast_base(bool_t video) { + LinphoneCoreManager *marie, *pauline; + int begin; + int leaked_objects; + LinphoneVideoPolicy marie_policy, pauline_policy; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + if (video) { + 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); + + marie_policy.automatically_initiate=TRUE; + marie_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=TRUE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + linphone_core_set_video_multicast_addr(pauline->lc,"224.1.2.3"); + linphone_core_enable_video_multicast(pauline->lc,TRUE); + } + linphone_core_set_audio_multicast_addr(pauline->lc,"224.1.2.3"); + linphone_core_enable_audio_multicast(pauline->lc,TRUE); + + BC_ASSERT_TRUE(call(pauline,marie)); + wait_for_until(marie->lc, pauline->lc, NULL, 1, 6000); + if (linphone_core_get_current_call(marie->lc)) { + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie),70,int,"%d"); + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(marie->lc),linphone_call_iframe_decoded_cb,marie->lc); + linphone_call_send_vfu_request(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + } + + end_call(marie,pauline); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + belle_sip_object_enable_leak_detector(FALSE); + +} + +static void call_multicast(void) { + call_multicast_base(FALSE); +} +static void multicast_audio_with_pause_resume() { + call_paused_resumed_base(TRUE); +} +#ifdef VIDEO_ENABLED +static void call_multicast_video(void) { + call_multicast_base(TRUE); +} +#endif +static void early_media_with_multicast_base(bool_t video) { + LinphoneCoreManager *marie, *pauline, *pauline2; + MSList* lcs = NULL; + int dummy=0; + int leaked_objects; + int begin; + LinphoneVideoPolicy marie_policy, pauline_policy; + LpConfig *marie_lp; + LinphoneCallParams *params; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_tcp_rc"); + pauline2 = linphone_core_manager_new("pauline_tcp_rc"); + + marie_lp=linphone_core_get_config(marie->lc); + lp_config_set_int(marie_lp,"misc","real_early_media",1); + + if (video) { + linphone_core_enable_video_capture(pauline->lc, FALSE); + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(pauline2->lc, FALSE); + linphone_core_enable_video_display(pauline2->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + + marie_policy.automatically_initiate=TRUE; + marie_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + pauline_policy.automatically_accept=TRUE; + + linphone_core_set_video_policy(marie->lc,&marie_policy); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + linphone_core_set_video_policy(pauline2->lc,&pauline_policy); + linphone_core_set_video_multicast_addr(marie->lc,"224.1.2.3"); + linphone_core_enable_video_multicast(marie->lc,TRUE); + } + linphone_core_set_audio_multicast_addr(marie->lc,"224.1.2.3"); + linphone_core_enable_audio_multicast(marie->lc,TRUE); + + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + lcs = ms_list_append(lcs,pauline2->lc); + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + + linphone_core_invite_address(marie->lc, pauline->identity); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + + if (linphone_core_inc_invite_pending(pauline->lc)) { + /* send a 183 to initiate the early media */ + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline->lc),linphone_call_iframe_decoded_cb,pauline->lc); + } + linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + BC_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + if (linphone_core_inc_invite_pending(pauline2->lc)) { + /* send a 183 to initiate the early media */ + if (video) { + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline2->lc),linphone_call_iframe_decoded_cb,pauline2->lc); + } + linphone_core_accept_early_media(pauline2->lc, linphone_core_get_current_call(pauline2->lc)); + + BC_ASSERT_TRUE( wait_for_list(lcs, &pauline2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + } + + wait_for_list(lcs, &dummy, 1, 3000); + + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(pauline),70,int,"%i"); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth<90); + + BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(pauline2),70,int,"%i"); + BC_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth<90); + + BC_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + BC_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + if (video) { + BC_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + BC_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + } + + if (video) { + BC_ASSERT_TRUE( wait_for_list(lcs,&pauline->stat.number_of_IframeDecoded,1,2000)); + BC_ASSERT_TRUE( wait_for_list(lcs,&pauline2->stat.number_of_IframeDecoded,1,2000)); + } + + linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline2->stat.number_of_LinphoneCallEnd, 1,1000)); + + BC_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + BC_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + if (video) { + BC_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + BC_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + } + params=linphone_call_params_copy(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + linphone_call_params_enable_audio_multicast(params,FALSE); + linphone_call_params_enable_video_multicast(params,FALSE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, TRUE); + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, TRUE); + + linphone_core_update_call( pauline->lc + , linphone_core_get_current_call(pauline->lc) + , params); + linphone_call_params_destroy(params); + + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2,1000)); + + BC_ASSERT_FALSE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + BC_ASSERT_FALSE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + + check_media_direction( pauline + , linphone_core_get_current_call(pauline->lc) + , lcs + ,LinphoneMediaDirectionSendRecv + , video?LinphoneMediaDirectionSendRecv:LinphoneMediaDirectionInactive); + check_media_direction( marie + , linphone_core_get_current_call(marie->lc) + , lcs + ,LinphoneMediaDirectionSendRecv + , video?LinphoneMediaDirectionSendRecv:LinphoneMediaDirectionInactive); + + if (video) { + BC_ASSERT_FALSE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + BC_ASSERT_FALSE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + } + end_call(marie,pauline); + } + ms_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(pauline2); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects,0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } + belle_sip_object_enable_leak_detector(FALSE); +} + +static void early_media_with_multicast_audio() { + early_media_with_multicast_base(FALSE); +} +static void unicast_incoming_with_multicast_audio_on() { + simple_call_base(TRUE); +} +#ifdef VIDEO_ENABLED +static void early_media_with_multicast_video() { + early_media_with_multicast_base(TRUE); +} +#endif + +test_t multicast_call_tests[] = { + { "Multicast audio call",call_multicast}, + { "Multicast call with pause/resume",multicast_audio_with_pause_resume}, + { "Early media multicast audio call",early_media_with_multicast_audio}, + { "Unicast incoming call with multicast activated",unicast_incoming_with_multicast_audio_on}, +#ifdef VIDEO_ENABLED + { "Multicast video call",call_multicast_video}, + { "Early media multicast video call",early_media_with_multicast_video}, +#endif +}; + +test_suite_t multicast_call_test_suite = { + "Multicast Call", + liblinphone_tester_setup, + NULL, + sizeof(multicast_call_tests) / sizeof(multicast_call_tests[0]), + multicast_call_tests +}; diff --git a/tester/offeranswer_tester.c b/tester/offeranswer_tester.c new file mode 100644 index 000000000..b433bda5c --- /dev/null +++ b/tester/offeranswer_tester.c @@ -0,0 +1,426 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include +#include +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static int get_codec_position(const MSList *l, const char *mime_type, int rate){ + const MSList *elem; + int i; + for (elem=l, i=0; elem!=NULL; elem=elem->next,i++){ + PayloadType *pt=(PayloadType*)elem->data; + if (strcasecmp(pt->mime_type, mime_type)==0 && pt->clock_rate==rate) return i; + } + return -1; +} + +/*check basic things about codecs at startup: order and enablement*/ +static void start_with_no_config(void){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc=linphone_core_new(&vtable, NULL, NULL, NULL); + const MSList *codecs=linphone_core_get_audio_codecs(lc); + int opus_codec_pos; + int speex_codec_pos=get_codec_position(codecs, "speex", 8000); + int speex16_codec_pos=get_codec_position(codecs, "speex", 16000); + PayloadType *pt; + opus_codec_pos=get_codec_position(codecs, "opus", 48000); + if (opus_codec_pos!=-1) BC_ASSERT_EQUAL(opus_codec_pos,0,int, "%d"); + BC_ASSERT_LOWER(speex16_codec_pos,speex_codec_pos,int,"%d"); + + pt=linphone_core_find_payload_type(lc, "speex", 16000, 1); + BC_ASSERT_PTR_NOT_NULL(pt); + if (pt) { + BC_ASSERT_TRUE(linphone_core_payload_type_enabled(lc, pt)); + } + linphone_core_destroy(lc); +} + +static void check_payload_type_numbers(LinphoneCall *call1, LinphoneCall *call2, int expected_number){ + const LinphoneCallParams *params=linphone_call_get_current_params(call1); + const PayloadType *pt=linphone_call_params_get_used_audio_codec(params); + BC_ASSERT_PTR_NOT_NULL(pt); + if (pt){ + BC_ASSERT_EQUAL(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt),expected_number, int, "%d"); + } + params=linphone_call_get_current_params(call2); + pt=linphone_call_params_get_used_audio_codec(params); + BC_ASSERT_PTR_NOT_NULL(pt); + if (pt){ + BC_ASSERT_EQUAL(linphone_core_get_payload_type_number(linphone_call_get_core(call1),pt),expected_number, int, "%d"); + } +} + +static void simple_call_with_different_codec_mappings(void) { + int begin; + int leaked_objects; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCall *pauline_call; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcmu",-1); + + /*marie set a fantasy number to PCMU*/ + linphone_core_set_payload_type_number(marie->lc, + linphone_core_find_payload_type(marie->lc, "PCMU", 8000, -1), + 104); + + BC_ASSERT_TRUE(call(marie,pauline)); + pauline_call=linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + LinphoneCallParams *params; + check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); + /*make a reinvite in the other direction*/ + linphone_core_update_call(pauline->lc, pauline_call, + params=linphone_core_create_call_params(pauline->lc, pauline_call)); + linphone_call_params_unref(params); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdating,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdatedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + /*payload type numbers shall remain the same*/ + check_payload_type_numbers(linphone_core_get_current_call(marie->lc), pauline_call, 104); + } + + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + +static void call_failed_because_of_codecs(void) { + int begin,leaked_objects; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall* out_call; + + disable_all_audio_codecs_except_one(marie->lc,"pcmu",-1); + disable_all_audio_codecs_except_one(pauline->lc,"pcma",-1); + out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + /*flexisip will retain the 488 until the "urgent reply" timeout (I.E 5s) arrives.*/ + BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,7000)); + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,0, int, "%d"); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + } + leaked_objects=belle_sip_object_get_object_count()-begin; + BC_ASSERT_EQUAL(leaked_objects, 0, int, "%d"); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} + + +static void profile_call_base(bool_t avpf1, LinphoneMediaEncryption srtp1,bool_t avpf2, LinphoneMediaEncryption srtp2, bool_t encryption_mandatory, const char *expected_profile) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphoneProxyConfig *lpc; + const LinphoneCallParams *params; + + if (avpf1) { + linphone_core_get_default_proxy(marie->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + if (avpf2) { + linphone_core_get_default_proxy(pauline->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + + if (encryption_mandatory) { + linphone_core_set_media_encryption_mandatory(marie->lc,TRUE); + linphone_core_set_media_encryption_mandatory(pauline->lc,TRUE); + } + + if (linphone_core_media_encryption_supported(marie->lc, srtp1)) { + linphone_core_set_media_encryption(marie->lc, srtp1); + } else { + ms_message("Unsupported [%s] encryption type, cannot test",linphone_media_encryption_to_string(srtp1)); + goto end; + + } + if (linphone_core_media_encryption_supported(pauline->lc, srtp2)) { + linphone_core_set_media_encryption(pauline->lc, srtp2); + }else { + ms_message("Unsupported [%s] encryption type, cannot test",linphone_media_encryption_to_string(srtp2)); + goto end; + + } + + BC_ASSERT_TRUE(call(marie, pauline)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + if (linphone_core_get_current_call(marie->lc)) { + params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + } + if (linphone_core_get_current_call(pauline->lc)) { + params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + } + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1, int, "%d"); +end: + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} + +static void profile_call(bool_t avpf1, LinphoneMediaEncryption srtp1, bool_t avpf2, LinphoneMediaEncryption srtp2, const char *expected_profile) { + return profile_call_base(avpf1, srtp1, avpf2,srtp2,FALSE,expected_profile); +} +static void avp_to_avp_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionNone, FALSE, LinphoneMediaEncryptionNone, "RTP/AVP"); +} + +static void avp_to_avpf_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionNone, TRUE, LinphoneMediaEncryptionNone, "RTP/AVP"); +} + +static void avp_to_savp_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionNone, FALSE, LinphoneMediaEncryptionSRTP, "RTP/AVP"); +} + +static void avp_to_savpf_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionNone, TRUE, LinphoneMediaEncryptionSRTP, "RTP/AVP"); +} + +static void avpf_to_avp_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionNone, FALSE, LinphoneMediaEncryptionNone, "RTP/AVPF"); +} + +static void avpf_to_avpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionNone, TRUE, LinphoneMediaEncryptionNone, "RTP/AVPF"); +} + +static void avpf_to_savp_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionNone, FALSE, LinphoneMediaEncryptionSRTP, "RTP/AVPF"); +} + +static void avpf_to_savpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionNone, TRUE, LinphoneMediaEncryptionSRTP, "RTP/AVPF"); +} + +static void savp_to_avp_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionSRTP, FALSE, LinphoneMediaEncryptionNone, "RTP/SAVP"); +} + +static void savp_to_avpf_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionSRTP, TRUE, LinphoneMediaEncryptionNone, "RTP/SAVP"); +} + +static void savp_to_savp_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionSRTP, FALSE, LinphoneMediaEncryptionSRTP, "RTP/SAVP"); +} + +static void savp_to_savpf_call(void) { + profile_call(FALSE, LinphoneMediaEncryptionSRTP, TRUE, LinphoneMediaEncryptionSRTP, "RTP/SAVP"); +} + +static void savpf_to_avp_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionSRTP, FALSE, LinphoneMediaEncryptionNone, "RTP/SAVPF"); +} + +static void savpf_to_avpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionSRTP, TRUE, LinphoneMediaEncryptionNone, "RTP/SAVPF"); +} + +static void savpf_to_savp_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionSRTP, FALSE, LinphoneMediaEncryptionSRTP, "RTP/SAVPF"); +} + +static void savpf_to_savpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionSRTP, TRUE, LinphoneMediaEncryptionSRTP, "RTP/SAVPF"); +} + +static void savpf_dtls_to_savpf_dtls_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionDTLS, TRUE, LinphoneMediaEncryptionDTLS, "UDP/TLS/RTP/SAVPF"); +} +static void savpf_dtls_to_savpf_dtls_encryption_mandatory_call(void) { + profile_call_base(TRUE, LinphoneMediaEncryptionDTLS, TRUE, LinphoneMediaEncryptionDTLS, TRUE, "UDP/TLS/RTP/SAVPF"); +} +static void savpf_dtls_to_savpf_encryption_mandatory_call(void) { + /*profile_call_base(TRUE, LinphoneMediaEncryptionDTLS, TRUE, LinphoneMediaEncryptionSRTP, TRUE, "UDP/TLS/RTP/SAVPF"); not sure of result*/ +} + +static void savpf_dtls_to_savpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionDTLS, TRUE, LinphoneMediaEncryptionSRTP, "UDP/TLS/RTP/SAVPF"); +} + +static void savpf_dtls_to_avpf_call(void) { + profile_call(TRUE, LinphoneMediaEncryptionDTLS, TRUE, LinphoneMediaEncryptionNone, "UDP/TLS/RTP/SAVPF"); +} + +#ifdef VIDEO_ENABLED +static LinphonePayloadType * configure_core_for_avpf_and_video(LinphoneCore *lc) { + LinphoneProxyConfig *lpc; + LinphonePayloadType *lpt; + LinphoneVideoPolicy policy = { 0 }; + + policy.automatically_initiate = TRUE; + policy.automatically_accept = TRUE; + linphone_core_get_default_proxy(lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + linphone_core_set_video_device(lc, "StaticImage: Static picture"); + linphone_core_enable_video_capture(lc, TRUE); + linphone_core_enable_video_display(lc, TRUE); + linphone_core_set_video_policy(lc, &policy); + lpt = linphone_core_find_payload_type(lc, "VP8", 90000, -1); + if (lpt == NULL) { + ms_warning("VP8 codec not available."); + } else { + disable_all_video_codecs_except_one(lc, "VP8"); + } + return lpt; +} + +static void check_avpf_features(LinphoneCore *lc, unsigned char expected_features) { + LinphoneCall *lcall = linphone_core_get_current_call(lc); + BC_ASSERT_PTR_NOT_NULL(lcall); + if (lcall != NULL) { + SalStreamDescription *desc = sal_media_description_find_stream(lcall->resultdesc, SalProtoRtpAvpf, SalVideo); + BC_ASSERT_PTR_NOT_NULL(desc); + if (desc != NULL) { + BC_ASSERT_PTR_NOT_NULL(desc->payloads); + if (desc->payloads) { + PayloadType *pt = (PayloadType *)desc->payloads->data; + BC_ASSERT_STRING_EQUAL(pt->mime_type, "VP8"); + BC_ASSERT_EQUAL(pt->avpf.features, expected_features, int, "%d"); + } + } + } +} + +static void compatible_avpf_features(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphonePayloadType *lpt; + bool_t call_ok; + + if (configure_core_for_avpf_and_video(marie->lc) == NULL) goto end; + lpt = configure_core_for_avpf_and_video(pauline->lc); + + BC_ASSERT_TRUE((call_ok=call(marie, pauline))); + if (!call_ok) goto end; + + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + check_avpf_features(marie->lc, lpt->avpf.features); + check_avpf_features(pauline->lc, lpt->avpf.features); + + end_call(marie,pauline); +end: + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} + +static void incompatible_avpf_features(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphonePayloadType *lpt; + bool_t call_ok; + + if (configure_core_for_avpf_and_video(marie->lc) == NULL) goto end; + lpt = configure_core_for_avpf_and_video(pauline->lc); + lpt->avpf.features = PAYLOAD_TYPE_AVPF_NONE; + + BC_ASSERT_TRUE(call_ok=call(marie, pauline)); + if (!call_ok) goto end; + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + check_avpf_features(marie->lc, PAYLOAD_TYPE_AVPF_NONE); + check_avpf_features(pauline->lc, PAYLOAD_TYPE_AVPF_NONE); + + end_call(marie,pauline); +end: + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} +#endif + +static test_t offeranswer_tests[] = { + { "Start with no config", start_with_no_config }, + { "Call failed because of codecs", call_failed_because_of_codecs }, + { "Simple call with different codec mappings", simple_call_with_different_codec_mappings}, + { "AVP to AVP call", avp_to_avp_call }, + { "AVP to AVPF call", avp_to_avpf_call }, + { "AVP to SAVP call", avp_to_savp_call }, + { "AVP to SAVPF call", avp_to_savpf_call }, + { "AVPF to AVP call", avpf_to_avp_call }, + { "AVPF to AVPF call", avpf_to_avpf_call }, + { "AVPF to SAVP call", avpf_to_savp_call }, + { "AVPF to SAVPF call", avpf_to_savpf_call }, + { "SAVP to AVP call", savp_to_avp_call }, + { "SAVP to AVPF call", savp_to_avpf_call }, + { "SAVP to SAVP call", savp_to_savp_call }, + { "SAVP to SAVPF call", savp_to_savpf_call }, + { "SAVPF to AVP call", savpf_to_avp_call }, + { "SAVPF to AVPF call", savpf_to_avpf_call }, + { "SAVPF to SAVP call", savpf_to_savp_call }, + { "SAVPF to SAVPF call", savpf_to_savpf_call }, + { "SAVPF/DTLS to SAVPF/DTLS call", savpf_dtls_to_savpf_dtls_call}, + { "SAVPF/DTLS to SAVPF/DTLS encryption mandatory call", savpf_dtls_to_savpf_dtls_encryption_mandatory_call}, + { "SAVPF/DTLS to SAVPF call", savpf_dtls_to_savpf_call}, + { "SAVPF/DTLS to SAVPF encryption mandatory call", savpf_dtls_to_savpf_encryption_mandatory_call}, + { "SAVPF/DTLS to AVPF call", savpf_dtls_to_avpf_call}, +#ifdef VIDEO_ENABLED + { "Compatible AVPF features", compatible_avpf_features }, + { "Incompatible AVPF features", incompatible_avpf_features }, +#endif +}; + +test_suite_t offeranswer_test_suite = { + "Offer-answer", + liblinphone_tester_setup, + NULL, + sizeof(offeranswer_tests) / sizeof(offeranswer_tests[0]), + offeranswer_tests +}; diff --git a/tester/player_tester.c b/tester/player_tester.c new file mode 100644 index 000000000..332bcffbc --- /dev/null +++ b/tester/player_tester.c @@ -0,0 +1,91 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include "liblinphone_tester.h" +#include + +static bool_t wait_for_eof(bool_t *eof, int *time,int time_refresh, int timeout) { + while(*time < timeout && !*eof) { + ms_usleep(time_refresh * 1000U); + *time += time_refresh; + } + return *time < timeout; +} + +static void eof_callback(LinphonePlayer *player, void *user_data) { + bool_t *eof = (bool_t *)user_data; + *eof = TRUE; +} + +static void play_file(const char *filename, bool_t unsupported_format, const char *audio_mime, const char *video_mime) { + LinphoneCoreManager *lc_manager; + LinphonePlayer *player; + int res, time = 0; + bool_t eof = FALSE; + + lc_manager = linphone_core_manager_new("marie_rc"); + BC_ASSERT_PTR_NOT_NULL(lc_manager); + if(lc_manager == NULL) return; + + player = linphone_core_create_local_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), video_stream_get_default_video_renderer(), 0); + BC_ASSERT_PTR_NOT_NULL(player); + if(player == NULL) goto fail; + + res = linphone_player_open(player, filename, eof_callback, &eof); + if(unsupported_format + || (audio_mime == NULL && video_mime == NULL) + || (video_mime == NULL && audio_mime && !ms_filter_codec_supported(audio_mime)) + || (audio_mime == NULL && video_mime && !ms_filter_codec_supported(video_mime))) { + BC_ASSERT_EQUAL(res, -1, int, "%d"); + } else { + BC_ASSERT_EQUAL(res, 0, int, "%d"); + } + if(res == -1) goto fail; + + res = linphone_player_start(player); + BC_ASSERT_EQUAL(res, 0, int, "%d"); + if(res == -1) goto fail; + + BC_ASSERT_TRUE(wait_for_eof(&eof, &time, 100, 13000)); + + linphone_player_close(player); + + fail: + if(player) linphone_player_destroy(player); + if(lc_manager) linphone_core_manager_destroy(lc_manager); +} + +static void playing_test(void) { + char *filename = bc_tester_res("sounds/hello_opus_h264.mkv"); + const char *audio_mime = "opus"; + const char *video_mime = "h264"; + play_file(filename, !linphone_local_player_matroska_supported(), audio_mime, video_mime); + ms_free(filename); +} + +test_t player_tests[] = { + { "Local MKV file" , playing_test } +}; + +test_suite_t player_test_suite = { + "Player", + liblinphone_tester_setup, + NULL, + sizeof(player_tests) / sizeof(test_t), + player_tests +}; diff --git a/tester/presence_tester.c b/tester/presence_tester.c new file mode 100644 index 000000000..a685aba7a --- /dev/null +++ b/tester/presence_tester.c @@ -0,0 +1,492 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#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_with_expire(int expires) { + 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); + if (expires >0) { + linphone_proxy_config_set_publish_expires(proxy,expires); + } + 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 void simple_publish() { + simple_publish_with_expire(-1); +} + +static void publish_with_expires() { + simple_publish_with_expire(1); +} + +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); + */ + + BC_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1, int, "%d"); + /*without proxy, callee cannot subscribe to caller + BC_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1, int, "%d"); + */ + BC_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1, int, "%d"); + + 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_tcp_rc"); + LinphoneProxyConfig* config; + LinphoneFriend* lf; + char* lf_identity=linphone_address_as_string_uri_only(pauline->identity); + linphone_core_get_default_proxy(marie->lc,&config); + + BC_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*/ + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationProgress,2)); + BC_ASSERT_EQUAL(linphone_proxy_config_get_error(config),LinphoneReasonIOError, int, "%d"); + 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); + BC_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); + BC_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); + BC_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"); + + BC_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + + + linphone_core_manager_destroy(marie); + /*unsubscribe is not reported ?*/ + BC_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); +} + +#if 0 +/* the core no longer changes the presence status when a call is ongoing, this is left to the application*/ +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); + BC_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + BC_ASSERT_TRUE(subscribe_to_callee_presence(pauline,marie)); + + BC_ASSERT_TRUE(call(marie,pauline)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnThePhone,1)); + BC_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); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityOnline,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnline,1)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#endif + +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; + + BC_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); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1, int, "%d"); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + BC_ASSERT_PTR_NOT_NULL(activity); + BC_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityDinner, int, "%d"); + description = linphone_presence_activity_get_description(activity); + BC_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); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1, int, "%d"); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + BC_ASSERT_PTR_NOT_NULL(activity); + BC_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivitySteering, int, "%d"); + description = linphone_presence_activity_get_description(activity); + BC_ASSERT_PTR_NOT_NULL(description); + if (description != NULL) BC_ASSERT_STRING_EQUAL(description, bike_description); + + /* 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); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1, int, "%d"); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + BC_ASSERT_PTR_NOT_NULL(activity); + BC_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityVacation, int, "%d"); + description = linphone_presence_activity_get_description(activity); + BC_ASSERT_PTR_NULL(description); + note = linphone_presence_model_get_note(marie->stat.last_received_presence, NULL); + BC_ASSERT_PTR_NOT_NULL(note); + if (note != NULL) { + note_content = linphone_presence_note_get_content(note); + BC_ASSERT_PTR_NOT_NULL(note_content); + if (note_content != NULL) { + BC_ASSERT_STRING_EQUAL(note_content, vacation_note); + } + } + + /* 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); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone, 1, int, "%d"); + contact2 = linphone_presence_model_get_contact(presence); + BC_ASSERT_PTR_NOT_NULL(contact2); + if (contact2 != NULL) { + BC_ASSERT_STRING_EQUAL(contact, contact2); + ms_free(contact2); + } + + /* Presence timestamp. */ + current_timestamp = ms_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); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityShopping, 1, int, "%d"); + presence_timestamp = linphone_presence_model_get_timestamp(presence); + BC_ASSERT_GREATER(presence_timestamp , current_timestamp, unsigned, "%u"); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#define USE_PRESENCE_SERVER 0 + +#if USE_PRESENCE_SERVER +static void test_subscribe_notify_publish(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; + + LpConfig *pauline_lp = linphone_core_get_config(pauline->lc); + char* lf_identity=linphone_address_as_string_uri_only(marie->identity); + LinphoneFriend *lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity); + + lp_config_set_int(pauline_lp,"sip","subscribe_expires",5); + + linphone_core_add_friend(pauline->lc,lf); + + /*wait for subscribe acknowledgment*/ + wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,1,2000); + BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d"); + + /*enable publish*/ + + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_set_publish_expires(proxy,3); + linphone_proxy_config_done(proxy); + + /*wait for marie status*/ + wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,2,2000); + BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d"); + + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL); + linphone_core_set_presence_model(marie->lc,presence); + + /*wait for new status*/ + wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,3,2000); + BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d"); + + /*wait for refresh*/ + wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000); + BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d"); + + /*linphone_core_remove_friend(pauline->lc,lf);*/ + /*wait for final notify*/ + /*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000); + BC_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf), int, "%d"); + */ + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void test_forked_subscribe_notify_publish(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; + LpConfig *pauline_lp; + char* lf_identity; + LinphoneFriend *lf; + MSList* lcs=ms_list_append(NULL,pauline->lc); + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + + pauline_lp = linphone_core_get_config(pauline->lc); + lf_identity=linphone_address_as_string_uri_only(marie->identity); + lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity); + + lp_config_set_int(pauline_lp,"sip","subscribe_expires",5); + + linphone_core_add_friend(pauline->lc,lf); + + /*wait for subscribe acknowledgment*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,2000); + BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d"); + + /*enable publish*/ + + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_set_publish_expires(proxy,3); + linphone_proxy_config_done(proxy); + + linphone_core_get_default_proxy(marie2->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_set_publish_expires(proxy,3); + linphone_proxy_config_done(proxy); + + + /*wait for marie status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,3,2000); + BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d"); + + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL); + linphone_core_set_presence_model(marie->lc,presence); + + /*wait for new status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,4,2000); + BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d"); + + + presence =linphone_presence_model_new_with_activity( LinphonePresenceActivityMeeting,NULL); + linphone_core_set_presence_model(marie2->lc,presence); + /*wait for new status*/ + wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,5,2000); + BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d"); /*because liblinphone compositor is very simple for now (I.E only take first occurence)*/ + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} + + +#endif + +test_t presence_tests[] = { + { "Simple Subscribe", simple_subscribe }, + { "Simple Publish", simple_publish }, + { "Simple Publish with expires", publish_with_expires }, + /*{ "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 }, +#if USE_PRESENCE_SERVER + { "Subscribe with late publish", test_subscribe_notify_publish }, + { "Forked subscribe with late publish", test_forked_subscribe_notify_publish }, +#endif +}; + +test_suite_t presence_test_suite = { + "Presence", + liblinphone_tester_setup, + NULL, + sizeof(presence_tests) / sizeof(presence_tests[0]), + presence_tests +}; + diff --git a/tester/proxy_config_tester.c b/tester/proxy_config_tester.c new file mode 100644 index 000000000..29a169557 --- /dev/null +++ b/tester/proxy_config_tester.c @@ -0,0 +1,109 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include "liblinphone_tester.h" + +const char* phone_normalization(LinphoneProxyConfig *proxy, const char* in) { + static char result[255]; + linphone_proxy_config_normalize_number(proxy, in, result, 255-1); + return result; +} + +static void phone_normalization_without_proxy() { + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "012 345 6789"), "0123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33123456789"), "+33123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33012345678"), "+33012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33 0012345678"), "+330012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33012345678"), "+33012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+3301234567891"), "+3301234567891"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33 01234567891"), "+3301234567891"); + BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "I_AM_NOT_A_NUMBER"), "I_AM_NOT_A_NUMBER"); // invalid phone number +} + +static void phone_normalization_with_proxy() { + LinphoneProxyConfig *proxy = linphone_proxy_config_new(); + linphone_proxy_config_set_dial_prefix(proxy, "33"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "012 3456 789"), "+33123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+33123456789"), "+33123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+33 0123456789"), "+330123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+330012345678"), "+330012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+3301 2345678"), "+33012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+3301234567891"), "+3301234567891"); + + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "123456789"), "+33123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, " 0123456789"), "+33123456789"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0012345678"), "+12345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "01 2345678"), "+33012345678"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "01234567891"), "+33234567891"); // invalid phone number (too long) + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "I_AM_NOT_A_NUMBER"), "I_AM_NOT_A_NUMBER"); // invalid phone number + + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+990012345678"), "+990012345678"); + + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0952636505"), "+33952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "09 52 63 65 05"), "+33952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "09-52-63-65-05"), "+33952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+31952636505"), "+31952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0033952636505"), "+33952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0033952636505"), "+33952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "toto"), "toto"); + + linphone_proxy_config_set_dial_prefix(proxy, "99"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0012345678"), "+12345678"); + + linphone_proxy_config_destroy(proxy); +} + +static void phone_normalization_with_dial_escape_plus(void){ + LinphoneProxyConfig *proxy = linphone_proxy_config_new(); + linphone_proxy_config_set_dial_prefix(proxy, "33"); + linphone_proxy_config_set_dial_escape_plus(proxy, TRUE); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0033952636505"), "0033952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0952636505"), "0033952636505"); + BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+34952636505"), "0034952636505"); + linphone_proxy_config_destroy(proxy); +} + +#define SIP_URI_CHECK(actual, expected) { \ + LinphoneAddress* res = linphone_proxy_config_normalize_sip_uri(NULL, actual); \ + char* actual_str = linphone_address_as_string_uri_only(res); \ + BC_ASSERT_STRING_EQUAL(actual_str, expected); \ + ms_free(actual_str); \ + linphone_address_destroy(res); \ + } + + +static void sip_uri_normalization(void) { + BC_ASSERT_PTR_NULL(linphone_proxy_config_normalize_sip_uri(NULL, "test")); + SIP_URI_CHECK("test@linphone.org", "sip:test@linphone.org"); + SIP_URI_CHECK("test@linphone.org;transport=tls", "sip:test@linphone.org;transport=tls"); +} + +test_t proxy_config_tests[] = { + { "Phone normalization without proxy", phone_normalization_without_proxy }, + { "Phone normalization with proxy", phone_normalization_with_proxy }, + { "Phone normalization with dial escape plus", phone_normalization_with_dial_escape_plus }, + { "SIP URI normalization", sip_uri_normalization }, +}; + +test_suite_t proxy_config_test_suite = { + "Proxy config", + liblinphone_tester_setup, + NULL, + sizeof(proxy_config_tests) / sizeof(proxy_config_tests[0]), + proxy_config_tests +}; diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c new file mode 100644 index 000000000..debfb2608 --- /dev/null +++ b/tester/quality_reporting_tester.c @@ -0,0 +1,392 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +/*avoid crash if x is NULL on libc versions <4.5.26 */ +#define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y)) + +void on_report_send_mandatory(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ + char * body = (char *)linphone_content_get_buffer(content); + char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + MediaStream * ms; + if (stream_type == LINPHONE_CALL_STATS_AUDIO){ + ms = (MediaStream*)call->audiostream; + }else{ + ms = (MediaStream*)call->videostream; + } + BC_ASSERT_TRUE( + __strstr(body, "VQIntervalReport\r\n") == body || + __strstr(body, "VQSessionReport\r\n") == body || + __strstr(body, "VQSessionReport: CallTerm\r\n") == body + ); + + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "CallID:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalID:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteID:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "OrigID:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalGroup:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteGroup:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalAddr:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteAddr:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "START=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "STOP=")); + + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PT=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PD=")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SR=")); + + /* We should have not reached RemoteMetrics section yet */ + BC_ASSERT_TRUE(!remote_metrics_start || body < remote_metrics_start); + + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "DialogID:")); + + if (report->remote_metrics.rtcp_sr_count>0&&ms!=NULL&&ms->rc!=NULL){ + /* Hack: reset rtcp_sr_count to 0 because in case of interval reports, we need one RTCP SR by interval. */ + report->remote_metrics.rtcp_sr_count=0; + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "AdaptiveAlg:")); + } +} + +char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, char * body){ + if (metrics->rtcp_xr_count){ + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "JitterBuffer:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PacketLoss:")); + } + if (metrics->rtcp_sr_count+metrics->rtcp_xr_count>0){ + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Delay:")); + } + if (metrics->rtcp_xr_count){ + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "QualityEst:")); + } + + return body; +} + +void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ + char * body = (char*)linphone_content_get_buffer(content); + char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + on_report_send_mandatory(call,stream_type,content); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); + BC_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start); +} +void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ + char * body = (char*)linphone_content_get_buffer(content); + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + + on_report_send_mandatory(call,stream_type,content); + if (report->remote_metrics.rtcp_sr_count+report->remote_metrics.rtcp_xr_count>0){ + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteMetrics:")); + BC_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:")); + on_report_send_verify_metrics(&report->remote_metrics,body); + } +} +void on_report_send_with_rtcp_xr_both(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ + on_report_send_with_rtcp_xr_local(call,stream_type,content); + on_report_send_with_rtcp_xr_remote(call,stream_type,content); +} + +bool_t create_call_for_quality_reporting_tests( + LinphoneCoreManager* marie, + LinphoneCoreManager* pauline, + LinphoneCall** call_marie, + LinphoneCall** call_pauline, + LinphoneCallParams * params_marie, + LinphoneCallParams * params_pauline + ) { + + + bool_t call_succeeded = call_with_params(marie,pauline,params_marie,params_pauline); + BC_ASSERT_TRUE(call_succeeded); + if (call_succeeded) { + if (call_marie) { + *call_marie = linphone_core_get_current_call(marie->lc); + BC_ASSERT_PTR_NOT_NULL(*call_marie); + } + if (call_pauline) { + *call_pauline = linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(*call_pauline); + } + } + return call_succeeded; +} + +static void quality_reporting_not_used_without_config() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { + // marie has stats collection enabled but pauline has not + BC_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); + BC_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); + + // this field should be already filled + BC_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip); + + // but not this one since it is updated at the end of call + BC_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_not_sent_if_call_not_started() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCallLog* out_call_log; + LinphoneCall* out_call; + + linphone_core_set_max_calls(pauline->lc,0); + out_call = linphone_core_invite(marie->lc,"pauline"); + BC_ASSERT_PTR_NOT_NULL(out_call); + if(out_call == NULL) goto end; + linphone_call_ref(out_call); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallError,1, 10000)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1, int, "%d"); + + if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { + out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data); + BC_ASSERT_PTR_NOT_NULL(out_call_log); + BC_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted, int, "%d"); + } + linphone_call_unref(out_call); + + // wait a few time... + wait_for_until(marie->lc,NULL,NULL,0,1000); + + // since the callee was busy, there should be no publish to do + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0, int, "%d"); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_not_sent_if_low_bandwidth() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCallParams* marie_params; + + marie_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_low_bandwidth(marie_params,TRUE); + + if (create_call_for_quality_reporting_tests(marie, pauline, NULL, NULL, marie_params, NULL)) { + linphone_core_terminate_all_calls(marie->lc); + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0, int, "%d"); + } + linphone_call_params_destroy(marie_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void on_report_send_remove_fields(const LinphoneCall *call, SalStreamType stream_type, const LinphoneContent *content){ + char *body = (char*)linphone_content_get_buffer(content); + /*corrupt start of the report*/ + strncpy(body, "corrupted report is corrupted", strlen("corrupted report is corrupted")); +} + +static void quality_reporting_invalid_report() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { + linphone_reporting_set_on_report_send(call_marie, on_report_send_remove_fields); + + linphone_core_terminate_all_calls(marie->lc); + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,1)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishError,1,3000)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,1, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0, int, "%d"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_at_call_termination() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { + linphone_reporting_set_on_report_send(call_marie, on_report_send_with_rtcp_xr_remote); + + linphone_core_terminate_all_calls(marie->lc); + + // now dialog id should be filled + BC_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); + + BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); + + // PUBLISH submission to the collector should be ok + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,1, int, "%d"); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_interval_report() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { + linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory); + linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 1); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); + + // PUBLISH submission to the collector should be ok + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,1,60000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,1,60000)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_session_report_if_video_stopped() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall* call_pauline = NULL; + LinphoneCall* call_marie = NULL; + LinphoneCallParams* pauline_params; + LinphoneCallParams* marie_params; + + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, FALSE); + marie_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(marie_params,TRUE); + pauline_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(pauline_params,TRUE); + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, marie_params, pauline_params)) { + linphone_reporting_set_on_report_send(call_marie, on_report_send_with_rtcp_xr_local); + + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0, int, "%d"); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0, int, "%d"); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,NULL,0,3000)); + BC_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline))); + + /*remove video*/ + linphone_call_params_enable_video(pauline_params,FALSE); + linphone_core_update_call(pauline->lc,call_pauline,pauline_params); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,1,10000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,1,10000)); + + BC_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline))); + + linphone_core_terminate_all_calls(marie->lc); + + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,2,5000)); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,2,5000)); + } + linphone_call_params_destroy(marie_params); + linphone_call_params_destroy(pauline_params); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +void publish_report_with_route_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + if (state == LinphonePublishProgress) { + BC_ASSERT_STRING_EQUAL(linphone_address_as_string(linphone_event_get_resource(ev)), linphone_proxy_config_get_quality_reporting_collector(linphone_core_get_default_proxy_config(lc))); + } +} + +static void quality_reporting_sent_using_custom_route() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_quality_reporting_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + LinphoneCoreVTable publish_vtable = {0}; + publish_vtable.publish_state_changed = publish_report_with_route_state_changed; + linphone_core_add_listener(marie->lc, &publish_vtable); + + //INVALID collector: sip.linphone.org do not collect reports, so it will throw a 404 Not Found error + linphone_proxy_config_set_quality_reporting_collector(linphone_core_get_default_proxy_config(marie->lc), "sip:sip.linphone.org"); + + if (create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline, NULL, NULL)) { + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); + BC_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); + + // PUBLISH submission to the collector should be ERROR since route is not valid + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,1, int, "%d"); + BC_ASSERT_TRUE(wait_for_until(marie->lc,NULL,&marie->stat.number_of_LinphonePublishError,1,10000)); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0,int, "%d"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +test_t quality_reporting_tests[] = { + { "Not used if no config", quality_reporting_not_used_without_config}, + { "Call term session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Call term session report not sent if low bandwidth", quality_reporting_not_sent_if_low_bandwidth}, + { "Call term session report invalid if missing mandatory fields", quality_reporting_invalid_report}, + { "Call term session report sent if call ended normally", quality_reporting_at_call_termination}, + { "Interval report if interval is configured", quality_reporting_interval_report}, + { "Session report sent if video stopped during call", quality_reporting_session_report_if_video_stopped}, + { "Sent using custom route", quality_reporting_sent_using_custom_route}, +}; + +test_suite_t quality_reporting_test_suite = { + "QualityReporting", + liblinphone_tester_setup, + NULL, + sizeof(quality_reporting_tests) / sizeof(quality_reporting_tests[0]), + quality_reporting_tests +}; diff --git a/tester/rcfiles/empty_rc b/tester/rcfiles/empty_rc new file mode 100644 index 000000000..2fa8c43a3 --- /dev/null +++ b/tester/rcfiles/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/rcfiles/laure_rc b/tester/rcfiles/laure_rc new file mode 100644 index 000000000..283f917f7 --- /dev/null +++ b/tester/rcfiles/laure_rc @@ -0,0 +1,46 @@ +[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-9390 +video_rtp_port=9410-9910 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general +stun_server=stun.linphone.org + diff --git a/tester/rcfiles/marie_early_rc b/tester/rcfiles/marie_early_rc new file mode 100644 index 000000000..efa5408bb --- /dev/null +++ b/tester/rcfiles/marie_early_rc @@ -0,0 +1,49 @@ +[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=18070-28000 +video_rtp_port=39072-49000 + +[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 + +[net] +stun_server=stun.linphone.org + diff --git a/tester/rcfiles/marie_h264_rc b/tester/rcfiles/marie_h264_rc new file mode 100644 index 000000000..8cd970d24 --- /dev/null +++ b/tester/rcfiles/marie_h264_rc @@ -0,0 +1,53 @@ +[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 +composing_idle_timeout=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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=1 +capture=1 +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 + +[video_codec_0] +mime=H264 +rate=90000 +enabled=1 diff --git a/tester/rcfiles/marie_quality_reporting_rc b/tester/rcfiles/marie_quality_reporting_rc new file mode 100644 index 000000000..10cacfc7d --- /dev/null +++ b/tester/rcfiles/marie_quality_reporting_rc @@ -0,0 +1,49 @@ +[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 +composing_idle_timeout=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 +quality_reporting_enabled=1 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=20070-22070 +video_rtp_port=24000-25000 + +[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/rcfiles/marie_rc b/tester/rcfiles/marie_rc new file mode 100644 index 000000000..558671211 --- /dev/null +++ b/tester/rcfiles/marie_rc @@ -0,0 +1,53 @@ +[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 +composing_idle_timeout=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="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general +stun_server=stun.linphone.org + diff --git a/tester/rcfiles/marie_rc_rtcp_xr b/tester/rcfiles/marie_rc_rtcp_xr new file mode 100644 index 000000000..801ef0ebd --- /dev/null +++ b/tester/rcfiles/marie_rc_rtcp_xr @@ -0,0 +1,54 @@ +[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 +composing_idle_timeout=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 +quality_reporting_enabled=1 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=20070-22070 +video_rtp_port=24000-25000 +rtcp_xr_enabled=1 +rtcp_xr_rcvr_rtt_mode=all +rtcp_xr_rcvr_rtt_max_size=10000 +rtcp_xr_stat_summary_enabled=1 +rtcp_xr_voip_metrics_enabled=1 + +[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/rcfiles/marie_remote_404_rc b/tester/rcfiles/marie_remote_404_rc new file mode 100644 index 000000000..a47d68ce7 --- /dev/null +++ b/tester/rcfiles/marie_remote_404_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_404 diff --git a/tester/rcfiles/marie_remote_default_values_rc b/tester/rcfiles/marie_remote_default_values_rc new file mode 100644 index 000000000..966d116fd --- /dev/null +++ b/tester/rcfiles/marie_remote_default_values_rc @@ -0,0 +1,5 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_default + +[app] +toto=titi diff --git a/tester/rcfiles/marie_remote_https_rc b/tester/rcfiles/marie_remote_https_rc new file mode 100644 index 000000000..cc5343c30 --- /dev/null +++ b/tester/rcfiles/marie_remote_https_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=https://smtp.linphone.org/marie_xml diff --git a/tester/rcfiles/marie_remote_invalid_rc b/tester/rcfiles/marie_remote_invalid_rc new file mode 100644 index 000000000..3d4dca248 --- /dev/null +++ b/tester/rcfiles/marie_remote_invalid_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_invalid diff --git a/tester/rcfiles/marie_remote_invalid_uri_rc b/tester/rcfiles/marie_remote_invalid_uri_rc new file mode 100644 index 000000000..972c0a0c3 --- /dev/null +++ b/tester/rcfiles/marie_remote_invalid_uri_rc @@ -0,0 +1,3 @@ +[misc] +config-uri=/tmp/lol + diff --git a/tester/rcfiles/marie_remote_localfile2_rc b/tester/rcfiles/marie_remote_localfile2_rc new file mode 100644 index 000000000..d41ca4c8d --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile2_rc @@ -0,0 +1,11 @@ + + +
    + 0 + 1 +
    +
    + 1 + 1 +
    +
    diff --git a/tester/rcfiles/marie_remote_localfile_android_rc b/tester/rcfiles/marie_remote_localfile_android_rc new file mode 100644 index 000000000..ef0a321ce --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile_android_rc @@ -0,0 +1,3 @@ +[misc] +config-uri=file:///data/data/org.linphone.tester/files/config_files/rcfiles/marie_remote_localfile2_rc + diff --git a/tester/rcfiles/marie_remote_localfile_rc b/tester/rcfiles/marie_remote_localfile_rc new file mode 100644 index 000000000..b2f947607 --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile_rc @@ -0,0 +1,3 @@ +[misc] +config-uri=file://./rcfiles/marie_remote_localfile2_rc + diff --git a/tester/rcfiles/marie_remote_rc b/tester/rcfiles/marie_remote_rc new file mode 100644 index 000000000..c581e0995 --- /dev/null +++ b/tester/rcfiles/marie_remote_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_xml diff --git a/tester/rcfiles/marie_sips_rc b/tester/rcfiles/marie_sips_rc new file mode 100644 index 000000000..3556248b0 --- /dev/null +++ b/tester/rcfiles/marie_sips_rc @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip2.linphone.org + + +[proxy_0] +reg_proxy=sips:sip2.linphone.org +reg_route=sips:sip2.linphone.org +reg_identity="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[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 + +[net] +dns_srv_enabled=0 #no srv needed in general +stun_server=stun.linphone.org diff --git a/tester/rcfiles/marie_transient_remote_rc b/tester/rcfiles/marie_transient_remote_rc new file mode 100644 index 000000000..138da3cc1 --- /dev/null +++ b/tester/rcfiles/marie_transient_remote_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_transient_xml diff --git a/tester/rcfiles/marie_zrtp_aes256_rc b/tester/rcfiles/marie_zrtp_aes256_rc new file mode 100644 index 000000000..2230535b6 --- /dev/null +++ b/tester/rcfiles/marie_zrtp_aes256_rc @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 +zrtp_cipher_suites=MS_ZRTP_CIPHER_AES3,MS_ZRTP_CIPHER_AES1 + +[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="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/marie_zrtp_b256_rc b/tester/rcfiles/marie_zrtp_b256_rc new file mode 100644 index 000000000..a9668f2f9 --- /dev/null +++ b/tester/rcfiles/marie_zrtp_b256_rc @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 +zrtp_sas_suites=MS_ZRTP_SAS_B256 + +[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="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/marie_zrtp_srtpsuite_aes256_rc b/tester/rcfiles/marie_zrtp_srtpsuite_aes256_rc new file mode 100644 index 000000000..3dc5b4d6a --- /dev/null +++ b/tester/rcfiles/marie_zrtp_srtpsuite_aes256_rc @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 +srtp_crypto_suites=AES_CM_256_HMAC_SHA1_80,AES_CM_256_HMAC_SHA1_32 + +[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="Super Marie" +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=18070-28000 +video_rtp_port=28070-38000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/multi_account_rc b/tester/rcfiles/multi_account_rc new file mode 100644 index 000000000..8aefbfcaf --- /dev/null +++ b/tester/rcfiles/multi_account_rc @@ -0,0 +1,64 @@ +[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 +realm=auth1.example.org + +[proxy_3] +reg_proxy=auth1.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 +realm=auth1.example.org + diff --git a/tester/rcfiles/pauline_alt_rc b/tester/rcfiles/pauline_alt_rc new file mode 100644 index 000000000..c8e730729 --- /dev/null +++ b/tester/rcfiles/pauline_alt_rc @@ -0,0 +1,22 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +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/rcfiles/pauline_h264_rc b/tester/rcfiles/pauline_h264_rc new file mode 100644 index 000000000..158f45fe5 --- /dev/null +++ b/tester/rcfiles/pauline_h264_rc @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=1 +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 + +[video_codec_0] +mime=H264 +rate=90000 +enabled=1 diff --git a/tester/rcfiles/pauline_rc b/tester/rcfiles/pauline_rc new file mode 100644 index 000000000..50920606b --- /dev/null +++ b/tester/rcfiles/pauline_rc @@ -0,0 +1,51 @@ +[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 +composing_idle_timeout=1 + +[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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general +stun_server=stun.linphone.org diff --git a/tester/rcfiles/pauline_rc_rtcp_xr b/tester/rcfiles/pauline_rc_rtcp_xr new file mode 100644 index 000000000..1648b508a --- /dev/null +++ b/tester/rcfiles/pauline_rc_rtcp_xr @@ -0,0 +1,52 @@ +[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 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 +rtcp_xr_enabled=1 +rtcp_xr_rcvr_rtt_mode=all +rtcp_xr_rcvr_rtt_max_size=10000 +rtcp_xr_stat_summary_enabled=1 +rtcp_xr_voip_metrics_enabled=1 + +[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/rcfiles/pauline_sips_rc b/tester/rcfiles/pauline_sips_rc new file mode 100644 index 000000000..f248cffc1 --- /dev/null +++ b/tester/rcfiles/pauline_sips_rc @@ -0,0 +1,50 @@ +[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 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sips:sip2.linphone.org +reg_route=sips:sip2.linphone.org +reg_identity=sips: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=18070-28000 +video_rtp_port=39072-49000 + +[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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/pauline_tcp_rc b/tester/rcfiles/pauline_tcp_rc new file mode 100644 index 000000000..f3a3ef568 --- /dev/null +++ b/tester/rcfiles/pauline_tcp_rc @@ -0,0 +1,51 @@ +[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 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +stun_server=stun.linphone.org + diff --git a/tester/rcfiles/pauline_wild_rc b/tester/rcfiles/pauline_wild_rc new file mode 100644 index 000000000..1d0d9b164 --- /dev/null +++ b/tester/rcfiles/pauline_wild_rc @@ -0,0 +1,31 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +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/rcfiles/pauline_zrtp_aes256_rc b/tester/rcfiles/pauline_zrtp_aes256_rc new file mode 100644 index 000000000..5f1af185d --- /dev/null +++ b/tester/rcfiles/pauline_zrtp_aes256_rc @@ -0,0 +1,51 @@ +[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 +composing_idle_timeout=1 +zrtp_cipher_suites=MS_ZRTP_CIPHER_AES3,MS_ZRTP_CIPHER_AES1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/pauline_zrtp_b256_rc b/tester/rcfiles/pauline_zrtp_b256_rc new file mode 100644 index 000000000..cf74f3fa7 --- /dev/null +++ b/tester/rcfiles/pauline_zrtp_b256_rc @@ -0,0 +1,51 @@ +[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 +composing_idle_timeout=1 +zrtp_sas_suites=MS_ZRTP_SAS_B256 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/pauline_zrtp_srtpsuite_aes256_rc b/tester/rcfiles/pauline_zrtp_srtpsuite_aes256_rc new file mode 100644 index 000000000..b79b11874 --- /dev/null +++ b/tester/rcfiles/pauline_zrtp_srtpsuite_aes256_rc @@ -0,0 +1,51 @@ +[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 +composing_idle_timeout=1 +srtp_crypto_suites=AES_CM_256_HMAC_SHA1_80,AES_CM_256_HMAC_SHA1_32 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +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=18070-28000 +video_rtp_port=39072-49000 + +[video] +display=0 +capture=0 +show_local=0 +size=qcif +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 + +[net] +dns_srv_enabled=0 #no srv needed in general diff --git a/tester/rcfiles/remote_zero_length_params_rc b/tester/rcfiles/remote_zero_length_params_rc new file mode 100644 index 000000000..915722787 --- /dev/null +++ b/tester/rcfiles/remote_zero_length_params_rc @@ -0,0 +1,7 @@ + + +
    + + test +
    +
    diff --git a/tester/rcfiles/stun_rc b/tester/rcfiles/stun_rc new file mode 100644 index 000000000..954a83b6c --- /dev/null +++ b/tester/rcfiles/stun_rc @@ -0,0 +1,2 @@ + [net] + firewall_policy=2 diff --git a/tester/rcfiles/upnp_rc b/tester/rcfiles/upnp_rc new file mode 100644 index 000000000..3b04fd077 --- /dev/null +++ b/tester/rcfiles/upnp_rc @@ -0,0 +1,2 @@ + [net] + firewall_policy=4 diff --git a/tester/rcfiles/zero_length_params_rc b/tester/rcfiles/zero_length_params_rc new file mode 100644 index 000000000..108749a5d --- /dev/null +++ b/tester/rcfiles/zero_length_params_rc @@ -0,0 +1,3 @@ +[test] +zero_len= +non_zero_len=test diff --git a/tester/register_tester.c b/tester/register_tester.c new file mode 100644 index 000000000..ab159ea2a --- /dev/null +++ b/tester/register_tester.c @@ -0,0 +1,904 @@ +/* + 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 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, see . +*/ + + +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + + +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + LinphoneAuthInfo *info; + 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*/ +} + + + +static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { + LinphoneCoreManager* lcm=linphone_core_manager_new(NULL); + + if (with_auth) { + LinphoneCoreVTable* vtable = linphone_core_v_table_new(); + vtable->auth_info_requested=auth_info_requested; + linphone_core_add_listener(lcm->lc,vtable); + } + + /*to allow testing with 127.0.0.1*/ + linphone_core_set_network_reachable(lcm->lc,TRUE); + return lcm; +} + +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: + BC_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; + + BC_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++ <(1100 /*only wait 11 s if final state is progress*/+(expected_final_state==LinphoneRegistrationProgress?0:2000))) { + 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)) { + BC_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized, int, "%d"); + 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 + || (counters->number_of_auth_info_requested>2 &&linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonUnauthorized)) /*no need to continue if auth cannot be found*/ + break; /*no need to continue*/ + ms_usleep(10000); + } + + BC_ASSERT_EQUAL(linphone_proxy_config_is_registered(proxy_cfg), expected_final_state == LinphoneRegistrationOk, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0, int, "%d"); + BC_ASSERT_TRUE(counters->number_of_LinphoneRegistrationProgress>=1); + if (expected_final_state == LinphoneRegistrationOk) { + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0), int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,late_auth_info?1:0, int, "%d"); + } else + /*checking to be done outside this functions*/ + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0, int, "%d"); + +} + +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); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1, int, "%d"); +} + +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++ <200) { + linphone_core_iterate(lcm->lc); + ms_usleep(10000); + } + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2, int, "%d"); + + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0, int, "%d"); + + linphone_core_manager_destroy(lcm); +} + +static void simple_register(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + register_with_refresh(lcm,FALSE,NULL,NULL); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + +static void register_with_custom_headers(void){ + LinphoneCoreManager *marie=linphone_core_manager_new("marie_rc"); + LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(marie->lc); + int initial_register_ok=marie->stat.number_of_LinphoneRegistrationOk; + const char *value; + + linphone_core_set_network_reachable(marie->lc, FALSE); + linphone_proxy_config_set_custom_header(cfg, "ah-bah-ouais", "...mais bon."); + /*unfortunately it is difficult to programmatically check that sent custom headers are actually sent. + * A server development would be required here.*/ + + linphone_core_set_network_reachable(marie->lc, TRUE); + wait_for(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk,initial_register_ok+1); + value=linphone_proxy_config_get_custom_header(cfg, "Server"); + BC_ASSERT_PTR_NOT_NULL(value); + if (value) BC_ASSERT_PTR_NOT_NULL(strstr(value, "Flexisip")); + linphone_core_manager_destroy(marie); +} + +static void simple_unregister(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + register_with_refresh_base(lcm->lc,FALSE,NULL,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + + linphone_proxy_config_edit(proxy_config); + reset_counters(counters); /*clear stats*/ + + /*nothing is supposed to arrive until done*/ + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_enable_register(proxy_config,FALSE); + linphone_proxy_config_done(proxy_config); + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1)); + linphone_core_manager_destroy(lcm); +} + +static void change_expires(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + register_with_refresh_base(lcm->lc,FALSE,NULL,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + + linphone_proxy_config_edit(proxy_config); + reset_counters(counters); /*clear stats*/ + + /*nothing is supposed to arrive until done*/ + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + + linphone_proxy_config_set_expires(proxy_config,3); + + linphone_proxy_config_done(proxy_config); + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*wait 2s without receive refresh*/ + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,2,2000)); + /* now, it should be ok*/ + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,2)); + + + 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); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + 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); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,1, int, "%d"); + 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(){ + if (transport_supported(LinphoneTransportTls)) { + char route[256]; + LinphoneCoreManager* lcm = create_lcm(); + sprintf(route,"sip:%s;transport=tls",test_route); + 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); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + +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); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + +static void authenticated_register_with_no_initial_credentials(){ + LinphoneCoreManager *lcm; + LinphoneCoreVTable* vtable = linphone_core_v_table_new(); + stats* counters; + char route[256]; + + sprintf(route,"sip:%s",test_route); + + lcm = linphone_core_manager_new(NULL); + + vtable->auth_info_requested=auth_info_requested; + linphone_core_add_listener(lcm->lc,vtable); + + counters= get_stats(lcm->lc); + counters->number_of_auth_info_requested=0; + register_with_refresh(lcm,FALSE,auth_domain,route); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,1, int, "%d"); + linphone_core_manager_destroy(lcm); +} + + +static void authenticated_register_with_late_credentials(){ + LinphoneCoreManager *lcm; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + char route[256]; + + sprintf(route,"sip:%s",test_route); + + lcm = linphone_core_manager_new(NULL); + + counters = get_stats(lcm->lc); + register_with_refresh_base_2(lcm->lc,FALSE,auth_domain,route,TRUE,transport); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,1, int, "%d"); + linphone_core_manager_destroy(lcm); +} + +static void authenticated_register_with_wrong_late_credentials(){ + LinphoneCoreManager *lcm; + 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 pourri"; + + test_password=wrong_passwd; + + sprintf(route,"sip:%s",test_route); + + lcm = linphone_core_manager_new(NULL); + + counters = get_stats(lcm->lc); + register_with_refresh_base_3(lcm->lc,FALSE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,2, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,2, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2, int, "%d"); + test_password=saved_test_passwd; + + linphone_core_manager_destroy(lcm); +} + +static void authenticated_register_with_wrong_credentials_with_params_base(const char* user_agent,LinphoneCoreManager *lcm) { + 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); + + sal_set_refresher_retry_after(lcm->lc->sal,500); + if (user_agent) { + linphone_core_set_user_agent(lcm->lc,user_agent,NULL); + } + linphone_core_add_auth_info(lcm->lc,info); /*add wrong authentication info to LinphoneCore*/ + counters = get_stats(lcm->lc); + register_with_refresh_base_3(lcm->lc,TRUE,auth_domain,route,FALSE,transport,LinphoneRegistrationFailed); + //BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,3, int, "%d"); register_with_refresh_base_3 does not alow to precisely check number of number_of_auth_info_requested + /*wait for retry*/ + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_auth_info_requested,4)); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1, int, "%d"); + + /*check the detailed error info */ + if (!user_agent || strcmp(user_agent,"tester-no-403")!=0){ + LinphoneProxyConfig *cfg=NULL; + linphone_core_get_default_proxy(lcm->lc,&cfg); + BC_ASSERT_PTR_NOT_NULL(cfg); + if (cfg){ + const LinphoneErrorInfo *ei=linphone_proxy_config_get_error_info(cfg); + const char *phrase=linphone_error_info_get_phrase(ei); + BC_ASSERT_PTR_NOT_NULL(phrase); + if (phrase) BC_ASSERT_STRING_EQUAL(phrase,"Forbidden"); + BC_ASSERT_EQUAL(linphone_error_info_get_protocol_code(ei),403, int, "%d"); + BC_ASSERT_PTR_NULL(linphone_error_info_get_details(ei)); + } + + } + } +static void authenticated_register_with_wrong_credentials_with_params(const char* user_agent) { + LinphoneCoreManager *lcm = linphone_core_manager_new(NULL); + authenticated_register_with_wrong_credentials_with_params_base(user_agent,lcm); + linphone_core_manager_destroy(lcm); +} +static void authenticated_register_with_wrong_credentials() { + authenticated_register_with_wrong_credentials_with_params(NULL); +} +static void authenticated_register_with_wrong_credentials_2() { + LinphoneCoreManager *lcm = linphone_core_manager_new(NULL); + stats* counters = get_stats(lcm->lc); + int current_in_progress; + LinphoneProxyConfig* proxy; + + authenticated_register_with_wrong_credentials_with_params_base(NULL,lcm); + + linphone_core_get_default_proxy(lcm->lc,&proxy); + /*Make sure registration attempts are stopped*/ + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_register(proxy,FALSE); + linphone_proxy_config_done(proxy); + current_in_progress=counters->number_of_LinphoneRegistrationProgress; + BC_ASSERT_FALSE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationProgress,current_in_progress+1)); + + linphone_core_manager_destroy(lcm); +} +static void authenticated_register_with_wrong_credentials_without_403() { + authenticated_register_with_wrong_credentials_with_params("tester-no-403"); +} +static LinphoneCoreManager* configure_lcm(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager *lcm=linphone_core_manager_new2( "multi_account_rc", FALSE); + stats *counters=&lcm->stat; + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(lcm->lc)))); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0, int, "%d"); + return lcm; + } + return NULL; +} + +static void multiple_proxy(){ + LinphoneCoreManager *lcm=configure_lcm(); + if (lcm) { + linphone_core_manager_destroy(lcm); + } +} + +static void network_state_change(){ + int register_ok; + stats *counters; + LinphoneCoreManager *lcm=configure_lcm(); + if (lcm) { + LinphoneCore *lc=lcm->lc; + + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + linphone_core_set_network_reachable(lc,FALSE); + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_NetworkReachableFalse,1)); + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_NetworkReachableTrue,1)); + wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); + + linphone_core_manager_destroy(lcm); + } +} +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 *lcm; + 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; + + lcm=configure_lcm(); + if (lcm) { + memset(&sip_tr,0,sizeof(sip_tr)); + lc=lcm->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); + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); + + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,total_number_of_proxies-number_of_udp_proxy)); + + linphone_core_manager_destroy(lcm); + } +} + +static void proxy_transport_change(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAddress* addr; + char* addr_as_string; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base(lcm->lc,FALSE,auth_domain,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + reset_counters(counters); /*clear stats*/ + linphone_proxy_config_edit(proxy_config); + + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + addr = linphone_address_new(linphone_proxy_config_get_addr(proxy_config)); + + if (LinphoneTransportTcp == linphone_address_get_transport(addr)) { + linphone_address_set_transport(addr,LinphoneTransportUdp); + } else { + linphone_address_set_transport(addr,LinphoneTransportTcp); + } + linphone_proxy_config_set_server_addr(proxy_config,addr_as_string=linphone_address_as_string(addr)); + + linphone_proxy_config_done(proxy_config); + + BC_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*as we change p[roxy server destination, we should'nt be notified about the clear*/ + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0, int, "%d"); + ms_free(addr_as_string); + linphone_address_destroy(addr); + linphone_core_manager_destroy(lcm); + +} +static void proxy_transport_change_with_wrong_port() { + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + LCSipTransports transport= {LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM}; + sprintf(route,"sip:%s",test_route); + + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base_3(lcm->lc, FALSE, auth_domain, "sip2.linphone.org:5987", 0,transport,LinphoneRegistrationProgress); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + linphone_proxy_config_edit(proxy_config); + + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_set_server_addr(proxy_config,route); + linphone_proxy_config_done(proxy_config); + + BC_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*as we change proxy server destination, we should'nt be notified about the clear*/ + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0, int, "%d"); + + linphone_core_manager_destroy(lcm); + +} + +static void proxy_transport_change_with_wrong_port_givin_up() { + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + LCSipTransports transport= {LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM}; + sprintf(route,"sip:%s",test_route); + + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base_3(lcm->lc, FALSE, auth_domain, "sip2.linphone.org:5987", 0,transport,LinphoneRegistrationProgress); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + linphone_proxy_config_edit(proxy_config); + + BC_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_enableregister(proxy_config,FALSE); + linphone_proxy_config_done(proxy_config); + + BC_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1)); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,0, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1, int, "%d"); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0, int, "%d"); + + linphone_core_manager_destroy(lcm); + +} + +static void io_recv_error(){ + LinphoneCoreManager *lcm; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + + + lcm=configure_lcm(); + if (lcm) { + lc=lcm->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); + + BC_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); + + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_manager_destroy(lcm); + } +} + +static void io_recv_error_retry_immediatly(){ + LinphoneCoreManager *lcm; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + + lcm=configure_lcm(); + if (lcm) { + lc=lcm->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); + + BC_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); + sal_set_recv_error(lc->sal, 1); /*reset*/ + + BC_ASSERT_TRUE(wait_for_until(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy+register_ok,30000)); + + linphone_core_manager_destroy(lcm); + } +} + +static void io_recv_error_late_recovery(){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager *lcm; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + MSList* lcs; + lcm=linphone_core_manager_new2( "multi_account_rc",FALSE); /*to make sure iterates are not call yet*/ + lc=lcm->lc; + sal_set_refresher_retry_after(lc->sal,1000); + counters=&lcm->stat; + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(lcm->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); + + BC_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); + + BC_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)+3000)); + + sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_send_error(lc->sal, 0); + + BC_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)+3000)); + linphone_core_manager_destroy(lcm); + } +} + +static void io_recv_error_without_active_register(){ + LinphoneCoreManager *lcm; + LinphoneCore* lc; + int register_ok; + stats* counters ; + MSList* proxys; + int dummy=0; + + lcm=configure_lcm(); + if (lcm) { + lc=lcm->lc; + counters = get_stats(lc); + + register_ok=counters->number_of_LinphoneRegistrationOk; + + 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_enableregister(proxy_cfg,FALSE); + linphone_proxy_config_done(proxy_cfg); + } + ms_list_free(proxys); + /*wait for unregistrations*/ + BC_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*/ + wait_for_until(lc,lc, &dummy, 1, 3000); + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress, ms_list_size(linphone_core_get_proxy_config_list(lc)), int, "%d"); + + BC_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0,int,"%d"); + + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_manager_destroy(lcm); + } +} + + +static void tls_certificate_failure(){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* lcm; + LinphoneCore *lc; + char *rootcapath = bc_tester_res("certificates/cn/agent.pem"); /*bad root ca*/ + + lcm=linphone_core_manager_new2("pauline_rc",FALSE); + lc=lcm->lc; + linphone_core_set_root_ca(lcm->lc,rootcapath); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&lcm->stat.number_of_LinphoneRegistrationFailed,1)); + linphone_core_set_root_ca(lcm->lc,NULL); /*no root ca*/ + linphone_core_refresh_registers(lcm->lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationFailed,2)); + ms_free(rootcapath); + rootcapath = bc_tester_res("certificates/cn/cafile.pem"); /*good root ca*/ + linphone_core_set_root_ca(lcm->lc,rootcapath); + linphone_core_refresh_registers(lcm->lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,1)); + BC_ASSERT_EQUAL(lcm->stat.number_of_LinphoneRegistrationFailed,2, int, "%d"); + linphone_core_manager_destroy(lcm); + ms_free(rootcapath); + } +} + +/*the purpose of this test is to check that will not block the proxy config during SSL handshake for entire life in case of mistaken configuration*/ +static void tls_with_non_tls_server(){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager *lcm; + LinphoneProxyConfig* proxy_cfg; + LinphoneAddress* addr; + char tmp[256]; + LinphoneCore *lc; + + lcm=linphone_core_manager_new2( "marie_rc", 0); + lc=lcm->lc; + sal_set_transport_timeout(lc->sal,3000); + 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); + BC_ASSERT_TRUE(wait_for_until(lc,lc,&lcm->stat.number_of_LinphoneRegistrationFailed,1,5000)); + linphone_core_manager_destroy(lcm); + } +} + +static void tls_alt_name_register(){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* lcm; + LinphoneCore *lc; + char *rootcapath = bc_tester_res("certificates/cn/cafile.pem"); + + lcm=linphone_core_manager_new2("pauline_alt_rc",FALSE); + lc=lcm->lc; + linphone_core_set_root_ca(lc,rootcapath); + linphone_core_refresh_registers(lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,1)); + BC_ASSERT_EQUAL(lcm->stat.number_of_LinphoneRegistrationFailed,0, int, "%d"); + linphone_core_manager_destroy(lcm); + ms_free(rootcapath); + } +} + +static void tls_wildcard_register(){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* lcm; + LinphoneCore *lc; + char *rootcapath = bc_tester_res("certificates/cn/cafile.pem"); + + lcm=linphone_core_manager_new2("pauline_wild_rc",FALSE); + lc=lcm->lc; + linphone_core_set_root_ca(lc,rootcapath); + linphone_core_refresh_registers(lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,2)); + BC_ASSERT_EQUAL(lcm->stat.number_of_LinphoneRegistrationFailed,0, int, "%d"); + linphone_core_manager_destroy(lcm); + ms_free(rootcapath); + } +} + +static void redirect(){ + char route[256]; + LinphoneCoreManager* lcm; + LCSipTransports transport = {-1,0,0,0}; + sprintf(route,"sip:%s:5064",test_route); + lcm = create_lcm(); + if (lcm) { + linphone_core_set_user_agent(lcm->lc,"redirect",NULL); + register_with_refresh_base_2(lcm->lc,FALSE,test_domain,route,FALSE,transport); + linphone_core_manager_destroy(lcm); + } +} + +test_t register_tests[] = { + { "Simple register", simple_register }, + { "Simple register unregister", simple_unregister }, + { "TCP register", simple_tcp_register }, + { "Register with custom headers", register_with_custom_headers }, + { "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 }, + { "Digest auth with wrong credentials, check if registration attempts are stopped", authenticated_register_with_wrong_credentials_2 }, + { "Digest auth with wrong credentials without 403", authenticated_register_with_wrong_credentials_without_403}, + { "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 changes", transport_change }, + { "Proxy transport changes", proxy_transport_change}, + { "Proxy transport changes with wrong address at first", proxy_transport_change_with_wrong_port}, + { "Proxy transport changes with wrong address, giving up",proxy_transport_change_with_wrong_port_givin_up}, + { "Change expires", change_expires}, + { "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}, + { "Simple redirect", redirect} +}; + +test_suite_t register_test_suite = { + "Register", + liblinphone_tester_setup, + NULL, + sizeof(register_tests) / sizeof(register_tests[0]), + register_tests +}; + diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c new file mode 100644 index 000000000..ac6e5602f --- /dev/null +++ b/tester/remote_provisioning_tester.c @@ -0,0 +1,143 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + stats* counters; + ms_message("Configuring state = %i with message %s", status, message?message:""); + + counters = get_stats(lc); + if (status == LinphoneConfiguringSkipped) { + counters->number_of_LinphoneConfiguringSkipped++; + } else if (status == LinphoneConfiguringFailed) { + counters->number_of_LinphoneConfiguringFailed++; + } else if (status == LinphoneConfiguringSuccessful) { + counters->number_of_LinphoneConfiguringSuccessful++; + } +} + +static void remote_provisioning_skipped(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSkipped,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_http(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_transient(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_transient_remote_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); + BC_ASSERT_TRUE(linphone_core_is_provisioning_transient(marie->lc)); + BC_ASSERT_PTR_NULL(linphone_core_get_provisioning_uri(marie->lc)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_https(void) { + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_https_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); + linphone_core_manager_destroy(marie); + } +} + +static void remote_provisioning_not_found(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_404_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_invalid(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_invalid_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_invalid_uri(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_invalid_uri_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_default_values(void) { + LinphoneProxyConfig *lpc; + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_default_values_rc", FALSE); + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + lpc = linphone_core_create_proxy_config(marie->lc); + BC_ASSERT_TRUE(lpc->reg_sendregister); + BC_ASSERT_EQUAL(lpc->expires, 604800, int, "%d"); + BC_ASSERT_STRING_EQUAL(lpc->reg_proxy, ""); + BC_ASSERT_STRING_EQUAL(lpc->reg_route, ""); + BC_ASSERT_STRING_EQUAL(lpc->reg_identity, "sip:?@sip.linphone.org"); + { + LpConfig* lp = linphone_core_get_config(marie->lc); + BC_ASSERT_STRING_EQUAL(lp_config_get_string(lp,"app","toto","empty"),"titi"); + } + linphone_proxy_config_destroy(lpc); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_file(void) { + LinphoneCoreManager* marie; + const LpConfig* conf; +#if TARGET_OS_IPHONE + ms_message("Skipping remote provisioning from file on iOS"); + return; +#elif defined(ANDROID) + marie = linphone_core_manager_new2("marie_remote_localfile_android_rc", FALSE); +#else + marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE); +#endif + BC_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + + conf = linphone_core_get_config( marie->lc ); + BC_ASSERT_EQUAL( lp_config_get_int(conf,"misc","tester_file_ok", 0), 1 , int, "%d"); + + linphone_core_manager_destroy(marie); +} + + +test_t remote_provisioning_tests[] = { + { "Remote provisioning skipped", remote_provisioning_skipped }, + { "Remote provisioning successful behind http", remote_provisioning_http }, + { "Remote provisioning successful behind https", remote_provisioning_https }, + { "Remote provisioning 404 not found", remote_provisioning_not_found }, + { "Remote provisioning invalid", remote_provisioning_invalid }, + { "Remote provisioning transient successful", remote_provisioning_transient }, + { "Remote provisioning default values", remote_provisioning_default_values }, + { "Remote provisioning from file", remote_provisioning_file }, + { "Remote provisioning invalid URI", remote_provisioning_invalid_uri } +}; + +test_suite_t remote_provisioning_test_suite = { + "RemoteProvisioning", + NULL, + NULL, + sizeof(remote_provisioning_tests) / sizeof(remote_provisioning_tests[0]), + remote_provisioning_tests +}; diff --git a/tester/setup_tester.c b/tester/setup_tester.c new file mode 100644 index 000000000..c24aa27b8 --- /dev/null +++ b/tester/setup_tester.c @@ -0,0 +1,316 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#include "linphonecore.h" +#include "liblinphone_tester.h" +#include "lpconfig.h" +#include "private.h" + +static void linphone_version_test(void){ + const char *version=linphone_core_get_version(); + /*make sure the git version is always included in the version number*/ + BC_ASSERT_PTR_NULL(strstr(version,"unknown")); +} + +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); + BC_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); + BC_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_get_sip_transports(lc,&tr); + BC_ASSERT_EQUAL(tr.udp_port,5060, int, "%d"); /*default config*/ + BC_ASSERT_EQUAL(tr.tcp_port,5060, int, "%d"); /*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); + + BC_ASSERT_NOT_EQUAL(tr.udp_port,5060,int,"%d"); /*default config*/ + BC_ASSERT_NOT_EQUAL(tr.tcp_port,5060,int,"%d"); /*default config*/ + + BC_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_port",-2),LC_SIP_TRANSPORT_RANDOM, int, "%d"); + BC_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tcp_port",-2),LC_SIP_TRANSPORT_RANDOM, int, "%d"); + BC_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tls_port",-2),LC_SIP_TRANSPORT_RANDOM, int, "%d"); + + 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 ); + BC_ASSERT_PTR_NOT_NULL_FATAL ( lc ); + + address = linphone_core_interpret_url(lc, sips_address); + + BC_ASSERT_PTR_NOT_NULL_FATAL(address); + BC_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_scheme(address), "sips"); + BC_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_username(address), "margaux"); + BC_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_domain(address), "sip.linphone.org"); + + linphone_address_destroy(address); + + linphone_core_destroy ( lc ); +} + +static void linphone_lpconfig_from_buffer(){ + const char* buffer = "[buffer]\ntest=ok"; + const char* buffer_linebreaks = "[buffer_linebreaks]\n\n\n\r\n\n\r\ntest=ok"; + LpConfig* conf; + + conf = lp_config_new_from_buffer(buffer); + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"buffer","test",""),"ok"); + lp_config_destroy(conf); + + conf = lp_config_new_from_buffer(buffer_linebreaks); + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"buffer_linebreaks","test",""),"ok"); + lp_config_destroy(conf); +} + +static void linphone_lpconfig_from_buffer_zerolen_value(){ + /* parameters that have no value should return NULL, not "". */ + const char* zerolen = "[test]\nzero_len=\nnon_zero_len=test"; + LpConfig* conf; + + conf = lp_config_new_from_buffer(zerolen); + + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","zero_len","LOL"),"LOL"); + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len",""),"test"); + + lp_config_set_string(conf, "test", "non_zero_len", ""); /* should remove "non_zero_len" */ + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len","LOL"), "LOL"); + + lp_config_destroy(conf); +} + +static void linphone_lpconfig_from_file_zerolen_value(){ + /* parameters that have no value should return NULL, not "". */ + const char* zero_rc_file = "zero_length_params_rc"; + char* rc_path = ms_strdup_printf("%s/rcfiles/%s", bc_tester_get_resource_dir_prefix(), zero_rc_file); + LpConfig* conf; + + /* not using lp_config_new() because it expects a readable file, and iOS (for instance) + stores the app bundle in read-only */ + conf = lp_config_new_with_factory(NULL, rc_path); + + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","zero_len","LOL"),"LOL"); + + // non_zero_len=test -> should return test + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len",""),"test"); + + lp_config_set_string(conf, "test", "non_zero_len", ""); /* should remove "non_zero_len" */ + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len","LOL"), "LOL"); + + ms_free(rc_path); + lp_config_destroy(conf); +} + +static void linphone_lpconfig_from_xml_zerolen_value(){ + const char* zero_xml_file = "remote_zero_length_params_rc"; + char* xml_path = ms_strdup_printf("%s/rcfiles/%s", bc_tester_get_resource_dir_prefix(), zero_xml_file); + LpConfig* conf; + + LinphoneCoreManager* mgr = linphone_core_manager_new2("empty_rc",FALSE); + + BC_ASSERT_EQUAL(linphone_remote_provisioning_load_file(mgr->lc, xml_path), 0, int, "%d"); + + conf = mgr->lc->config; + + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","zero_len","LOL"),"LOL"); + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len",""),"test"); + + lp_config_set_string(conf, "test", "non_zero_len", ""); /* should remove "non_zero_len" */ + BC_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"test","non_zero_len","LOL"), "LOL"); + + linphone_core_manager_destroy(mgr); + ms_free(xml_path); +} + +void linphone_proxy_config_address_equal_test() { + LinphoneAddress *a = linphone_address_new("sip:toto@titi"); + LinphoneAddress *b = linphone_address_new("sips:toto@titi"); + LinphoneAddress *c = linphone_address_new("sip:toto@titi;transport=tcp"); + LinphoneAddress *d = linphone_address_new("sip:toto@titu"); + LinphoneAddress *e = linphone_address_new("sip:toto@titi;transport=udp"); + LinphoneAddress *f = linphone_address_new("sip:toto@titi?X-Create-Account=yes"); + + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,NULL), LinphoneProxyConfigAddressDifferent, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,b), LinphoneProxyConfigAddressDifferent, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,c), LinphoneProxyConfigAddressDifferent, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,d), LinphoneProxyConfigAddressDifferent, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,e), LinphoneProxyConfigAddressWeakEqual, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(NULL,NULL), LinphoneProxyConfigAddressEqual, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(a,f), LinphoneProxyConfigAddressWeakEqual, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(c,f), LinphoneProxyConfigAddressDifferent, int, "%d"); + BC_ASSERT_EQUAL(linphone_proxy_config_address_equal(e,f), LinphoneProxyConfigAddressWeakEqual, int, "%d"); + + linphone_address_destroy(a); + linphone_address_destroy(b); + linphone_address_destroy(c); + linphone_address_destroy(d); +} + +void linphone_proxy_config_is_server_config_changed_test() { + LinphoneProxyConfig* proxy_config = linphone_proxy_config_new(); + + linphone_proxy_config_done(proxy_config); /*test done without edit*/ + + linphone_proxy_config_set_identity(proxy_config,"sip:toto@titi"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_identity(proxy_config,"sips:toto@titi"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent, int, "%d"); + + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_server_addr(proxy_config,"sip:toto.com"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent, int, "%d"); + + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org:4444"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent, int, "%d"); + + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;transport=tcp"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressDifferent, int, "%d"); + + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;param=blue"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressWeakEqual, int, "%d"); + + + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_contact_parameters(proxy_config,"blabla=blue"); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressEqual, int, "%d"); + + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_enable_register(proxy_config,TRUE); + BC_ASSERT_EQUAL(linphone_proxy_config_is_server_config_changed(proxy_config), LinphoneProxyConfigAddressEqual, int, "%d"); + + linphone_proxy_config_destroy(proxy_config); +} + +static void chat_room_test(void) { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + memset (&v_table,0,sizeof(v_table)); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + BC_ASSERT_PTR_NOT_NULL_FATAL(lc); + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room_from_uri(lc,"sip:toto@titi.com")); + linphone_core_destroy(lc); +} + +static void devices_reload_test(void) { + char *devid1; + char *devid2; + LinphoneCoreManager *mgr = linphone_core_manager_new2("empty_rc", FALSE); + + devid1 = ms_strdup(linphone_core_get_capture_device(mgr->lc)); + linphone_core_reload_sound_devices(mgr->lc); + devid2 = ms_strdup(linphone_core_get_capture_device(mgr->lc)); + BC_ASSERT_STRING_EQUAL(devid1, devid2); + ms_free(devid1); + ms_free(devid2); + + devid1 = ms_strdup(linphone_core_get_video_device(mgr->lc)); + linphone_core_reload_video_devices(mgr->lc); + devid2 = ms_strdup(linphone_core_get_video_device(mgr->lc)); + BC_ASSERT_STRING_EQUAL(devid1, devid2); + ms_free(devid1); + ms_free(devid2); + + linphone_core_manager_destroy(mgr); +} + +static void codec_usability_test(void) { + LinphoneCoreManager *mgr = linphone_core_manager_new2("empty_rc", FALSE); + PayloadType *pt = linphone_core_find_payload_type(mgr->lc, "PCMU", 8000, -1); + + BC_ASSERT_PTR_NOT_NULL(pt); + if (!pt) goto end; + /*no limit*/ + linphone_core_set_upload_bandwidth(mgr->lc, 0); + linphone_core_set_download_bandwidth(mgr->lc, 0); + BC_ASSERT_TRUE(linphone_core_check_payload_type_usability(mgr->lc, pt)); + /*low limit*/ + linphone_core_set_upload_bandwidth(mgr->lc, 50); + linphone_core_set_download_bandwidth(mgr->lc, 50); + BC_ASSERT_FALSE(linphone_core_check_payload_type_usability(mgr->lc, pt)); + + /*reasonable limit*/ + linphone_core_set_upload_bandwidth(mgr->lc, 200); + linphone_core_set_download_bandwidth(mgr->lc, 200); + BC_ASSERT_TRUE(linphone_core_check_payload_type_usability(mgr->lc, pt)); + +end: + linphone_core_manager_destroy(mgr); +} + +test_t setup_tests[] = { + { "Version check", linphone_version_test }, + { "Linphone Address", linphone_address_test }, + { "Linphone proxy config address equal (internal api)", linphone_proxy_config_address_equal_test}, + { "Linphone proxy config server address change (internal api)", linphone_proxy_config_is_server_config_changed_test}, + { "Linphone core init/uninit", core_init_test }, + { "Linphone random transport port",core_sip_transport_test}, + { "Linphone interpret url", linphone_interpret_url_test }, + { "LPConfig from buffer", linphone_lpconfig_from_buffer }, + { "LPConfig zero_len value from buffer", linphone_lpconfig_from_buffer_zerolen_value }, + { "LPConfig zero_len value from file", linphone_lpconfig_from_file_zerolen_value }, + { "LPConfig zero_len value from XML", linphone_lpconfig_from_xml_zerolen_value }, + { "Chat room", chat_room_test }, + { "Devices reload", devices_reload_test }, + { "Codec usability", codec_usability_test } +}; + +test_suite_t setup_test_suite = { + "Setup", + liblinphone_tester_setup, + NULL, + sizeof(setup_tests) / sizeof(setup_tests[0]), + setup_tests +}; + diff --git a/tester/sounds/ahbahouaismaisbon.wav b/tester/sounds/ahbahouaismaisbon.wav new file mode 100644 index 000000000..dca22773a Binary files /dev/null and b/tester/sounds/ahbahouaismaisbon.wav differ diff --git a/tester/sounds/hello8000.mkv b/tester/sounds/hello8000.mkv new file mode 100644 index 000000000..812d62563 Binary files /dev/null and b/tester/sounds/hello8000.mkv differ diff --git a/tester/sounds/hello8000.wav b/tester/sounds/hello8000.wav new file mode 100644 index 000000000..b5629df7a Binary files /dev/null and b/tester/sounds/hello8000.wav differ diff --git a/tester/sounds/hello8000_mkv_ref.wav b/tester/sounds/hello8000_mkv_ref.wav new file mode 100644 index 000000000..f91203cd8 Binary files /dev/null and b/tester/sounds/hello8000_mkv_ref.wav differ diff --git a/tester/sounds/hello_opus_h264.mkv b/tester/sounds/hello_opus_h264.mkv new file mode 100644 index 000000000..4aa5d338b Binary files /dev/null and b/tester/sounds/hello_opus_h264.mkv 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/sounds/vrroom.wav b/tester/sounds/vrroom.wav new file mode 100644 index 000000000..673a3addc Binary files /dev/null and b/tester/sounds/vrroom.wav differ diff --git a/tester/stun_tester.c b/tester/stun_tester.c new file mode 100644 index 000000000..89762cab3 --- /dev/null +++ b/tester/stun_tester.c @@ -0,0 +1,119 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2014 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 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 "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "mediastreamer2/stun.h" +#include "ortp/port.h" + + +static const char* stun_address = "stun.linphone.org"; + + +static int test_stun_encode( char*buffer, size_t len, bool_t expect_fail ) +{ + StunAtrString username; + StunAtrString password; + StunMessage req; + memset(&req, 0, sizeof(StunMessage)); + memset(&username,0,sizeof(username)); + memset(&password,0,sizeof(password)); + stunBuildReqSimple( &req, &username, TRUE , TRUE , 11); + len = stunEncodeMessage( &req, buffer, len, &password); + if (len<=0){ + if( expect_fail ) + ms_message("Fail to encode stun message (EXPECTED).\n"); + else + ms_error("Fail to encode stun message.\n"); + return -1; + } + return len; +} + + +static void linphone_stun_test_encode() +{ + char smallBuff[12]; + size_t smallLen = 12; + char bigBuff[STUN_MAX_MESSAGE_SIZE]; + size_t bigLen = STUN_MAX_MESSAGE_SIZE; + + size_t len = test_stun_encode(smallBuff, smallLen, TRUE); + BC_ASSERT(len == -1); + + len = test_stun_encode(bigBuff, bigLen, TRUE); + BC_ASSERT(len > 0); + ms_message("STUN message encoded in %i bytes", (int)len); +} + + +static void linphone_stun_test_grab_ip() +{ + LinphoneCoreManager* lc_stun = linphone_core_manager_new2( "stun_rc", FALSE); + LinphoneCall dummy_call; + int ping_time; + int tmp=0; + + memset(&dummy_call, 0, sizeof(LinphoneCall)); + dummy_call.media_ports[0].rtp_port = 7078; + dummy_call.media_ports[1].rtp_port = 9078; + + linphone_core_set_stun_server(lc_stun->lc, stun_address); + BC_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc)); + + wait_for(lc_stun->lc,lc_stun->lc,&tmp,1); + + ping_time = linphone_core_run_stun_tests(lc_stun->lc, &dummy_call); + BC_ASSERT(ping_time != -1); + + ms_message("Round trip to STUN: %d ms", ping_time); + + BC_ASSERT( dummy_call.ac.addr[0] != '\0'); + BC_ASSERT( dummy_call.ac.port != 0); +#ifdef VIDEO_ENABLED + BC_ASSERT( dummy_call.vc.addr[0] != '\0'); + BC_ASSERT( dummy_call.vc.port != 0); +#endif + + ms_message("STUN test result: local audio port maps to %s:%i", + dummy_call.ac.addr, + dummy_call.ac.port); +#ifdef VIDEO_ENABLED + ms_message("STUN test result: local video port maps to %s:%i", + dummy_call.vc.addr, + dummy_call.vc.port); +#endif + + linphone_core_manager_destroy(lc_stun); +} + + +test_t stun_tests[] = { + { "Basic Stun test (Ping/public IP)", linphone_stun_test_grab_ip }, + { "STUN encode buffer protection", linphone_stun_test_encode }, +}; + +test_suite_t stun_test_suite = { + "Stun", + liblinphone_tester_setup, + NULL, + sizeof(stun_tests) / sizeof(stun_tests[0]), + stun_tests +}; diff --git a/tester/tester.c b/tester/tester.c new file mode 100644 index 000000000..eded255ed --- /dev/null +++ b/tester/tester.c @@ -0,0 +1,483 @@ + /* + tester - liblinphone test suite + 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, see . + */ + +#include +#include "CUnit/TestRun.h" +#include "CUnit/Automated.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#if HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +#endif +#ifdef HAVE_GTK +#include +#endif +#if _WIN32 +#define unlink _unlink +#endif + +static bool_t liblinphone_tester_ipv6_enabled=FALSE; +static int liblinphone_tester_keep_accounts_flag = 0; +static int liblinphone_tester_keep_record_files = FALSE; +int manager_count = 0; + +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"; +const char *userhostsfile = "tester_hosts"; + +const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)"; + +static void network_reachable(LinphoneCore *lc, bool_t reachable) { + stats* counters; + ms_message("Network reachable [%s]",reachable?"TRUE":"FALSE"); + counters = get_stats(lc); + if (reachable) + counters->number_of_NetworkReachableTrue++; + else + counters->number_of_NetworkReachableFalse++; +} +void liblinphone_tester_clock_start(MSTimeSpec *start){ + ms_get_cur_time(start); +} + +bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){ + MSTimeSpec current; + ms_get_cur_time(¤t); + if ((((current.tv_sec-start->tv_sec)*1000LL) + ((current.tv_nsec-start->tv_nsec)/1000000LL))>=value_ms) + return TRUE; + return FALSE; +} + +void liblinphone_tester_enable_ipv6(bool_t enabled){ + liblinphone_tester_ipv6_enabled=enabled; +} + +LinphoneAddress * create_linphone_address(const char * domain) { + LinphoneAddress *addr = linphone_address_new(NULL); + BC_ASSERT_PTR_NOT_NULL_FATAL(addr); + linphone_address_set_username(addr,test_username); + BC_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); + if (!domain) domain= test_route; + linphone_address_set_domain(addr,domain); + BC_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); + linphone_address_set_display_name(addr, NULL); + linphone_address_set_display_name(addr, "Mr Tester"); + BC_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); + return addr; +} + +static void auth_info_requested(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++; +} + +void reset_counters( stats* counters) { + if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message); + memset(counters,0,sizeof(stats)); +} + +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { + LinphoneCore* lc; + LpConfig* config = NULL; + char *filepath = NULL; + char *ringpath = NULL; + char *ringbackpath = NULL; + char *rootcapath = NULL; + char *dnsuserhostspath = NULL; + char *nowebcampath = NULL; + + if (path==NULL) path="."; + + if (file){ + filepath = ms_strdup_printf("%s/%s", path, file); + BC_ASSERT_EQUAL_FATAL(ortp_file_exist(filepath),0,int, "%d"); + config = lp_config_new_with_factory(NULL,filepath); + } + + + // setup dynamic-path assets + ringpath = ms_strdup_printf("%s/sounds/oldphone.wav",path); + ringbackpath = ms_strdup_printf("%s/sounds/ringback.wav", path); + nowebcampath = ms_strdup_printf("%s/images/nowebcamCIF.jpg", path); + rootcapath = ms_strdup_printf("%s/certificates/cn/cafile.pem", path); + dnsuserhostspath = ms_strdup_printf( "%s/%s", path, userhostsfile); + + + if( config != NULL ) { + lp_config_set_string(config, "sound", "remote_ring", ringbackpath); + lp_config_set_string(config, "sound", "local_ring" , ringpath); + lp_config_set_string(config, "sip", "root_ca" , rootcapath); + lc = linphone_core_new_with_config(v_table, config, user_data); + } else { + lc = linphone_core_new(v_table,NULL,(filepath!=NULL&&filepath[0]!='\0') ? filepath : NULL, user_data); + + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); + linphone_core_set_root_ca(lc,rootcapath); + } + + sal_enable_test_features(lc->sal,TRUE); + sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + linphone_core_set_static_picture(lc,nowebcampath); + + linphone_core_enable_ipv6(lc, liblinphone_tester_ipv6_enabled); + + ms_free(ringpath); + ms_free(ringbackpath); + ms_free(nowebcampath); + ms_free(rootcapath); + ms_free(dnsuserhostspath); + + if( filepath ) ms_free(filepath); + + if( config ) lp_config_unref(config); + + 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,10000); +} + +bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { + MSList* iterator; + MSTimeSpec start; + + liblinphone_tester_clock_start(&start); + while ((counter==NULL || *counternext) { +#ifdef HAVE_GTK + gdk_threads_enter(); + gtk_main_iteration_do(FALSE); + gdk_threads_leave(); +#endif + linphone_core_iterate((LinphoneCore*)(iterator->data)); + } +#ifdef LINPHONE_WINDOWS_DESKTOP + { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0,1)){ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +#endif + ms_usleep(20000); + } + 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; +} + +bool_t transport_supported(LinphoneTransportType transport) { + Sal *sal = sal_init(); + bool_t supported = sal_transport_available(sal,(SalTransport)transport); + if (!supported) ms_message("TLS transport not supported, falling back to TCP if possible otherwise skipping test."); + sal_uninit(sal); + return supported; +} + + +static void display_status(LinphoneCore *lc, const char *status){ + ms_message("display_status(): %s",status); +} + +LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) { + LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); + char *rc_path = NULL; + char *hellopath = bc_tester_res("sounds/hello8000.wav"); + mgr->number_of_cunit_error_at_creation = CU_get_number_of_failures(); + 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.is_composing_received=is_composing_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->v_table.configuring_status=linphone_configuration_status; + mgr->v_table.call_encryption_changed=linphone_call_encryption_changed; + mgr->v_table.network_reachable=network_reachable; + mgr->v_table.dtmf_received=dtmf_received; + mgr->v_table.call_stats_updated=call_stats_updated; + mgr->v_table.display_status=display_status; + + reset_counters(&mgr->stat); + if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); + mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), rc_path, mgr); + linphone_core_manager_check_accounts(mgr); + + manager_count++; + +#if TARGET_OS_IPHONE + linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device"); + linphone_core_set_ringback(mgr->lc, NULL); +#endif + +#ifdef VIDEO_ENABLED + { + MSWebCam *cam; + + cam = ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), "Mire: Mire (synthetic moving picture)"); + + if (cam == NULL) { + MSWebCamDesc *desc = ms_mire_webcam_desc_get(); + if (desc){ + cam=ms_web_cam_new(desc); + ms_web_cam_manager_add_cam(ms_web_cam_manager_get(), cam); + } + } + } +#endif + + + linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/ + ms_free(hellopath); + + if( manager_count >= 2){ + char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc); + ms_message("Manager for '%s' using files", rc_file ? rc_file : "--"); + linphone_core_set_use_files(mgr->lc, TRUE); + linphone_core_set_record_file(mgr->lc,recordpath); + ms_free(recordpath); + } + + linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix()); + + if (rc_path) ms_free(rc_path); + + return mgr; +} + +void linphone_core_manager_start(LinphoneCoreManager *mgr, const char* rc_file, int check_for_proxies) { + LinphoneProxyConfig* proxy; + int proxy_count; + + /*BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/ + if (check_for_proxies && rc_file) /**/ + proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); + else + proxy_count=0; + + if (proxy_count){ +#define REGISTER_TIMEOUT 20 /* seconds */ + int success = wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk, + proxy_count,(REGISTER_TIMEOUT * 1000 * proxy_count)); + if( !success ){ + ms_error("Did not register after %d seconds for %d proxies", REGISTER_TIMEOUT, proxy_count); + } + } + BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count, int, "%d"); + enable_codec(mgr->lc,"PCMU",8000); + + linphone_core_get_default_proxy(mgr->lc,&proxy); + if (proxy) { + mgr->identity = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy)); + linphone_address_clean(mgr->identity); + } +} + +LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { + LinphoneCoreManager *manager = linphone_core_manager_init(rc_file); + linphone_core_manager_start(manager, rc_file, TRUE); + return manager; +} + +LinphoneCoreManager* linphone_core_manager_new2( const char* rc_file, int check_for_proxies) { + LinphoneCoreManager *manager = linphone_core_manager_init(rc_file); + linphone_core_manager_start(manager, rc_file, check_for_proxies); + return manager; +} + +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){ + const char *record_file=linphone_core_get_record_file(mgr->lc); + if (!liblinphone_tester_keep_record_files && record_file){ + if ((CU_get_number_of_failures()-mgr->number_of_cunit_error_at_creation)>0) { + ms_message ("Test has failed, keeping recorded file [%s]",record_file); + } else { + unlink(record_file); + } + } + linphone_core_destroy(mgr->lc); + } + if (mgr->identity) linphone_address_destroy(mgr->identity); + if (mgr->stat.last_received_chat_message) linphone_chat_message_unref(mgr->stat.last_received_chat_message); + manager_count--; + + ms_free(mgr); +} + +int liblinphone_tester_ipv6_available(void){ + struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53); + if (ai){ + struct sockaddr_storage ss; + struct addrinfo src; + socklen_t slen=sizeof(ss); + char localip[128]; + int port=0; + belle_sip_get_src_addr_for(ai->ai_addr,ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444); + src.ai_addr=(struct sockaddr*) &ss; + src.ai_addrlen=slen; + belle_sip_addrinfo_to_ip(&src,localip, sizeof(localip),&port); + freeaddrinfo(ai); + return strcmp(localip,"::1")!=0; + } + return FALSE; +} + +void liblinphone_tester_keep_accounts( int keep ){ + liblinphone_tester_keep_accounts_flag = keep; +} + +void liblinphone_tester_keep_recorded_files(int keep){ + liblinphone_tester_keep_record_files = keep; +} + +void liblinphone_tester_clear_accounts(void){ + account_manager_destroy(); +} + +void liblinphone_tester_add_suites() { + bc_tester_add_suite(&setup_test_suite); + bc_tester_add_suite(®ister_test_suite); + bc_tester_add_suite(&offeranswer_test_suite); + bc_tester_add_suite(&call_test_suite); + bc_tester_add_suite(&multi_call_test_suite); + bc_tester_add_suite(&message_test_suite); + bc_tester_add_suite(&presence_test_suite); +#ifdef UPNP + bc_tester_add_suite(&upnp_test_suite); +#endif + bc_tester_add_suite(&stun_test_suite); + bc_tester_add_suite(&event_test_suite); + bc_tester_add_suite(&flexisip_test_suite); + bc_tester_add_suite(&remote_provisioning_test_suite); + bc_tester_add_suite(&quality_reporting_test_suite); + bc_tester_add_suite(&log_collection_test_suite); + bc_tester_add_suite(&tunnel_test_suite); + bc_tester_add_suite(&player_test_suite); + bc_tester_add_suite(&dtmf_test_suite); +#if defined(VIDEO_ENABLED) && defined(HAVE_GTK) + bc_tester_add_suite(&video_test_suite); +#endif + bc_tester_add_suite(&multicast_call_test_suite); + bc_tester_add_suite(&proxy_config_test_suite); +} + +static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) { + int i,result=0; + for (i=0; istat.audio_download_bandwidth + , sizeof(mgr->stat.audio_download_bandwidth)/sizeof(int)); +} +int linphone_core_manager_get_max_audio_up_bw(const LinphoneCoreManager *mgr) { + return linphone_core_manager_get_max_audio_bw_base(mgr->stat.audio_upload_bandwidth + , sizeof(mgr->stat.audio_upload_bandwidth)/sizeof(int)); +} + +int linphone_core_manager_get_mean_audio_down_bw(const LinphoneCoreManager *mgr) { + return linphone_core_manager_get_mean_audio_bw_base(mgr->stat.audio_download_bandwidth + , sizeof(mgr->stat.audio_download_bandwidth)/sizeof(int)); +} +int linphone_core_manager_get_mean_audio_up_bw(const LinphoneCoreManager *mgr) { + return linphone_core_manager_get_mean_audio_bw_base(mgr->stat.audio_upload_bandwidth + , sizeof(mgr->stat.audio_upload_bandwidth)/sizeof(int)); +} + +int liblinphone_tester_setup() { + if (manager_count != 0) { + // crash in some linphone core have not been destroyed because if we continue + // it will crash in CUnit AND we should NEVER keep a manager alive + ms_fatal("%d linphone core manager still alive!", manager_count); + return 1; + } + return 0; +} diff --git a/tester/tester_hosts b/tester/tester_hosts new file mode 100644 index 000000000..872dd4a63 --- /dev/null +++ b/tester/tester_hosts @@ -0,0 +1,2 @@ +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 +2001:41d0:2:14b0::1 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 \ No newline at end of file diff --git a/tester/tunnel_tester.c b/tester/tunnel_tester.c new file mode 100644 index 000000000..76ce2a826 --- /dev/null +++ b/tester/tunnel_tester.c @@ -0,0 +1,271 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + +#include +#include +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +/* Retrieve the public IP from a given hostname */ +static const char* get_ip_from_hostname(const char * tunnel_hostname){ + struct addrinfo hints; + struct addrinfo *res = NULL, *it = NULL; + struct sockaddr_in *add; + char * output = NULL; + int err; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((err = getaddrinfo(tunnel_hostname, NULL, &hints, &res))){ + ms_error("error while retrieving IP from %s: %s", tunnel_hostname, gai_strerror(err)); + return NULL; + } + + for (it=res; it!=NULL; it=it->ai_next){ + add = (struct sockaddr_in *) it->ai_addr; + output = inet_ntoa( add->sin_addr ); + } + freeaddrinfo(res); + return output; +} +static char* get_public_contact_ip(LinphoneCore* lc) { + const LinphoneAddress * contact = linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(lc)); + BC_ASSERT_PTR_NOT_NULL(contact); + return ms_strdup(linphone_address_get_domain(contact)); +} + + +static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption, bool_t with_video_and_ice) { + if (linphone_core_tunnel_available()){ + LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager *marie = linphone_core_manager_new( "marie_rc"); + LinphoneCall *pauline_call, *marie_call; + LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(pauline->lc); + LinphoneAddress *server_addr = linphone_address_new(linphone_proxy_config_get_server_addr(proxy)); + LinphoneAddress *route = linphone_address_new(linphone_proxy_config_get_route(proxy)); + const char * tunnel_ip = get_ip_from_hostname("tunnel.linphone.org"); + char *public_ip, *public_ip2=NULL; + + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1)); + public_ip = get_public_contact_ip(pauline->lc); + BC_ASSERT_STRING_NOT_EQUAL(public_ip, tunnel_ip); + + linphone_core_set_media_encryption(pauline->lc, encryption); + + if (with_video_and_ice){ + /*we want to test that tunnel is able to work with long SIP message, above mtu. + * Enable ICE and many codec to make the SIP message bigger*/ + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); + linphone_core_enable_payload_type(pauline->lc, + linphone_core_find_payload_type(pauline->lc, "speex", 32000, 1), TRUE); + linphone_core_enable_payload_type(pauline->lc, + linphone_core_find_payload_type(pauline->lc, "speex", 16000, 1), TRUE); + linphone_core_enable_payload_type(pauline->lc, + linphone_core_find_payload_type(pauline->lc, "G722", 8000, 1), TRUE); + linphone_core_enable_payload_type(marie->lc, + linphone_core_find_payload_type(marie->lc, "speex", 32000, 1), TRUE); + linphone_core_enable_payload_type(marie->lc, + linphone_core_find_payload_type(marie->lc, "speex", 16000, 1), TRUE); + linphone_core_enable_payload_type(marie->lc, + linphone_core_find_payload_type(marie->lc, "G722", 8000, 1), TRUE); + + } + + if (tunnel_mode != LinphoneTunnelModeDisable){ + LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc); + LinphoneTunnelConfig *config = linphone_tunnel_config_new(); + + linphone_tunnel_config_set_host(config, "tunnel.linphone.org"); + linphone_tunnel_config_set_port(config, 443); + linphone_tunnel_config_set_remote_udp_mirror_port(config, 12345); + linphone_tunnel_add_server(tunnel, config); + linphone_tunnel_set_mode(tunnel, tunnel_mode); + linphone_tunnel_enable_sip(tunnel, with_sip); + + /* + * Enabling the tunnel with sip cause another REGISTER to be made. + * In automatic mode, the udp test should conclude (assuming we have a normal network), that no + * tunnel is needed. Thus the number of registrations should stay to 1. + * The library is missing a notification of "tunnel connectivity test finished" to enable the + * full testing of the automatic mode. + */ + + if (tunnel_mode == LinphoneTunnelModeEnable && with_sip) { + BC_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,2)); + /* Ensure that we did use the tunnel. If so, we should see contact changed from: + Contact: ;.[...] + To: + Contact: ;[....] (91.121.209.194 must be tunnel.liphone.org) + */ + ms_free(public_ip); + public_ip = get_public_contact_ip(pauline->lc); + BC_ASSERT_STRING_EQUAL(public_ip, tunnel_ip); + } else { + public_ip2 = get_public_contact_ip(pauline->lc); + BC_ASSERT_STRING_EQUAL(public_ip, public_ip2); + } + } + + BC_ASSERT_TRUE(call(pauline,marie)); + pauline_call=linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call!=NULL){ + BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(pauline_call)), + encryption, int, "%d"); + } + if (tunnel_mode == LinphoneTunnelModeEnable && with_sip){ + /* make sure the call from pauline arrived from the tunnel by checking the contact address*/ + marie_call = linphone_core_get_current_call(marie->lc); + BC_ASSERT_PTR_NOT_NULL(marie_call); + if (marie_call){ + const char *remote_contact = linphone_call_get_remote_contact(marie_call); + BC_ASSERT_PTR_NOT_NULL(remote_contact); + if (remote_contact){ + LinphoneAddress *tmp = linphone_address_new(remote_contact); + BC_ASSERT_PTR_NOT_NULL(tmp); + if (tmp){ + BC_ASSERT_STRING_EQUAL(linphone_address_get_domain(tmp), tunnel_ip); + linphone_address_destroy(tmp); + } + } + } + } +#ifdef VIDEO_ENABLED + if (with_video_and_ice){ + BC_ASSERT_TRUE(add_video(pauline, marie, TRUE)); + } +#endif + end_call(pauline,marie); + + ms_free(public_ip); + if(public_ip2 != NULL) ms_free(public_ip2); + linphone_address_destroy(server_addr); + linphone_address_destroy(route); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + }else{ + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); + } +} + + +static void call_with_tunnel(void) { + call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, FALSE); +} + +static void call_with_tunnel_srtp(void) { + call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionSRTP, FALSE); +} + +static void call_with_tunnel_without_sip(void) { + call_with_tunnel_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone, FALSE); +} + +static void call_with_tunnel_auto(void) { + call_with_tunnel_base(LinphoneTunnelModeAuto, TRUE, LinphoneMediaEncryptionNone, FALSE); +} + +static void call_with_tunnel_auto_without_sip_with_srtp(void) { + call_with_tunnel_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP, FALSE); +} + +#ifdef VIDEO_ENABLED + +static void full_tunnel_video_ice_call(void){ + if (linphone_core_tunnel_available()){ + call_with_tunnel_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone, TRUE); + }else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_srtp_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} +static void tunnel_zrtp_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_dtls_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionDTLS,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_video_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} +#endif + +static void tunnel_srtp_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_zrtp_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} + +static void tunnel_ice_call(void) { + if (linphone_core_tunnel_available()) + call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE); + else + ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__); +} +test_t tunnel_tests[] = { + { "Simple", call_with_tunnel }, + { "With SRTP", call_with_tunnel_srtp }, + { "Without SIP", call_with_tunnel_without_sip }, + { "In automatic mode", call_with_tunnel_auto }, + { "In automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp }, + { "Ice call", tunnel_ice_call }, + { "SRTP ice call", tunnel_srtp_ice_call }, + { "ZRTP ice call", tunnel_zrtp_ice_call }, +#ifdef VIDEO_ENABLED + { "Ice video call", tunnel_video_ice_call }, + { "With SIP - ice video call", full_tunnel_video_ice_call }, + { "SRTP ice video call", tunnel_srtp_video_ice_call }, + { "DTLS ice video call", tunnel_dtls_video_ice_call }, + { "ZRTP ice video call", tunnel_zrtp_video_ice_call }, +#endif +}; + +test_suite_t tunnel_test_suite = { + "Tunnel", + liblinphone_tester_setup, + NULL, + sizeof(tunnel_tests) / sizeof(tunnel_tests[0]), + tunnel_tests +}; diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c new file mode 100644 index 000000000..fc487b75e --- /dev/null +++ b/tester/upnp_tester.c @@ -0,0 +1,68 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ + + +#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 + BC_ASSERT_PTR_NOT_NULL(lc_upnp->lc->upnp); +#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); + BC_ASSERT_EQUAL(linphone_core_get_upnp_state(lc_upnp->lc), LinphoneUpnpStateOk, int, "%d"); + linphone_core_manager_destroy(lc_upnp); +} + +static void upnp_check_ipaddress(void) { + int tmp = 0; + const char *addr; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + addr = linphone_core_get_upnp_external_ipaddress(lc_upnp->lc); + BC_ASSERT_PTR_NOT_NULL(addr); + if (addr!=NULL) { + BC_ASSERT_GREATER(strlen(addr),7,int,"%d"); + } + 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", + liblinphone_tester_setup, + NULL, + sizeof(upnp_tests) / sizeof(upnp_tests[0]), + upnp_tests +}; diff --git a/tester/video_tester.c b/tester/video_tester.c new file mode 100644 index 000000000..abffb59ab --- /dev/null +++ b/tester/video_tester.c @@ -0,0 +1,564 @@ +/* + liblinphone_tester - liblinphone test suite + 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, see . +*/ +#include "private.h" + +#if defined(VIDEO_ENABLED) + + +#include "linphonecore.h" +#include "liblinphone_tester.h" +#include "lpconfig.h" + +#if HAVE_GTK +#include +#ifdef GDK_WINDOWING_X11 +#include +#elif defined(_WIN32) +#include +#elif defined(__APPLE__) +extern void *gdk_quartz_window_get_nswindow(GdkWindow *window); +extern void *gdk_quartz_window_get_nsview(GdkWindow *window); +#endif + +#include + + +static void *get_native_handle(GdkWindow *gdkw) { +#ifdef GDK_WINDOWING_X11 + return (void *)GDK_WINDOW_XID(gdkw); +#elif defined(_WIN32) + return (void *)GDK_WINDOW_HWND(gdkw); +#elif defined(__APPLE__) + return (void *)gdk_quartz_window_get_nsview(gdkw); +#endif + g_warning("No way to get the native handle from gdk window"); + return 0; +} + +static GtkWidget *create_video_window(LinphoneCall *call, LinphoneCallState cstate) { + GtkWidget *video_window; + GdkDisplay *display; + GdkColor color; + MSVideoSize vsize = { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H }; + const char *cstate_str; + char *title; + stats* counters = get_stats(call->core); + + cstate_str = linphone_call_state_to_string(cstate); + title = g_strdup_printf("%s", cstate_str); + video_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(video_window), title); + g_free(title); + gtk_window_resize(GTK_WINDOW(video_window), vsize.width, vsize.height); + gdk_color_parse("black", &color); + gtk_widget_modify_bg(video_window, GTK_STATE_NORMAL, &color); + gtk_widget_show(video_window); + g_object_set_data(G_OBJECT(video_window), "call", call); +#if GTK_CHECK_VERSION(2,24,0) + display = gdk_window_get_display(gtk_widget_get_window(video_window)); +#else // backward compatibility with Debian 6 and Centos 6 + display = gdk_drawable_get_display(gtk_widget_get_window(video_window)); +#endif + gdk_display_flush(display); + counters->number_of_video_windows_created++; + return video_window; +} + +static void show_video_window(LinphoneCall *call, LinphoneCallState cstate) { + GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call); + if (video_window == NULL) { + video_window = create_video_window(call, cstate); + linphone_call_set_user_data(call, video_window); + linphone_call_set_native_video_window_id(call, get_native_handle(gtk_widget_get_window(video_window))); + } +} + +static void hide_video_video(LinphoneCall *call) { + GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call); + if (video_window != NULL) { + gtk_widget_destroy(video_window); + linphone_call_set_user_data(call, NULL); + linphone_call_set_native_video_window_id(call, 0); + } +} + +static void video_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + switch (cstate) { + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallConnected: + show_video_window(call, cstate); + break; + case LinphoneCallEnd: + hide_video_video(call); + break; + default: + break; + } +} + +static void early_media_video_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + LinphoneCallParams *params; + + video_call_state_changed(lc, call, cstate, msg); + switch (cstate) { + case LinphoneCallIncomingReceived: + params = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_video(params, TRUE); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendOnly); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionRecvOnly); + linphone_core_accept_early_media_with_params(lc, call, params); + linphone_call_params_unref(params); + break; + default: + break; + } +} + +static void early_media_video_call_state_changed_with_inactive_audio(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) { + LinphoneCallParams *params; + + video_call_state_changed(lc, call, cstate, msg); + switch (cstate) { + case LinphoneCallIncomingReceived: + params = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_video(params, TRUE); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionInactive); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionRecvOnly); + linphone_core_accept_early_media_with_params(lc, call, params); + linphone_call_params_unref(params); + break; + default: + break; + } +} + +bool_t wait_for_three_cores(LinphoneCore *lc1, LinphoneCore *lc2, LinphoneCore *lc3, int timeout) { + MSList *lcs = NULL; + bool_t result; + int dummy = 0; + if (lc1) lcs = ms_list_append(lcs, lc1); + if (lc2) lcs = ms_list_append(lcs, lc2); + if (lc3) lcs = ms_list_append(lcs, lc3); + result = wait_for_list(lcs, &dummy, 1, timeout); + ms_list_free(lcs); + return result; +} + +static bool_t video_call_with_params(LinphoneCoreManager* caller_mgr, LinphoneCoreManager* callee_mgr, const LinphoneCallParams *caller_params, const LinphoneCallParams *callee_params, bool_t automatically_accept) { + int retry = 0; + stats initial_caller = caller_mgr->stat; + stats initial_callee = callee_mgr->stat; + bool_t result = TRUE; + bool_t did_received_call; + + BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc, callee_mgr->identity, caller_params)); + did_received_call = wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallIncomingReceived, initial_callee.number_of_LinphoneCallIncomingReceived + 1); + if (!did_received_call) return 0; + + BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress, initial_caller.number_of_LinphoneCallOutgoingProgress + 1, int, "%d"); + + 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++ < 200) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(10000); + } + + BC_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)); + + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) { + return 0; + } + + if (automatically_accept == TRUE) { + linphone_core_accept_call_with_params(callee_mgr->lc, linphone_core_get_current_call(callee_mgr->lc), callee_params); + + BC_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1)); + BC_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1)); + 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); + } + return result; +} + +static LinphoneCallParams * _configure_for_video(LinphoneCoreManager *manager, LinphoneCoreCallStateChangedCb cb) { + LinphoneCallParams *params; + LinphoneCoreVTable *vtable = linphone_core_v_table_new(); + vtable->call_state_changed = cb; + linphone_core_add_listener(manager->lc, vtable); + linphone_core_set_video_device(manager->lc, "StaticImage: Static picture"); + linphone_core_enable_video_capture(manager->lc, TRUE); + linphone_core_enable_video_display(manager->lc, TRUE); + params = linphone_core_create_default_call_parameters(manager->lc); + linphone_call_params_enable_video(params, TRUE); + if (linphone_core_find_payload_type(manager->lc,"VP8", 90000, -1)!=NULL){ + disable_all_video_codecs_except_one(manager->lc, "VP8"); + }else{ + ms_warning("VP8 codec not available, will use MP4V-ES instead"); + disable_all_video_codecs_except_one(manager->lc, "MP4V-ES"); + } + return params; +} + +static LinphoneCallParams * configure_for_video(LinphoneCoreManager *manager) { + return _configure_for_video(manager, video_call_state_changed); +} + +static LinphoneCallParams * configure_for_early_media_video_sending(LinphoneCoreManager *manager) { + LinphoneCallParams *params = _configure_for_video(manager, video_call_state_changed); + linphone_call_params_enable_early_media_sending(params, TRUE); + return params; +} + +static LinphoneCallParams * configure_for_early_media_video_receiving(LinphoneCoreManager *manager) { + return _configure_for_video(manager, early_media_video_call_state_changed); +} + +static LinphoneCallParams * configure_for_early_media_video_receiving_with_inactive_audio(LinphoneCoreManager *manager) { + return _configure_for_video(manager, early_media_video_call_state_changed_with_inactive_audio); +} + + +static void early_media_video_during_video_call_test(void) { + LinphoneCoreManager *marie; + LinphoneCoreManager *pauline; + LinphoneCoreManager *laure; + LinphoneCallParams *marie_params; + LinphoneCallParams *pauline_params; + LinphoneCallParams *laure_params; + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_tcp_rc"); + laure = linphone_core_manager_new("laure_rc"); + marie_params = configure_for_early_media_video_receiving(marie); + pauline_params = configure_for_video(pauline); + laure_params = configure_for_early_media_video_sending(laure); + + /* Normal automatically accepted video call from marie to pauline. */ + BC_ASSERT_TRUE(video_call_with_params(marie, pauline, marie_params, pauline_params, TRUE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, NULL, 2000); + + /* Early media video call from laure to marie. */ + BC_ASSERT_TRUE(video_call_with_params(laure, marie, laure_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 2000); + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &laure->stat.number_of_LinphoneCallEnd, 1)); + + BC_ASSERT_EQUAL(marie->stat.number_of_video_windows_created, 2, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_video_windows_created, 1, int, "%d"); + BC_ASSERT_EQUAL(laure->stat.number_of_video_windows_created, 1, int, "%d"); + + linphone_call_params_unref(marie_params); + linphone_call_params_unref(pauline_params); + linphone_call_params_unref(laure_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +static void two_incoming_early_media_video_calls_test(void) { + char *ringback_path; + LinphoneCoreManager *marie; + LinphoneCoreManager *pauline; + LinphoneCoreManager *laure; + LinphoneCallParams *marie_params; + LinphoneCallParams *pauline_params; + LinphoneCallParams *laure_params; + LinphoneCall *call; + const MSList *calls_list; + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_tcp_rc"); + laure = linphone_core_manager_new("laure_rc"); + marie_params = configure_for_early_media_video_receiving(marie); + pauline_params = configure_for_early_media_video_sending(pauline); + laure_params = configure_for_early_media_video_sending(laure); + + /* Configure early media audio to play ring during early-media and send remote ring back tone. */ + linphone_core_set_ring_during_incoming_early_media(marie->lc, TRUE); + ringback_path = bc_tester_res("sounds/ringback.wav"); + linphone_core_set_remote_ringback_tone(marie->lc, ringback_path); + ms_free(ringback_path); + + /* Early media video call from pauline to marie. */ + BC_ASSERT_TRUE(video_call_with_params(pauline, marie, pauline_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, NULL, 2000); + + /* Early media video call from laure to marie. */ + BC_ASSERT_TRUE(video_call_with_params(laure, marie, laure_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 2000); + + BC_ASSERT_EQUAL(linphone_core_get_calls_nb(marie->lc), 2, int, "%d"); + if (linphone_core_get_calls_nb(marie->lc) == 2) { + calls_list = linphone_core_get_calls(marie->lc); + call = (LinphoneCall *)ms_list_nth_data(calls_list, 0); + BC_ASSERT_PTR_NOT_NULL(call); + if (call != NULL) { + LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_current_params(call)); + linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendRecv); + linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendRecv); + linphone_core_accept_call_with_params(marie->lc, call, params); + + /* Wait for 5s. */ + wait_for_three_cores(marie->lc, pauline->lc, laure->lc, 5000); + } + } + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, laure->lc, &laure->stat.number_of_LinphoneCallEnd, 1)); + + BC_ASSERT_EQUAL(marie->stat.number_of_video_windows_created, 2, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_video_windows_created, 1, int, "%d"); + BC_ASSERT_EQUAL(laure->stat.number_of_video_windows_created, 1, int, "%d"); + + linphone_call_params_unref(marie_params); + linphone_call_params_unref(pauline_params); + linphone_call_params_unref(laure_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +static void early_media_video_with_inactive_audio(void) { + LinphoneCoreManager *marie; + LinphoneCoreManager *pauline; + LinphoneCallParams *marie_params; + LinphoneCallParams *pauline_params; + + marie = linphone_core_manager_new("marie_rc"); + pauline = linphone_core_manager_new("pauline_tcp_rc"); + marie_params = configure_for_early_media_video_receiving_with_inactive_audio(marie); + pauline_params = configure_for_early_media_video_sending(pauline); + + /* Early media video call from pauline to marie. */ + BC_ASSERT_TRUE(video_call_with_params(pauline, marie, pauline_params, NULL, FALSE)); + + /* Wait for 2s. */ + wait_for_three_cores(marie->lc, pauline->lc, NULL, 2000); + + /* Check that we are in LinphoneCallOutgoingEarlyMedia state and that the ringstream is present meaning we are playing the ringback tone. */ + BC_ASSERT_EQUAL(linphone_call_get_state(linphone_core_get_current_call(pauline->lc)), LinphoneCallOutgoingEarlyMedia, int, "%d"); + BC_ASSERT_PTR_NOT_NULL(pauline->lc->ringstream); + + linphone_core_terminate_all_calls(marie->lc); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1)); + + BC_ASSERT_EQUAL(marie->stat.number_of_video_windows_created, 1, int, "%d"); + BC_ASSERT_EQUAL(pauline->stat.number_of_video_windows_created, 1, int, "%d"); + + linphone_call_params_unref(marie_params); + linphone_call_params_unref(pauline_params); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void forked_outgoing_early_media_video_call_with_inactive_audio_test(void) { + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); + LinphoneCoreManager *marie1 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager *marie2 = linphone_core_manager_new("marie_early_rc"); + MSList *lcs = NULL; + LinphoneCallParams *pauline_params; + LinphoneCallParams *marie1_params; + LinphoneCallParams *marie2_params; + LinphoneVideoPolicy pol; + LinphoneCall *marie1_call; + LinphoneCall *marie2_call; + LinphoneCall *pauline_call; + LinphoneInfoMessage *info; + int dummy = 0; + pol.automatically_accept = 1; + pol.automatically_initiate = 1; + + linphone_core_enable_video(pauline->lc, TRUE, TRUE); + linphone_core_enable_video(marie1->lc, TRUE, TRUE); + linphone_core_set_video_policy(marie1->lc, &pol); + 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); + + lcs = ms_list_append(lcs,marie1->lc); + lcs = ms_list_append(lcs,marie2->lc); + lcs = ms_list_append(lcs,pauline->lc); + + pauline_params = linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_early_media_sending(pauline_params, TRUE); + linphone_call_params_enable_video(pauline_params, TRUE); + marie1_params = configure_for_early_media_video_receiving_with_inactive_audio(marie1); + marie2_params = configure_for_early_media_video_receiving_with_inactive_audio(marie2); + + linphone_core_invite_address_with_params(pauline->lc, marie1->identity, pauline_params); + linphone_call_params_destroy(pauline_params); + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 3000)); + + marie1_call = linphone_core_get_current_call(marie1->lc); + marie2_call = linphone_core_get_current_call(marie2->lc); + + if (marie1_call){ + linphone_call_set_next_video_frame_decoded_callback(marie1_call, linphone_call_iframe_decoded_cb, marie1->lc); + } + if (marie2_call){ + linphone_call_set_next_video_frame_decoded_callback(marie2_call, linphone_call_iframe_decoded_cb, marie2->lc); + } + + BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1, 3000)); + + pauline_call = linphone_core_get_current_call(pauline->lc); + + + BC_ASSERT_PTR_NOT_NULL(pauline_call); + BC_ASSERT_PTR_NOT_NULL(marie1_call); + BC_ASSERT_PTR_NOT_NULL(marie2_call); + + if (pauline_call && marie1_call && marie2_call) { + linphone_call_set_next_video_frame_decoded_callback(pauline_call, linphone_call_iframe_decoded_cb, pauline->lc); + + /* wait a bit that streams are established */ + wait_for_list(lcs, &dummy, 1, 3000); + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(marie2_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_LOWER(linphone_call_get_video_stats(pauline_call)->download_bandwidth, 11, float, "%f"); /* because of stun packets*/ + BC_ASSERT_GREATER(linphone_call_get_video_stats(marie1_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_GREATER(linphone_call_get_video_stats(marie2_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_GREATER(marie1->stat.number_of_IframeDecoded, 1, int, "%i"); + BC_ASSERT_GREATER(marie2->stat.number_of_IframeDecoded, 1, int, "%i"); + + linphone_call_params_set_audio_direction(marie1_params, LinphoneMediaDirectionSendRecv); + linphone_core_accept_call_with_params(marie1->lc, linphone_core_get_current_call(marie1->lc), marie1_params); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 3000)); + + /* marie2 should get her call terminated */ + BC_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, 3000); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 71, float, "%f"); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 71, float, "%f"); + BC_ASSERT_GREATER(linphone_call_get_video_stats(pauline_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_GREATER(linphone_call_get_video_stats(marie1_call)->download_bandwidth, 0, float, "%f"); + BC_ASSERT_GREATER(pauline->stat.number_of_IframeDecoded, 1, int, "%i"); + + /* send an INFO in reverse side to check that dialogs are properly established */ + info = linphone_core_create_info_message(marie1->lc); + linphone_call_send_info_message(marie1_call, info); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_inforeceived, 1, 3000)); + } + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallEnd, 1, 3000)); + + linphone_call_params_destroy(marie1_params); + linphone_call_params_destroy(marie2_params); + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} +#endif /*HAVE_GTK*/ + +static void enable_disable_camera_after_camera_switches() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + const char *currentCamId = (char*)linphone_core_get_video_device(marie->lc); + const char **cameras=linphone_core_get_video_devices(marie->lc); + const char *newCamId=NULL; + int i; + + + video_call_base_2(marie,pauline,FALSE,LinphoneMediaEncryptionNone,TRUE,TRUE); + + for (i=0;cameras[i]!=NULL;++i){ + if (strcmp(cameras[i],currentCamId)!=0){ + newCamId=cameras[i]; + break; + } + } + if (newCamId){ + LinphoneCall *call = linphone_core_get_current_call(marie->lc); + ms_message("Switching from [%s] to [%s]", currentCamId, newCamId); + linphone_core_set_video_device(marie->lc, newCamId); + if(call != NULL) { + linphone_core_update_call(marie->lc, call, NULL); + } + BC_ASSERT_STRING_EQUAL(newCamId,ms_web_cam_get_string_id(linphone_call_get_video_device(call))); + linphone_call_enable_camera(call,FALSE); + linphone_core_iterate(marie->lc); + linphone_call_enable_camera(call,TRUE); + BC_ASSERT_STRING_EQUAL(newCamId,ms_web_cam_get_string_id(linphone_call_get_video_device(call))); + } + + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +test_t video_tests[] = { +#if HAVE_GTK + { "Early-media video during video call", early_media_video_during_video_call_test }, + { "Two incoming early-media video calls", two_incoming_early_media_video_calls_test }, + { "Early-media video with inactive audio", early_media_video_with_inactive_audio }, + { "Forked outgoing early-media video call with inactive audio", forked_outgoing_early_media_video_call_with_inactive_audio_test }, +#endif /*HAVE_GTK*/ + { "Enable/disable camera after camera switches", enable_disable_camera_after_camera_switches} + +}; + +test_suite_t video_test_suite = { + "Video", + liblinphone_tester_setup, + NULL, + sizeof(video_tests) / sizeof(video_tests[0]), + video_tests +}; + +#endif /* VIDEO_ENABLED */ diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 000000000..6d383a4a7 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,55 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 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. +# +############################################################################ + +if(MSVC) + find_library(LIBGCC NAMES gcc) + find_library(LIBMINGWEX NAMES mingwex) +endif() + +set(LP_GEN_WRAPPERS_SOURCE_FILES + generator.cc + generator.hh + genwrappers.cc + software-desc.cc + software-desc.hh +) + +add_definitions( + -DIN_LINPHONE +) + +set(LP_GEN_WRAPPERS_LIBS + ${LIBGCC} + ${LIBMINGWEX} + ${XML2_LIBRARIES} +) + +add_executable(lp-gen-wrappers ${LP_GEN_WRAPPERS_SOURCE_FILES}) +target_link_libraries(lp-gen-wrappers ${LP_GEN_WRAPPERS_LIBS}) + + +install(TARGETS lp-gen-wrappers + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) diff --git a/tools/Makefile.am b/tools/Makefile.am index a93d809f1..ecd6cab5a 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,43 +2,24 @@ 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) + $(STRICT_OPTIONS_CC) \ + $(LIBXML2_CFLAGS) + +#-fpermissive to workaround a g++ bug on macos 32bit SDK. +AM_CXXFLAGS=$(LIBXML2_CFLAGS) -fpermissive $(STRICT_OPTIONS) $(STRICT_OPTIONS_CXX) EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc if BUILD_TOOLS -lib_LTLIBRARIES=libxml2lpc.la liblpc2xml.la - -libxml2lpc_la_SOURCES=\ - xml2lpc.c \ - xml2lpc.h - -liblpc2xml_la_SOURCES=\ - lpc2xml.c \ - lpc2xml.h - -libxml2lpc_la_CFLAGS=$(COMMON_CFLAGS) -libxml2lpc_la_LIBADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - $(LIBXML2_LIBS) - -liblpc2xml_la_CFLAGS=$(COMMON_CFLAGS) -liblpc2xml_la_LIBADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - $(LIBXML2_LIBS) - -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 lp-autoanswer xml2lpc_test_SOURCES=\ xml2lpc_test.c @@ -48,13 +29,25 @@ lpc2xml_test_SOURCES=\ xml2lpc_test_CFLAGS=$(COMMON_CFLAGS) xml2lpc_test_LDADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - libxml2lpc.la + $(top_builddir)/coreapi/liblinphone.la lpc2xml_test_CFLAGS=$(COMMON_CFLAGS) lpc2xml_test_LDADD=\ + $(top_builddir)/coreapi/liblinphone.la + +lp_gen_wrappers_SOURCES=genwrappers.cc \ + software-desc.cc software-desc.hh \ + generator.cc generator.hh + +lp_gen_wrappers_LDADD= \ + $(LIBXML2_LIBS) + +lp_autoanswer_SOURCES=auto_answer.c +lp_autoanswer_CFLAGS=$(COMMON_CFLAGS) +lp_autoanswer_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ - liblpc2xml.la + $(MEDIASTREAMER_LIBS) + endif diff --git a/tools/auto_answer.c b/tools/auto_answer.c new file mode 100644 index 000000000..b76968ec4 --- /dev/null +++ b/tools/auto_answer.c @@ -0,0 +1,207 @@ +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (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. +*/ + + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +static bool_t running=TRUE; +static bool_t print_stats=FALSE; +static bool_t dump_stats=FALSE; + +static void stop(int signum){ + running=FALSE; +} +#ifndef WIN32 +static void stats(int signum){ + print_stats=TRUE; +} +static void dump_call_logs(int signum){ + dump_stats=TRUE; +} + +#endif +#ifndef PACKAGE_DATA_DIR + #define PACKAGE_DATA_DIR '.' +#endif +/* + * Call state notification callback + */ +static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + LinphoneCallParams * call_params; + switch(cstate){ + case LinphoneCallIncomingReceived: + ms_message("Incoming call arrive !\n"); + /* accept the incoming call*/ + call_params = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_video(call_params,TRUE); + linphone_call_params_set_audio_direction(call_params,LinphoneMediaDirectionSendOnly); + linphone_call_params_set_video_direction(call_params,LinphoneMediaDirectionSendOnly); + linphone_core_accept_call_with_params(lc,call,call_params); + linphone_call_params_destroy(call_params); + + break; + default: + break; + } +} +extern MSWebCamDesc mire_desc; +static void helper() { + printf("auto_answer --help\n" + "\t\t\t--listening-uri uri to listen on, default [sip:localhost:5060]\n" + "\t\t\t--max-call-duration max duration of a call in seconds, default [3600]\n" + "\t\t\t--verbose\n"); + exit(0); +} + +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc; + LinphoneVideoPolicy policy; + int i; + LinphoneAddress *addr=NULL; + LCSipTransports tp; + char * tmp = NULL; + LpConfig * lp_config = lp_config_new(NULL); + int max_call_duration=3600; + + policy.automatically_accept=TRUE; + signal(SIGINT,stop); +#ifndef WIN32 + signal(SIGUSR1,stats); + signal(SIGUSR2,dump_call_logs); +#endif + for(i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--verbose") == 0) { + linphone_core_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + } else if (strcmp(argv[i], "--max-call-duration") == 0){ + max_call_duration = atoi(argv[++i]); + } else if (strcmp(argv[i], "--listening-uri") == 0){ + addr = linphone_address_new(argv[++i]); + if (!addr) { + printf("Error, bad sip uri"); + helper(); + } +/* switch(linphone_address_get_transport(addr)) { + case LinphoneTransportUdp: + case LinphoneTransportTcp: + break; + default: + ms_error("Error, bad sip uri [%s] transport, should be udp | tcp",argv[i]); + helper(); + break; + }*/ + } else { + helper(); + } + } + + if (!addr) { + addr = linphone_address_new("sip:bot@0.0.0.0:5060"); + } + + lp_config_set_string(lp_config,"sip","bind_address",linphone_address_get_domain(addr)); + lp_config_set_string(lp_config,"rtp","bind_address",linphone_address_get_domain(addr)); + lp_config_set_int(lp_config,"misc","history_max_size",100000); + + vtable.call_state_changed=call_state_changed; + + lc=linphone_core_new_with_config(&vtable,lp_config,NULL); + linphone_core_enable_video_capture(lc,TRUE); + linphone_core_enable_video_display(lc,FALSE); + linphone_core_set_video_policy(lc,&policy); + linphone_core_enable_keep_alive(lc,FALSE); + + + /*instead of using sound capture card, a file is played to the calling party*/ + linphone_core_set_play_file(lc,PACKAGE_DATA_DIR "/sounds/linphone/hello16000.wav"); + linphone_core_set_use_files(lc,TRUE); + + { + MSWebCamDesc *desc = ms_mire_webcam_desc_get(); + if (desc){ + ms_web_cam_manager_add_cam(ms_web_cam_manager_get(),ms_web_cam_new(desc)); + linphone_core_set_video_device(lc,"Mire: Mire (synthetic moving picture)"); + } + } + + + + memset(&tp,0,sizeof(LCSipTransports)); + + tp.udp_port = linphone_address_get_port(addr); + tp.tcp_port = linphone_address_get_port(addr); + + linphone_core_set_sip_transports(lc,&tp); + linphone_core_set_audio_port_range(lc,1024,65000); + linphone_core_set_preferred_framerate(lc,5); + linphone_core_set_primary_contact(lc,tmp=linphone_address_as_string(addr)); + ms_free(tmp); + + /* main loop for receiving notifications and doing background linphonecore work: */ + while(running){ + const MSList * iterator; + linphone_core_iterate(lc); + ms_usleep(50000); + if (print_stats) { + ms_message("*********************************"); + ms_message("*Current number of call [%10i] *",ms_list_size(linphone_core_get_calls(lc))); + ms_message("*Number of call until now [%10i] *",ms_list_size(linphone_core_get_call_logs(lc))); + ms_message("*********************************"); + print_stats=FALSE; + } + if (dump_stats) { + ms_message("*********************************"); + for (iterator=linphone_core_get_call_logs(lc);iterator!=NULL;iterator=iterator->next) { + LinphoneCallLog *call_log=(LinphoneCallLog *)iterator->data; + char * tmp_str = linphone_call_log_to_str(call_log); + ms_message("\n%s",tmp_str); + ms_free(tmp_str); + } + dump_stats=FALSE; + ms_message("*********************************"); + } + for (iterator=linphone_core_get_calls(lc);iterator!=NULL;iterator=iterator->next) { + LinphoneCall *call=(LinphoneCall *)iterator->data; + if (linphone_call_get_duration(call) > max_call_duration) { + ms_message("Terminating call [%p] after [%i] s",call,linphone_call_get_duration(call)); + linphone_core_terminate_call(lc,call); + break; + } + } + + } + + ms_message("Shutting down...\n"); + linphone_core_destroy(lc); + ms_message("Exited\n"); + return 0; +} + + + + diff --git a/tools/genapixml.py b/tools/genapixml.py new file mode 100755 index 000000000..656428b9e --- /dev/null +++ b/tools/genapixml.py @@ -0,0 +1,759 @@ +#!/usr/bin/python + +# Copyright (C) 2014 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import argparse +import os +import string +import sys +import xml.etree.ElementTree as ET +import xml.dom.minidom as minidom + + +class CObject: + def __init__(self, name): + self.name = name.strip() + self.briefDescription = '' + self.detailedDescription = None + self.deprecated = False + + +class CEnumValue(CObject): + pass + + +class CEnum(CObject): + def __init__(self, name): + CObject.__init__(self, name) + self.values = [] + self.associatedTypedef = None + + def addValue(self, value): + self.values.append(value) + + +class CStructMember(CObject): + def __init__(self, name, t): + CObject.__init__(self, name) + self.ctype = t.strip() + + +class CStruct(CObject): + def __init__(self, name): + CObject.__init__(self, name) + self.members = [] + self.associatedTypedef = None + + def addMember(self, member): + self.members.append(member) + + +class CTypedef(CObject): + def __init__(self, name, definition): + CObject.__init__(self, name) + self.definition = definition.strip() + + +class CArgument(CObject): + def __init__(self, t, name = '', enums = [], structs = []): + CObject.__init__(self, name) + self.description = None + self.containedType = None + keywords = [ 'const', 'struct', 'enum', 'signed', 'unsigned', 'short', 'long', '*' ] + fullySplittedType = [] + splittedType = t.strip().split(' ') + for s in splittedType: + if s.startswith('*'): + fullySplittedType.append('*') + if len(s) > 1: + fullySplittedType.append(s[1:]) + elif s.endswith('*'): + fullySplittedType.append(s[:-1]) + fullySplittedType.append('*') + else: + fullySplittedType.append(s) + isStruct = False + isEnum = False + self.ctype = 'int' # Default to int so that the result is correct eg. for 'unsigned short' + for s in fullySplittedType: + if not s in keywords: + self.ctype = s + if s == 'struct': + isStruct = True + if s == 'enum': + isEnum = True + if isStruct: + for st in structs: + if st.associatedTypedef is not None: + self.ctype = st.associatedTypedef.name + elif isEnum: + for e in enums: + if e.associatedTypedef is not None: + self.ctype = e.associatedTypedef.name + if self.ctype == 'int' and 'int' not in fullySplittedType: + if fullySplittedType[-1] == '*': + fullySplittedType.insert(-1, 'int') + else: + fullySplittedType.append('int') + self.completeType = ' '.join(fullySplittedType) + + def __str__(self): + return self.completeType + " " + self.name + + +class CArgumentsList: + def __init__(self): + self.arguments = [] + + def addArgument(self, arg): + self.arguments.append(arg) + + def __len__(self): + return len(self.arguments) + + def __getitem__(self, key): + return self.arguments[key] + + def __str__(self): + argstr = [] + for arg in self.arguments: + argstr.append(str(arg)) + return ', '.join(argstr) + + +class CFunction(CObject): + def __init__(self, name, returnarg, argslist): + CObject.__init__(self, name) + self.returnArgument = returnarg + self.arguments = argslist + self.location = None + + +class CEvent(CFunction): + pass + + +class CProperty: + def __init__(self, name): + self.name = name + self.getter = None + self.setter = None + + +class CClass(CObject): + def __init__(self, st): + CObject.__init__(self, st.associatedTypedef.name) + if st.deprecated or st.associatedTypedef.deprecated: + self.deprecated = True + if len(st.associatedTypedef.briefDescription) > 0: + self.briefDescription = st.associatedTypedef.briefDescription + elif len(st.briefDescription) > 0: + self.briefDescription = st.briefDescription + if st.associatedTypedef.detailedDescription is not None: + self.detailedDescription = st.associatedTypedef.detailedDescription + elif st.detailedDescription is not None: + self.detailedDescription = st.detailedDescription + self.__struct = st + self.events = {} + self.classMethods = {} + self.instanceMethods = {} + self.properties = {} + self.__computeCFunctionPrefix() + + def __computeCFunctionPrefix(self): + self.cFunctionPrefix = '' + first = True + for l in self.name: + if l.isupper() and not first: + self.cFunctionPrefix += '_' + self.cFunctionPrefix += l.lower() + first = False + self.cFunctionPrefix += '_' + + def __addPropertyGetter(self, name, f): + if not name in self.properties: + prop = CProperty(name) + self.properties[name] = prop + self.properties[name].getter = f + + def __addPropertySetter(self, name, f): + if not name in self.properties: + prop = CProperty(name) + self.properties[name] = prop + self.properties[name].setter = f + + def __addClassMethod(self, f): + name = f.name[len(self.cFunctionPrefix):] + if name.startswith('get_') and len(f.arguments) == 0: + self.__addPropertyGetter(name[4:], f) + elif name.startswith('is_') and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': + self.__addPropertyGetter(name[3:], f) + elif name.endswith('_enabled') and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t': + self.__addPropertyGetter(name, f) + elif name.startswith('set_') and len(f.arguments) == 1: + self.__addPropertySetter(name[4:], f) + elif name.startswith('enable_') and len(f.arguments) == 1 and f.arguments[0].ctype == 'bool_t': + self.__addPropertySetter(name[7:] + '_enabled', f) + else: + if not f.name in self.classMethods: + self.classMethods[f.name] = f + + def __addInstanceMethod(self, f): + name = f.name[len(self.cFunctionPrefix):] + if name.startswith('get_') and len(f.arguments) == 1: + self.__addPropertyGetter(name[4:], f) + elif name.startswith('is_') and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': + self.__addPropertyGetter(name[3:], f) + elif name.endswith('_enabled') and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t': + self.__addPropertyGetter(name, f) + elif name.startswith('set_') and len(f.arguments) == 2: + self.__addPropertySetter(name[4:], f) + elif name.startswith('enable_') and len(f.arguments) == 2 and f.arguments[1].ctype == 'bool_t': + self.__addPropertySetter(name[7:] + '_enabled', f) + else: + if not f.name in self.instanceMethods: + self.instanceMethods[f.name] = f + + def addEvent(self, ev): + if not ev.name in self.events: + self.events[ev.name] = ev + + def addMethod(self, f): + if len(f.arguments) > 0 and f.arguments[0].ctype == self.name: + self.__addInstanceMethod(f) + else: + self.__addClassMethod(f) + + +class Project: + def __init__(self): + self.verbose = False + self.prettyPrint = False + self.enums = [] + self.__structs = [] + self.__typedefs = [] + self.__events = [] + self.__functions = [] + self.classes = [] + + def add(self, elem): + if isinstance(elem, CClass): + if self.verbose: + print("Adding class " + elem.name) + self.classes.append(elem) + elif isinstance(elem, CEnum): + if self.verbose: + print("Adding enum " + elem.name) + for ev in elem.values: + print("\t" + ev.name) + self.enums.append(elem) + elif isinstance(elem, CStruct): + if self.verbose: + print("Adding struct " + elem.name) + for sm in elem.members: + print("\t" + sm.ctype + " " + sm.name) + self.__structs.append(elem) + elif isinstance(elem, CTypedef): + if self.verbose: + print("Adding typedef " + elem.name) + print("\t" + elem.definition) + self.__typedefs.append(elem) + elif isinstance(elem, CEvent): + if self.verbose: + print("Adding event " + elem.name) + print("\tReturns: " + elem.returnArgument.ctype) + print("\tArguments: " + str(elem.arguments)) + self.__events.append(elem) + elif isinstance(elem, CFunction): + if self.verbose: + print("Adding function " + elem.name) + print("\tReturns: " + elem.returnArgument.ctype) + print("\tArguments: " + str(elem.arguments)) + self.__functions.append(elem) + + def __cleanDescription(self, descriptionNode): + for para in descriptionNode.findall('./para'): + for n in para.findall('./parameterlist'): + para.remove(n) + for n in para.findall("./simplesect[@kind='return']"): + para.remove(n) + for n in para.findall("./simplesect[@kind='see']"): + t = ''.join(n.itertext()) + n.clear() + n.tag = 'see' + n.text = t + for n in para.findall("./simplesect[@kind='note']"): + n.tag = 'note' + n.attrib = {} + for n in para.findall(".//xrefsect"): + para.remove(n) + for n in para.findall('.//ref'): + n.attrib = {} + for n in para.findall(".//mslist"): + para.remove(n) + if descriptionNode.tag == 'parameterdescription': + descriptionNode.tag = 'description' + if descriptionNode.tag == 'simplesect': + descriptionNode.tag = 'description' + descriptionNode.attrib = {} + return descriptionNode + + def __discoverClasses(self): + for td in self.__typedefs: + if td.definition.startswith('enum '): + for e in self.enums: + if (e.associatedTypedef is None) and td.definition[5:] == e.name: + e.associatedTypedef = td + break + elif td.definition.startswith('struct '): + structFound = False + for st in self.__structs: + if (st.associatedTypedef is None) and td.definition[7:] == st.name: + st.associatedTypedef = td + structFound = True + break + if not structFound: + name = td.definition[7:] + print("Structure with no associated typedef: " + name) + st = CStruct(name) + st.associatedTypedef = td + self.add(st) + for td in self.__typedefs: + if td.definition.startswith('struct '): + for st in self.__structs: + if st.associatedTypedef == td: + self.add(CClass(st)) + break + elif ('Linphone' + td.definition) == td.name: + st = CStruct(td.name) + st.associatedTypedef = td + self.add(st) + self.add(CClass(st)) + # Sort classes by length of name (longest first), so that methods are put in the right class + self.classes.sort(key = lambda c: len(c.name), reverse = True) + for e in self.__events: + eventAdded = False + for c in self.classes: + if c.name.endswith('Cbs') and e.name.startswith(c.name): + c.addEvent(e) + eventAdded = True + break + if not eventAdded: + for c in self.classes: + if e.name.startswith(c.name): + c.addEvent(e) + eventAdded = True + break + for f in self.__functions: + for c in self.classes: + if c.cFunctionPrefix == f.name[0 : len(c.cFunctionPrefix)]: + c.addMethod(f) + break + + def __parseCEnumValue(self, node): + ev = CEnumValue(node.find('./name').text) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + ev.deprecated = True + ev.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + ev.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + return ev + + def __parseCEnumMemberdef(self, node): + e = CEnum(node.find('./name').text) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + e.deprecated = True + e.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + e.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + enumvalues = node.findall("enumvalue[@prot='public']") + for enumvalue in enumvalues: + ev = self.__parseCEnumValue(enumvalue) + e.addValue(ev) + return e + + def __findCEnum(self, tree): + memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='enum']/memberdef[@kind='enum'][@prot='public']") + for m in memberdefs: + e = self.__parseCEnumMemberdef(m) + self.add(e) + + def __parseCStructMember(self, node, structname): + name = node.find('./name').text + definition = node.find('./definition').text + t = definition[0:string.find(definition, structname + "::" + name)] + sm = CStructMember(name, t) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + sm.deprecated = True + sm.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + sm.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + return sm + + def __parseCStructCompounddef(self, node): + s = CStruct(node.find('./compoundname').text) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + s.deprecated = True + s.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + s.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + structmembers = node.findall("sectiondef/memberdef[@kind='variable'][@prot='public']") + for structmember in structmembers: + sm = self.__parseCStructMember(structmember, s.name) + s.addMember(sm) + return s + + def __findCStruct(self, tree): + compounddefs = tree.findall("./compounddef[@kind='struct'][@prot='public']") + for c in compounddefs: + s = self.__parseCStructCompounddef(c) + self.add(s) + + def __parseCTypedefMemberdef(self, node): + name = node.find('./name').text + definition = node.find('./definition').text + if definition.startswith('typedef '): + definition = definition[8 :] + if name.endswith('Cb'): + pos = string.find(definition, "(*") + if pos == -1: + return None + returntype = definition[0:pos].strip() + returnarg = CArgument(returntype, enums = self.enums, structs = self.__structs) + returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']") + if returndesc is not None: + if returnarg.ctype == 'MSList': + n = returndesc.find('.//mslist') + if n is not None: + returnarg.containedType = n.text + returnarg.description = self.__cleanDescription(returndesc) + elif returnarg.completeType != 'void': + missingDocWarning += "\tReturn value is not documented\n" + definition = definition[pos + 2 :] + pos = string.find(definition, "(") + definition = definition[pos + 1 : -1] + argslist = CArgumentsList() + for argdef in definition.split(', '): + argType = '' + starPos = string.rfind(argdef, '*') + spacePos = string.rfind(argdef, ' ') + if starPos != -1: + argType = argdef[0 : starPos + 1] + argName = argdef[starPos + 1 :] + elif spacePos != -1: + argType = argdef[0 : spacePos] + argName = argdef[spacePos + 1 :] + argslist.addArgument(CArgument(argType, argName, self.enums, self.__structs)) + if len(argslist) > 0: + paramdescs = node.findall("detaileddescription/para/parameterlist[@kind='param']/parameteritem") + if paramdescs: + for arg in argslist.arguments: + for paramdesc in paramdescs: + if arg.name == paramdesc.find('./parameternamelist').find('./parametername').text: + arg.description = self.__cleanDescription(paramdesc.find('./parameterdescription')) + missingDocWarning = '' + for arg in argslist.arguments: + if arg.description == None: + missingDocWarning += "\t'" + arg.name + "' parameter not documented\n"; + if missingDocWarning != '': + print(name + ":\n" + missingDocWarning) + f = CEvent(name, returnarg, argslist) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + f.deprecated = True + f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + return f + else: + pos = string.rfind(definition, " " + name) + if pos != -1: + definition = definition[0 : pos] + td = CTypedef(name, definition) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + td.deprecated = True + td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + return td + return None + + def __findCTypedef(self, tree): + memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='typedef']/memberdef[@kind='typedef'][@prot='public']") + for m in memberdefs: + td = self.__parseCTypedefMemberdef(m) + self.add(td) + + def __parseCFunctionMemberdef(self, node): + missingDocWarning = '' + name = node.find('./name').text + t = ''.join(node.find('./type').itertext()) + returnarg = CArgument(t, enums = self.enums, structs = self.__structs) + returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']") + if returndesc is not None: + if returnarg.ctype == 'MSList': + n = returndesc.find('.//mslist') + if n is not None: + returnarg.containedType = n.text + returnarg.description = self.__cleanDescription(returndesc) + elif returnarg.completeType != 'void': + missingDocWarning += "\tReturn value is not documented\n" + argslist = CArgumentsList() + argslistNode = node.findall('./param') + for argNode in argslistNode: + argType = ''.join(argNode.find('./type').itertext()) + argName = '' + argNameNode = argNode.find('./declname') + if argNameNode is not None: + argName = ''.join(argNameNode.itertext()) + if argType != 'void': + argslist.addArgument(CArgument(argType, argName, self.enums, self.__structs)) + if len(argslist) > 0: + paramdescs = node.findall("./detaileddescription/para/parameterlist[@kind='param']/parameteritem") + if paramdescs: + for arg in argslist.arguments: + for paramdesc in paramdescs: + if arg.name == paramdesc.find('./parameternamelist').find('./parametername').text: + if arg.ctype == 'MSList': + n = paramdesc.find('.//mslist') + if n is not None: + arg.containedType = n.text + arg.description = self.__cleanDescription(paramdesc.find('./parameterdescription')) + missingDocWarning = '' + for arg in argslist.arguments: + if arg.description == None: + missingDocWarning += "\t'" + arg.name + "' parameter not documented\n"; + f = CFunction(name, returnarg, argslist) + deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']") + if deprecatedNode is not None: + f.deprecated = True + f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() + f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + if f.briefDescription == '' and ''.join(f.detailedDescription.itertext()).strip() == '': + return None + locationNode = node.find('./location') + if locationNode is not None: + f.location = locationNode.get('file') + if not f.location.endswith('.h'): + missingDocWarning += "\tNot documented in a header file ('" + f.location + "')\n"; + if missingDocWarning != '': + print(name + ":\n" + missingDocWarning) + return f + + def __findCFunction(self, tree): + memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='func']/memberdef[@kind='function'][@prot='public'][@static='no']") + for m in memberdefs: + f = self.__parseCFunctionMemberdef(m) + self.add(f) + + def initFromFiles(self, xmlfiles): + trees = [] + for f in xmlfiles: + tree = None + try: + if self.verbose: + print("Parsing XML file: " + f.name) + tree = ET.parse(f) + except ET.ParseError as e: + print(e) + if tree is not None: + trees.append(tree) + for tree in trees: + self.__findCEnum(tree) + for tree in trees: + self.__findCStruct(tree) + for tree in trees: + self.__findCTypedef(tree) + for tree in trees: + self.__findCFunction(tree) + self.__discoverClasses() + + def initFromDir(self, xmldir): + files = [ os.path.join(xmldir, f) for f in os.listdir(xmldir) if (os.path.isfile(os.path.join(xmldir, f)) and f.endswith('.xml')) ] + self.initFromFiles(files) + + def check(self): + for c in self.classes: + for name, p in c.properties.iteritems(): + if p.getter is None and p.setter is not None: + print("Property '" + name + "' of class '" + c.name + "' has a setter but no getter") + + +class Generator: + def __init__(self, outputfile): + self.__outputfile = outputfile + + def __generateEnum(self, cenum, enumsNode): + enumNodeAttributes = { 'name' : cenum.name, 'deprecated' : str(cenum.deprecated).lower() } + if cenum.associatedTypedef is not None: + enumNodeAttributes['name'] = cenum.associatedTypedef.name + enumNode = ET.SubElement(enumsNode, 'enum', enumNodeAttributes) + if cenum.briefDescription != '': + enumBriefDescriptionNode = ET.SubElement(enumNode, 'briefdescription') + enumBriefDescriptionNode.text = cenum.briefDescription + enumNode.append(cenum.detailedDescription) + if len(cenum.values) > 0: + enumValuesNode = ET.SubElement(enumNode, 'values') + for value in cenum.values: + enumValuesNodeAttributes = { 'name' : value.name, 'deprecated' : str(value.deprecated).lower() } + valueNode = ET.SubElement(enumValuesNode, 'value', enumValuesNodeAttributes) + if value.briefDescription != '': + valueBriefDescriptionNode = ET.SubElement(valueNode, 'briefdescription') + valueBriefDescriptionNode.text = value.briefDescription + valueNode.append(value.detailedDescription) + + def __generateFunction(self, parentNode, nodeName, f): + functionAttributes = { 'name' : f.name, 'deprecated' : str(f.deprecated).lower() } + if f.location is not None: + functionAttributes['location'] = f.location + functionNode = ET.SubElement(parentNode, nodeName, functionAttributes) + returnValueAttributes = { 'type' : f.returnArgument.ctype, 'completetype' : f.returnArgument.completeType } + if f.returnArgument.containedType is not None: + returnValueAttributes['containedtype'] = f.returnArgument.containedType + returnValueNode = ET.SubElement(functionNode, 'return', returnValueAttributes) + if f.returnArgument.description is not None: + returnValueNode.append(f.returnArgument.description) + argumentsNode = ET.SubElement(functionNode, 'arguments') + for arg in f.arguments: + argumentNodeAttributes = { 'name' : arg.name, 'type' : arg.ctype, 'completetype' : arg.completeType } + if arg.containedType is not None: + argumentNodeAttributes['containedtype'] = arg.containedType + argumentNode = ET.SubElement(argumentsNode, 'argument', argumentNodeAttributes) + if arg.description is not None: + argumentNode.append(arg.description) + if f.briefDescription != '': + functionBriefDescriptionNode = ET.SubElement(functionNode, 'briefdescription') + functionBriefDescriptionNode.text = f.briefDescription + functionNode.append(f.detailedDescription) + + def __generateClass(self, cclass, classesNode): + # Do not include classes that contain nothing + if len(cclass.events) == 0 and len(cclass.classMethods) == 0 and \ + len(cclass.instanceMethods) == 0 and len(cclass.properties) == 0: + return + # Check the capabilities of the class + has_ref_method = False + has_unref_method = False + has_destroy_method = False + for methodname in cclass.instanceMethods: + methodname_without_prefix = methodname.replace(cclass.cFunctionPrefix, '') + if methodname_without_prefix == 'ref': + has_ref_method = True + elif methodname_without_prefix == 'unref': + has_unref_method = True + elif methodname_without_prefix == 'destroy': + has_destroy_method = True + refcountable = False + destroyable = False + if has_ref_method and has_unref_method: + refcountable = True + if has_destroy_method: + destroyable = True + classNodeAttributes = { + 'name' : cclass.name, + 'cfunctionprefix' : cclass.cFunctionPrefix, + 'deprecated' : str(cclass.deprecated).lower(), + 'refcountable' : str(refcountable).lower(), + 'destroyable' : str(destroyable).lower() + } + # Generate the XML node for the class + classNode = ET.SubElement(classesNode, 'class', classNodeAttributes) + if len(cclass.events) > 0: + eventsNode = ET.SubElement(classNode, 'events') + eventnames = [] + for eventname in cclass.events: + eventnames.append(eventname) + eventnames.sort() + for eventname in eventnames: + self.__generateFunction(eventsNode, 'event', cclass.events[eventname]) + if len(cclass.classMethods) > 0: + classMethodsNode = ET.SubElement(classNode, 'classmethods') + methodnames = [] + for methodname in cclass.classMethods: + methodnames.append(methodname) + methodnames.sort() + for methodname in methodnames: + self.__generateFunction(classMethodsNode, 'classmethod', cclass.classMethods[methodname]) + if len(cclass.instanceMethods) > 0: + instanceMethodsNode = ET.SubElement(classNode, 'instancemethods') + methodnames = [] + for methodname in cclass.instanceMethods: + methodnames.append(methodname) + methodnames.sort() + for methodname in methodnames: + self.__generateFunction(instanceMethodsNode, 'instancemethod', cclass.instanceMethods[methodname]) + if len(cclass.properties) > 0: + propertiesNode = ET.SubElement(classNode, 'properties') + propnames = [] + for propname in cclass.properties: + propnames.append(propname) + propnames.sort() + for propname in propnames: + propertyNodeAttributes = { 'name' : propname } + propertyNode = ET.SubElement(propertiesNode, 'property', propertyNodeAttributes) + if cclass.properties[propname].getter is not None: + self.__generateFunction(propertyNode, 'getter', cclass.properties[propname].getter) + if cclass.properties[propname].setter is not None: + self.__generateFunction(propertyNode, 'setter', cclass.properties[propname].setter) + if cclass.briefDescription != '': + classBriefDescriptionNode = ET.SubElement(classNode, 'briefdescription') + classBriefDescriptionNode.text = cclass.briefDescription + classNode.append(cclass.detailedDescription) + + def generate(self, project): + print("Generating XML document of Linphone API to '" + self.__outputfile.name + "'") + apiNode = ET.Element('api') + project.enums.sort(key = lambda e: e.name) + if len(project.enums) > 0: + enumsNode = ET.SubElement(apiNode, 'enums') + for cenum in project.enums: + self.__generateEnum(cenum, enumsNode) + if len(project.classes) > 0: + classesNode = ET.SubElement(apiNode, 'classes') + project.classes.sort(key = lambda c: c.name) + for cclass in project.classes: + self.__generateClass(cclass, classesNode) + s = '\n' + s += ET.tostring(apiNode, 'utf-8') + if project.prettyPrint: + s = minidom.parseString(s).toprettyxml(indent='\t') + self.__outputfile.write(s) + + + +def main(argv = None): + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser(description="Generate XML version of the Linphone API.") + argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output XML file describing the Linphone API.") + argparser.add_argument('--verbose', help="Increase output verbosity", action='store_true') + argparser.add_argument('--pretty', help="XML pretty print", action='store_true') + argparser.add_argument('xmldir', help="XML directory generated by doxygen.") + args = argparser.parse_args() + if args.outputfile == None: + args.outputfile = open('api.xml', 'w') + project = Project() + if args.verbose: + project.verbose = True + if args.pretty: + project.prettyPrint = True + project.initFromDir(args.xmldir) + project.check() + gen = Generator(args.outputfile) + gen.generate(project) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/generator.cc b/tools/generator.cc new file mode 100644 index 000000000..c8763f1ef --- /dev/null +++ b/tools/generator.cc @@ -0,0 +1,454 @@ +/* +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 + +#define strncasecmp _strnicmp +#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()<<"="<getValue(); + 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); + + filename<getName())<<"/"<getName()<<" = "<getName()<<" || {};"<getHelp(),0); + mOutfile<getName()<<"."<getHelp().empty()){ + writeTabs(1); + mOutfile<<"/**"<getHelp(),1); + mOutfile<getName().substr(prefix_size,string::npos)<<" : "<getValue(); + if (++it!=members.end()) mOutfile<<","; + mOutfile<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..86a54d9b1 --- /dev/null +++ b/tools/genwrappers.cc @@ -0,0 +1,482 @@ +/* +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'; + string ret(tmp); + delete[] tmp; + return ret; +} + +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; + int value = 0; + for (it=enumValues.begin();it!=enumValues.end();++it){ + string initializer = (*it).getChild("initializer").getText(); + if ((initializer.length() > 1) && (initializer.at(0) == '=')) { + std::stringstream ss; + if ((initializer.length() > 2) && (initializer.at(1) == '0')) { + if ((initializer.length() > 3) && (initializer.at(2) == 'x')) { + ss << std::hex << initializer.substr(3); + } else { + ss << std::oct << initializer.substr(2); + } + } else { + ss << std::dec << initializer.substr(1); + } + ss >> value; + } + ConstField *cf=new ConstField(Type::getType("int"),(*it).getChild("name").getText(),value); + cf->setHelp((*it).getChild("detaileddescription").getChild("para").getText()); + klass->addConstField(cf); + value++; + } + +} + +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_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/lpc2xml_test.c b/tools/lpc2xml_test.c index cdad72f97..03ac571cf 100644 --- a/tools/lpc2xml_test.c +++ b/tools/lpc2xml_test.c @@ -47,13 +47,15 @@ void show_usage(int argc, char *argv[]) { } int main(int argc, char *argv[]) { + lpc2xml_context *ctx; + LpConfig *lpc; if(argc != 4) { show_usage(argc, argv); return -1; } - - lpc2xml_context *ctx = lpc2xml_context_new(cb_function, NULL); - LpConfig *lpc = lp_config_new(argv[2]); + + ctx = lpc2xml_context_new(cb_function, NULL); + lpc = lp_config_new(argv[2]); lpc2xml_set_lpc(ctx, lpc); if(strcmp("convert", argv[1]) == 0) { lpc2xml_convert_file(ctx, argv[3]); 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/python/.gitignore b/tools/python/.gitignore new file mode 100644 index 000000000..701f19514 --- /dev/null +++ b/tools/python/.gitignore @@ -0,0 +1,4 @@ +*.pyc +build +linphone.c +.kdev* diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py new file mode 100755 index 000000000..04de40a9e --- /dev/null +++ b/tools/python/apixml2python.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +# Copyright (C) 2014 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import argparse +import os +import pystache +import sys +import xml.etree.ElementTree as ET + +sys.path.append(os.path.realpath(__file__)) +from apixml2python.linphone import LinphoneModule, HandWrittenClassMethod, HandWrittenInstanceMethod, HandWrittenDeallocMethod, HandWrittenProperty + + +blacklisted_classes = [ + 'LinphoneTunnel', + 'LinphoneTunnelConfig' +] +blacklisted_events = [ + 'LinphoneCoreInfoReceivedCb', # missing LinphoneInfoMessage + 'LinphoneCoreNotifyReceivedCb', # missing LinphoneContent + 'LinphoneCoreFileTransferProgressIndicationCb', # missing LinphoneContent + 'LinphoneCoreFileTransferRecvCb', # missing LinphoneContent + 'LinphoneCoreFileTransferSendCb' # missing LinphoneContent +] +blacklisted_functions = [ + 'linphone_call_log_get_local_stats', # missing rtp_stats_t + 'linphone_call_log_get_remote_stats', # missing rtp_stats_t + 'linphone_call_params_get_privacy', # missing LinphonePrivacyMask + 'linphone_call_params_set_privacy', # missing LinphonePrivacyMask + 'linphone_chat_message_state_to_string', # There is no use to wrap this function + 'linphone_core_add_listener', + 'linphone_core_can_we_add_call', # private function + 'linphone_core_enable_log_collection', # need to handle class properties + 'linphone_core_get_audio_port_range', # to be handwritten because of result via arguments + 'linphone_core_get_supported_video_sizes', # missing MSVideoSizeDef + 'linphone_core_get_video_policy', # missing LinphoneVideoPolicy + 'linphone_core_get_video_port_range', # to be handwritten because of result via arguments + 'linphone_core_remove_listener', + 'linphone_core_serialize_logs', # There is no use to wrap this function + 'linphone_core_set_log_collection_max_file_size', # need to handle class properties + 'linphone_core_set_log_collection_path', # need to handle class properties + 'linphone_core_set_log_collection_prefix', # need to handle class properties + 'linphone_core_set_log_file', # There is no use to wrap this function + 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module + 'linphone_core_set_log_level', # There is no use to wrap this function + 'linphone_core_set_log_level_mask', # There is no use to wrap this function + 'linphone_core_set_video_policy', # missing LinphoneVideoPolicy + 'linphone_proxy_config_get_privacy', # missing LinphonePrivacyMask + 'linphone_proxy_config_normalize_number', # to be handwritten because of result via arguments + 'linphone_proxy_config_set_file_transfer_server', # defined but not implemented in linphone core + 'linphone_proxy_config_set_privacy', # missing LinphonePrivacyMask + 'linphone_tunnel_get_http_proxy', # to be handwritten because of double pointer indirection + 'linphone_xml_rpc_request_new_with_args', # to be handwritten because of va_list + 'lp_config_for_each_entry', # to be handwritten because of callback + 'lp_config_for_each_section', # to be handwritten because of callback + 'lp_config_get_range', # to be handwritten because of result via arguments + 'lp_config_load_dict_to_section', # missing LinphoneDictionary + 'lp_config_section_to_dict' # missing LinphoneDictionary +] +hand_written_functions = [ + HandWrittenClassMethod('Buffer', 'new_from_data', 'linphone_buffer_new_from_data', "Create a new LinphoneBuffer object from existing data.\n\n:param data: The initial data to store in the LinphoneBuffer.\n:type data: ByteArray\n:returns: A new LinphoneBuffer object.\n:rtype: linphone.Buffer"), + HandWrittenProperty('Buffer', 'content', 'linphone_buffer_get_content', 'linphone_buffer_set_content', "[ByteArray] Set the content of the data buffer."), + HandWrittenProperty('Content', 'buffer', 'linphone_content_get_buffer', 'linphone_content_set_buffer', "[ByteArray] Set the content data buffer."), + HandWrittenProperty('Call', 'native_video_window_id', 'linphone_call_get_native_video_window_id', 'linphone_call_set_native_video_window_id', "[int] Set the native video window id where the video is to be displayed."), + HandWrittenProperty('Core', 'native_preview_window_id', 'linphone_core_get_native_preview_window_id', 'linphone_core_set_native_preview_window_id', "[int] Set the native window id where the preview video (local camera) is to be displayed. This has to be used in conjonction with :py:meth:`linphone.Core.use_preview_window` . MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given."), + HandWrittenProperty('Core', 'native_video_window_id', 'linphone_core_get_native_video_window_id', 'linphone_core_set_native_video_window_id', "[int] Set the native video window id where the video is to be displayed. For MacOS, Linux, Windows: if not set or LINPHONE_VIDEO_DISPLAY_AUTO the core will create its own window, unless the special id LINPHONE_VIDEO_DISPLAY_NONE is given."), + HandWrittenProperty('Core', 'sip_transports', 'linphone_core_get_sip_transports', 'linphone_core_set_sip_transports', "[:py:class:`linphone.SipTransports`] Sets the ports to be used for each transport. A zero value port for a given transport means the transport is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be chosen randomly by the system."), + HandWrittenProperty('Core', 'sip_transports_used', 'linphone_core_get_sip_transports_used', None, "[:py:class:`linphone.SipTransports`] Retrieves the real port number assigned for each sip transport (udp, tcp, tls). A zero value means that the transport is not activated. If LC_SIP_TRANSPORT_RANDOM was passed to :py:attr:`linphone.Core.sip_transports`, the random port choosed by the system is returned."), + HandWrittenProperty('Core', 'sound_devices', 'linphone_core_get_sound_devices', None, "[list of string] Get the available sound devices."), + HandWrittenProperty('Core', 'video_devices', 'linphone_core_get_video_devices', None, "[list of string] Get the available video capture devices."), + HandWrittenClassMethod('Core', 'new', 'linphone_core_new', "Instantiate a LinphoneCore object.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param configPath: A path to a config file. If it does not exists it will be created. The config file is used to store all settings, call logs, friends, proxies... so that all these settings become persistent over the life of the LinphoneCore object. It is allowed to set to None. In that case LinphoneCore will not store any settings.\n:type configPath: string\n:param factoryConfigPath: A path to a read-only config file that can be used to store hard-coded preference such as proxy settings or internal preferences. The settings in this factory file always override the one in the normal config file. It is OPTIONAL, use None if unneeded.\n:type factoryConfigPath: string\n:rtype: linphone.Core"), + HandWrittenClassMethod('Core', 'new_with_config', 'linphone_core_new_with_config', "Instantiate a LinphoneCore object from a LpConfig.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param config: A LpConfig object holding the configuration of the LinphoneCore to be instantiated.\n:rtype: linphone.Core"), + HandWrittenDeallocMethod('Core', 'linphone_core_destroy') +] + +def generate(apixmlfile, outputfile): + tree = ET.parse(apixmlfile) + renderer = pystache.Renderer() + m = LinphoneModule(tree, blacklisted_classes, blacklisted_events, blacklisted_functions, hand_written_functions) + os.chdir('apixml2python') + tmpfilename = outputfile.name + '.tmp' + f = open(tmpfilename, 'w') + f.write(renderer.render(m)) + f.close() + f = open(tmpfilename, 'rU') + for line in f: + outputfile.write(line) + f.close() + os.unlink(tmpfilename) + + +def main(argv = None): + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser(description="Generate a Python wrapper of the Linphone API.") + argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output C file containing the code of the Python wrapper.") + argparser.add_argument('apixmlfile', help="XML file of the Linphone API generated by genapixml.py.") + args = argparser.parse_args() + if args.outputfile == None: + args.outputfile = open('linphone.c', 'w') + generate(args.apixmlfile, args.outputfile) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/po/cat-id-tbl.c b/tools/python/apixml2python/__init__.py similarity index 100% rename from po/cat-id-tbl.c rename to tools/python/apixml2python/__init__.py diff --git a/tools/python/apixml2python/handwritten_declarations.mustache b/tools/python/apixml2python/handwritten_declarations.mustache new file mode 100644 index 000000000..3449fa7e6 --- /dev/null +++ b/tools/python/apixml2python/handwritten_declarations.mustache @@ -0,0 +1,42 @@ +static PyObject * pylinphone_Call_get_native_video_window_id(PyObject *self, void *closure); +static int pylinphone_Call_set_native_video_window_id(PyObject *self, PyObject *value, void *closure); +static PyObject * pylinphone_Core_get_native_preview_window_id(PyObject *self, void *closure); +static int pylinphone_Core_set_native_preview_window_id(PyObject *self, PyObject *value, void *closure); +static PyObject * pylinphone_Core_get_native_video_window_id(PyObject *self, void *closure); +static int pylinphone_Core_set_native_video_window_id(PyObject *self, PyObject *value, void *closure); +static PyObject * pylinphone_Core_get_sip_transports(PyObject *self, void *closure); +static int pylinphone_Core_set_sip_transports(PyObject *self, PyObject *value, void *closure); +static void pylinphone_Core_dealloc(PyObject *self); +static PyObject * pylinphone_Core_get_sip_transports_used(PyObject *self, void *closure); +static PyObject * pylinphone_Core_get_sound_devices(PyObject *self, void *closure); +static PyObject * pylinphone_Core_get_video_devices(PyObject *self, void *closure); + +static PyTypeObject pylinphone_VideoSizeType; +static PyTypeObject pylinphone_SipTransportsType; + +typedef struct { + PyObject_HEAD + MSVideoSize vs; +} pylinphone_VideoSizeObject; + +typedef struct { + PyObject_HEAD + LCSipTransports lcst; +} pylinphone_SipTransportsObject; + +int PyLinphoneVideoSize_Check(PyObject *p); +MSVideoSize PyLinphoneVideoSize_AsMSVideoSize(PyObject *obj); +PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs); + +int PyLinphoneSipTransports_Check(PyObject *p); +LCSipTransports * PyLinphoneSipTransports_AsLCSipTransports(PyObject *obj); +PyObject * PyLinphoneSipTransports_FromLCSipTransports(LCSipTransports lcst); + +time_t PyDateTime_As_time_t(PyObject *obj); +PyObject * PyDateTime_From_time_t(time_t t); + +static PyObject * pylinphone_Buffer_get_content(PyObject *self, void *closure); +static int pylinphone_Buffer_set_content(PyObject *self, PyObject *value, void *closure); + +static PyObject * pylinphone_Content_get_buffer(PyObject *self, void *closure); +static int pylinphone_Content_set_buffer(PyObject *self, PyObject *value, void *closure); diff --git a/tools/python/apixml2python/handwritten_definitions.mustache b/tools/python/apixml2python/handwritten_definitions.mustache new file mode 100644 index 000000000..4937b951e --- /dev/null +++ b/tools/python/apixml2python/handwritten_definitions.mustache @@ -0,0 +1,972 @@ +static void pylinphone_dispatch_messages(void) { +#ifdef WIN32 + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, 1)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#endif +} + +static void pylinphone_log(const char *level, int indent, const char *fmt, va_list args) { + static int current_indent = 1; + PyObject *linphone_module; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + if (gstate != PyGILState_LOCKED) return; + linphone_module = PyImport_ImportModule("linphone.linphone"); + if (linphone_module != NULL) { + if (PyObject_HasAttrString(linphone_module, "__log_handler")) { + PyObject *log_handler = PyObject_GetAttrString(linphone_module, "__log_handler"); + if (log_handler != NULL) { + if (PyCallable_Check(log_handler)) { + char logstr[4096]; + int i = 0; + if (indent == -1) current_indent--; + if (current_indent < 1) current_indent = 1; + if ((indent >= -1) && (indent <= 1)) { + for (i = 0; i < current_indent; i++) { + logstr[i] = '\t'; + } + } + if (indent == 1) current_indent++; + if (vsnprintf(logstr + i, sizeof(logstr) - i, fmt, args) > 0) { + PyObject *pyargs = Py_BuildValue("ss", level, logstr); + if (PyEval_CallObject(log_handler, pyargs) == NULL) { + PyErr_Print(); + } + Py_DECREF(pyargs); + } + } + Py_DECREF(log_handler); + } + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); +} + +static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + pylinphone_log("debug", indent, fmt, args); + va_end(args); +} + +static const char * pylinphone_ortp_log_level_to_string(OrtpLogLevel lev) { + switch (lev) { + default: + case ORTP_DEBUG: + return "debug"; + case ORTP_MESSAGE: + return "info"; + case ORTP_WARNING: + return "warning"; + case ORTP_ERROR: + return "error"; + case ORTP_FATAL: + return "critical"; + case ORTP_TRACE: + return "debug"; + } +} + +static void pylinphone_module_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + PyGILState_STATE gstate; + PyObject *linphone_module; + const char *level; + + gstate = PyGILState_Ensure(); + if (gstate != PyGILState_LOCKED) return; + linphone_module = PyImport_ImportModule("linphone.linphone"); + level = pylinphone_ortp_log_level_to_string(lev); + if (linphone_module != NULL) { + if (PyObject_HasAttrString(linphone_module, "__log_handler")) { + PyObject *log_handler = PyObject_GetAttrString(linphone_module, "__log_handler"); + if (log_handler != NULL) { + if (PyCallable_Check(log_handler)) { + char logstr[4096]; + if (vsnprintf(logstr, sizeof(logstr), fmt, args) > 0) { + PyObject *pyargs = Py_BuildValue("ss", level, logstr); + if (PyEval_CallObject(log_handler, pyargs) == NULL) { + PyErr_Print(); + } + Py_DECREF(pyargs); + } + } + Py_DECREF(log_handler); + } + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); +} + +static void pylinphone_init_logging(void) { + linphone_core_serialize_logs(); + linphone_core_set_log_handler(pylinphone_module_log_handler); + linphone_core_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); +} + + +static PyObject * pylinphone_module_method_set_log_handler(PyObject *self, PyObject *args) { + PyObject *linphone_module = PyImport_ImportModule("linphone.linphone"); + PyObject *callback; + if (!PyArg_ParseTuple(args, "O", &callback)) { + return NULL; + } + if (!PyCallable_Check(callback) && (callback != Py_None)) { + PyErr_SetString(PyExc_TypeError, "The argument must be a callable or None"); + return NULL; + } + if (linphone_module != NULL) { + PyObject_SetAttrString(linphone_module, "__log_handler", callback); + Py_DECREF(linphone_module); + } + Py_RETURN_NONE; +} + + +static PyObject * pylinphone_Call_get_native_video_window_id(PyObject *self, void *closure) { + void * cresult; + PyObject * pyresult; + PyObject * pyret; + const LinphoneCall *native_ptr; + native_ptr = pylinphone_Call_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Call instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + cresult = linphone_call_get_native_video_window_id(native_ptr); + pylinphone_dispatch_messages(); + + pyret = Py_BuildValue("k", (unsigned long)cresult); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Call_set_native_video_window_id(PyObject *self, PyObject *value, void *closure) { + LinphoneCall *native_ptr; + unsigned long _id; + native_ptr = pylinphone_Call_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Call instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'native_video_window_id' attribute."); + return -1; + } + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'native_video_window_id' attribute value must be a unsigned int."); + return -1; + } + + _id = (unsigned long)PyInt_AsUnsignedLongMask(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %u)", __FUNCTION__, self, native_ptr, _id); + linphone_call_set_native_video_window_id(native_ptr, (void *)_id); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} + + +static PyObject * pylinphone_Core_get_native_preview_window_id(PyObject *self, void *closure) { + void * cresult; + PyObject * pyresult; + PyObject * pyret; + const LinphoneCore *native_ptr; + native_ptr = pylinphone_Core_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + cresult = linphone_core_get_native_preview_window_id(native_ptr); + pylinphone_dispatch_messages(); + + pyret = Py_BuildValue("k", (unsigned long)cresult); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Core_set_native_preview_window_id(PyObject *self, PyObject *value, void *closure) { + LinphoneCore *native_ptr; + unsigned long _id; + native_ptr = pylinphone_Core_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'native_preview_window_id' attribute."); + return -1; + } + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'native_preview_window_id' attribute value must be a unsigned int."); + return -1; + } + + _id = (unsigned long)PyInt_AsUnsignedLongMask(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %u)", __FUNCTION__, self, native_ptr, _id); + linphone_core_set_native_preview_window_id(native_ptr, (void *)_id); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} + + +static PyObject * pylinphone_Core_get_native_video_window_id(PyObject *self, void *closure) { + void * cresult; + PyObject * pyresult; + PyObject * pyret; + const LinphoneCore *native_ptr; + native_ptr = pylinphone_Core_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + cresult = linphone_core_get_native_video_window_id(native_ptr); + pylinphone_dispatch_messages(); + + pyret = Py_BuildValue("k", (unsigned long)cresult); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Core_set_native_video_window_id(PyObject *self, PyObject *value, void *closure) { + LinphoneCore *native_ptr; + unsigned long _id; + native_ptr = pylinphone_Core_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'native_video_window_id' attribute."); + return -1; + } + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'native_video_window_id' attribute value must be a unsigned int."); + return -1; + } + + _id = (unsigned long)PyInt_AsUnsignedLongMask(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %u)", __FUNCTION__, self, native_ptr, _id); + linphone_core_set_native_video_window_id(native_ptr, (void *)_id); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} + +static PyObject * pylinphone_Core_get_sip_transports(PyObject *self, void *closure) { + PyObject *pytr; + LCSipTransports tr = { 0 }; + LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self); + + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + linphone_core_get_sip_transports(native_ptr, &tr); + pylinphone_dispatch_messages(); + + pytr = PyLinphoneSipTransports_FromLCSipTransports(tr); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pytr); + return pytr; +} + +static int pylinphone_Core_set_sip_transports(PyObject *self, PyObject *value, void *closure) { + LinphoneCore *native_ptr; + PyObject * _tr_config; + const LCSipTransports * _tr_config_native_obj; + native_ptr = pylinphone_Core_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'sip_transports' attribute."); + return -1; + } + if (!PyLinphoneSipTransports_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'sip_transports' attribute value must be a linphone.SipTransports."); + return -1; + } + + _tr_config = value; + _tr_config_native_obj = PyLinphoneSipTransports_AsLCSipTransports(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, _tr_config, _tr_config_native_obj); + linphone_core_set_sip_transports(native_ptr, _tr_config_native_obj); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} + +static PyObject * pylinphone_Core_get_sip_transports_used(PyObject *self, void *closure) { + PyObject *pytr; + LCSipTransports tr = { 0 }; + LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self); + + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + linphone_core_get_sip_transports_used(native_ptr, &tr); + pylinphone_dispatch_messages(); + + pytr = PyLinphoneSipTransports_FromLCSipTransports(tr); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pytr); + return pytr; +} + + + +static PyObject * pylinphone_Core_get_sound_devices(PyObject *self, void *closure) { + PyObject *_list; + const char **_devices; + LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self); + + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + _devices = linphone_core_get_sound_devices(native_ptr); + pylinphone_dispatch_messages(); + + _list = PyList_New(0); + while (*_devices != NULL) { + PyObject *_item = PyString_FromString(*_devices); + PyList_Append(_list, _item); + _devices++; + } + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, _list); + return _list; +} + +static PyObject * pylinphone_Core_get_video_devices(PyObject *self, void *closure) { + PyObject *_list; + const char **_devices; + LinphoneCore *native_ptr = pylinphone_Core_get_native_ptr(self); + + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Core instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + _devices = linphone_core_get_video_devices(native_ptr); + pylinphone_dispatch_messages(); + + _list = PyList_New(0); + while (*_devices != NULL) { + PyObject *_item = PyString_FromString(*_devices); + PyList_Append(_list, _item); + _devices++; + } + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, _list); + return _list; +} + +static void pylinphone_init_ms2_plugins(void) { + ms_init(); // Initialize mediastreamer2 before loading the plugins +#ifdef ENABLE_OPENH264 + libmsopenh264_init(); +#endif +#ifdef ENABLE_WASAPI + libmswasapi_init(); +#endif +} + +static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args) { + LinphoneCore * cresult; + pylinphone_CoreObject *self; + PyObject * pyret; + LinphoneCoreVTable _vtable = { 0 }; + PyObject * _vtable_dict; + const char * _config_path; + const char * _factory_config_path; + + if (!PyArg_ParseTuple(args, "Ozz", &_vtable_dict, &_config_path, &_factory_config_path)) { + return NULL; + } + if (!PyDict_Check(_vtable_dict)) { + PyErr_SetString(PyExc_TypeError, "The first argument must be a dictionary"); + return NULL; + } + + self = (pylinphone_CoreObject *)PyObject_CallObject((PyObject *) &pylinphone_CoreType, NULL); + if (self == NULL) { + return NULL; + } + Py_INCREF(_vtable_dict); + self->vtable_dict = _vtable_dict; +{{#core_events}} + {{{event_vtable_reference}}} +{{/core_events}} + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p, \"%s\", \"%s\")", __FUNCTION__, _vtable_dict, _config_path, _factory_config_path); + pylinphone_init_ms2_plugins(); + cresult = linphone_core_new(&_vtable, _config_path, _factory_config_path, self); + self->native_ptr = cresult; + + pyret = Py_BuildValue("O", self); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + Py_DECREF(self); + return pyret; +} + +static PyObject * pylinphone_Core_class_method_new_with_config(PyObject *cls, PyObject *args) { + LinphoneCore * cresult; + pylinphone_CoreObject *self; + PyObject * pyret; + LinphoneCoreVTable _vtable = { 0 }; + PyObject * _vtable_dict; + PyObject * _config; + LpConfig * _config_native_ptr; + + if (!PyArg_ParseTuple(args, "OO", &_vtable_dict, &_config)) { + return NULL; + } + if (!PyDict_Check(_vtable_dict)) { + PyErr_SetString(PyExc_TypeError, "The first argument must be a dictionary"); + return NULL; + } + + if ((_config_native_ptr = pylinphone_LpConfig_get_native_ptr(_config)) == NULL) { + return NULL; + } + + self = (pylinphone_CoreObject *)PyObject_CallObject((PyObject *) &pylinphone_CoreType, NULL); + if (self == NULL) { + return NULL; + } + Py_INCREF(_vtable_dict); + self->vtable_dict = _vtable_dict; +{{#core_events}} + {{{event_vtable_reference}}} +{{/core_events}} + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, _config, _config_native_ptr); + pylinphone_init_ms2_plugins(); + cresult = linphone_core_new_with_config(&_vtable, _config_native_ptr, self); + self->native_ptr = cresult; + + pyret = Py_BuildValue("O", self); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + Py_DECREF(self); + return pyret; +} + +static void pylinphone_Core_dealloc(PyObject *self) { + LinphoneCore * native_ptr = pylinphone_Core_get_native_ptr(self); + if (Py_REFCNT(self) < 0) return; + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + + if (native_ptr != NULL) { + linphone_core_destroy(native_ptr); + ms_exit(); // De-initialize mediastreamer + } + + pylinphone_dispatch_messages(); + Py_XDECREF(((pylinphone_CoreObject *)self)->user_data); + Py_XDECREF(((pylinphone_CoreObject *)self)->vtable_dict); + + self->ob_type->tp_free(self); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__); +} + + + +static void pylinphone_VideoSize_dealloc(PyObject *self) { + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, self); + self->ob_type->tp_free(self); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__); +} + +static PyObject * pylinphone_VideoSize_new(PyTypeObject *type, PyObject *args, PyObject *kw) { + pylinphone_VideoSizeObject *self = (pylinphone_VideoSizeObject *)type->tp_alloc(type, 0); + pylinphone_trace(1, "[PYLINPHONE] >>> %s()", __FUNCTION__); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, self); + return (PyObject *)self; +} + +static int pylinphone_VideoSize_init(PyObject *self, PyObject *args, PyObject *kw) { + pylinphone_VideoSizeObject *vso = (pylinphone_VideoSizeObject *)self; + int width; + int height; + if (!PyArg_ParseTuple(args, "ii", &width, &height)) { + return -1; + } + vso->vs.width = width; + vso->vs.height = height; + return 0; +} + +static PyMemberDef pylinphone_VideoSize_members[] = { + { "width", T_INT, offsetof(pylinphone_VideoSizeObject, vs) + offsetof(MSVideoSize, width), 0, "[int] The width of the video" }, + { "height", T_INT, offsetof(pylinphone_VideoSizeObject, vs) + offsetof(MSVideoSize, height), 0, "[int] The height of the video" }, + { NULL, 0, 0, 0, NULL } /* Sentinel */ +}; + +static PyTypeObject pylinphone_VideoSizeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "linphone.VideoSize", /* tp_name */ + sizeof(pylinphone_VideoSizeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + pylinphone_VideoSize_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Object representing the size of a video: its width and its height in pixels.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + pylinphone_VideoSize_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pylinphone_VideoSize_init, /* tp_init */ + 0, /* tp_alloc */ + pylinphone_VideoSize_new, /* tp_new */ + 0, /* tp_free */ +}; + +int PyLinphoneVideoSize_Check(PyObject *p) { + return PyObject_IsInstance(p, (PyObject *)&pylinphone_VideoSizeType); +} + +MSVideoSize PyLinphoneVideoSize_AsMSVideoSize(PyObject *obj) { + return ((pylinphone_VideoSizeObject *)obj)->vs; +} + +PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs) { + PyObject *linphone_module; + PyObject *pyret = NULL; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + linphone_module = PyImport_ImportModule("linphone.linphone"); + if (linphone_module != NULL) { + PyObject *cls = PyObject_GetAttrString(linphone_module, "VideoSize"); + if (cls != NULL) { + PyObject *args = Py_BuildValue("ii", vs.width, vs.height); + pyret = PyEval_CallObject(cls, args); + if (pyret == NULL) { + PyErr_Print(); + } + Py_DECREF(args); + Py_DECREF(cls); + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); + + if (pyret == NULL) { + Py_RETURN_NONE; + } + return pyret; +} + + + +static void pylinphone_SipTransports_dealloc(PyObject *self) { + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, self); + self->ob_type->tp_free(self); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__); +} + +static PyObject * pylinphone_SipTransports_new(PyTypeObject *type, PyObject *args, PyObject *kw) { + pylinphone_SipTransportsObject *self = (pylinphone_SipTransportsObject *)type->tp_alloc(type, 0); + pylinphone_trace(1, "[PYLINPHONE] >>> %s()", __FUNCTION__); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, self); + return (PyObject *)self; +} + +static int pylinphone_SipTransports_init(PyObject *self, PyObject *args, PyObject *kw) { + pylinphone_SipTransportsObject *sto = (pylinphone_SipTransportsObject *)self; + int udp_port; + int tcp_port; + int tls_port; + int dtls_port; + if (!PyArg_ParseTuple(args, "iiii", &udp_port, &tcp_port, &tls_port, &dtls_port)) { + return -1; + } + sto->lcst.udp_port = udp_port; + sto->lcst.tcp_port = tcp_port; + sto->lcst.tls_port = tls_port; + sto->lcst.dtls_port = dtls_port; + return 0; +} + +static PyMemberDef pylinphone_SipTransports_members[] = { + { "udp_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, udp_port), 0, "[int] The port used for UDP SIP transport" }, + { "tcp_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, tcp_port), 0, "[int] The port used for TCP SIP transport" }, + { "tls_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, tls_port), 0, "[int] The port used for TLS SIP transport" }, + { "dtls_port", T_INT, offsetof(pylinphone_SipTransportsObject, lcst) + offsetof(LCSipTransports, dtls_port), 0, "[int] The port used for DTLS SIP transport" }, + { NULL, 0, 0, 0, NULL } /* Sentinel */ +}; + +static PyTypeObject pylinphone_SipTransportsType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "linphone.SipTransports", /* tp_name */ + sizeof(pylinphone_SipTransportsObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + pylinphone_SipTransports_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Object representing the SIP transports: its UDP, TCP, TLS and DTLS ports.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + pylinphone_SipTransports_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pylinphone_SipTransports_init, /* tp_init */ + 0, /* tp_alloc */ + pylinphone_SipTransports_new, /* tp_new */ + 0, /* tp_free */ +}; + +int PyLinphoneSipTransports_Check(PyObject *p) { + return PyObject_IsInstance(p, (PyObject *)&pylinphone_SipTransportsType); +} + +LCSipTransports * PyLinphoneSipTransports_AsLCSipTransports(PyObject *obj) { + return &((pylinphone_SipTransportsObject *)obj)->lcst; +} + +PyObject * PyLinphoneSipTransports_FromLCSipTransports(LCSipTransports lcst) { + PyObject *linphone_module; + PyObject *pyret = NULL; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + linphone_module = PyImport_ImportModule("linphone.linphone"); + if (linphone_module != NULL) { + PyObject *cls = PyObject_GetAttrString(linphone_module, "SipTransports"); + if (cls != NULL) { + PyObject *args = Py_BuildValue("iiii", lcst.udp_port, lcst.tcp_port, lcst.tls_port, lcst.dtls_port); + pyret = PyEval_CallObject(cls, args); + if (pyret == NULL) { + PyErr_Print(); + } + Py_DECREF(args); + Py_DECREF(cls); + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); + + if (pyret == NULL) { + Py_RETURN_NONE; + } + return pyret; +} + + + +time_t PyDateTime_As_time_t(PyObject *obj) { + time_t ret = -1; + PyObject *utctimetuple = PyObject_GetAttrString(obj, "utctimetuple"); + if (utctimetuple != NULL) { + PyObject *calendar_module = PyImport_ImportModule("calendar"); + if (calendar_module != NULL) { + PyObject *timegm = PyObject_GetAttrString(calendar_module, "timegm"); + if (timegm != NULL) { + PyObject *args; + PyObject *tuple; + PyObject *pyres; + args = Py_BuildValue("()"); + tuple = PyEval_CallObject(utctimetuple, args); + Py_DECREF(args); + args = Py_BuildValue("(O)", tuple); + pyres = PyEval_CallObject(timegm, args); + Py_DECREF(args); + ret = (time_t)PyLong_AsLong(pyres); + Py_DECREF(timegm); + } + Py_DECREF(calendar_module); + } + Py_DECREF(utctimetuple); + } + return ret; +} + +PyObject * PyDateTime_From_time_t(time_t t) { + PyObject *pyret = NULL; + PyObject *datetime_module; + if (t == -1) { + Py_RETURN_NONE; + } + datetime_module = PyImport_ImportModule("datetime"); + if (datetime_module != NULL) { + PyObject *datetime_class = PyObject_GetAttrString(datetime_module, "datetime"); + if (datetime_class != NULL) { + PyObject *utcfromtimestamp = PyObject_GetAttrString(datetime_class, "utcfromtimestamp"); + if (utcfromtimestamp != NULL) { + PyObject *args = Py_BuildValue("(f)", (float)t); + pyret = PyEval_CallObject(utcfromtimestamp, args); + if (pyret == NULL) { + PyErr_Print(); + } + Py_DECREF(args); + Py_DECREF(utcfromtimestamp); + } + Py_DECREF(datetime_class); + } + Py_DECREF(datetime_module); + } + if (pyret == NULL) { + Py_RETURN_NONE; + } + return pyret; +} + + +static PyObject * pylinphone_PayloadTypeType_module_method_string(PyObject *self, PyObject *args) { + const char *value_str = "[invalid]"; + int value; + PyObject *pyret; + if (!PyArg_ParseTuple(args, "i", &value)) { + return NULL; + } + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%d)", __FUNCTION__, value); + switch (value) { + case PAYLOAD_AUDIO_CONTINUOUS: + value_str = "PAYLOAD_AUDIO_CONTINUOUS"; + break; + case PAYLOAD_AUDIO_PACKETIZED: + value_str = "PAYLOAD_AUDIO_PACKETIZED"; + break; + case PAYLOAD_VIDEO: + value_str = "PAYLOAD_VIDEO"; + break; + case PAYLOAD_TEXT: + value_str = "PAYLOAD_TEXT"; + break; + case PAYLOAD_OTHER: + value_str = "PAYLOAD_OTHER"; + break; + default: + break; + } + pyret = Py_BuildValue("z", value_str); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static PyMethodDef pylinphone_PayloadTypeType_ModuleMethods[] = { + { "string", pylinphone_PayloadTypeType_module_method_string, METH_VARARGS, "Get a string representation of a linphone.PayloadTypeType value." }, + /* Sentinel */ + { NULL, NULL, 0, NULL } +}; + + +static PyObject * pylinphone_Buffer_class_method_new_from_data(PyObject *cls, PyObject *args) { + LinphoneBuffer * cresult; + pylinphone_BufferObject *self; + PyObject * pyret; + PyObject * _byte_array; + + if (!PyArg_ParseTuple(args, "O", &_byte_array)) { + return NULL; + } + if (!PyByteArray_Check(_byte_array)) { + PyErr_SetString(PyExc_TypeError, "The argument must be a ByteArray"); + return NULL; + } + + self = (pylinphone_BufferObject *)PyObject_CallObject((PyObject *) &pylinphone_BufferType, NULL); + if (self == NULL) { + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, _byte_array); + cresult = linphone_buffer_new_from_data((uint8_t *)PyByteArray_AsString(_byte_array), PyByteArray_Size(_byte_array)); + self->native_ptr = cresult; + + pyret = Py_BuildValue("O", self); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + Py_DECREF(self); + return pyret; +} + +static PyObject * pylinphone_Buffer_get_content(PyObject *self, void *closure) { + const uint8_t * ccontent; + size_t csize; + PyObject * pyresult; + PyObject * pyret; + const char *pyret_fmt; + const LinphoneBuffer *native_ptr; + native_ptr = pylinphone_Buffer_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Buffer instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + ccontent = linphone_buffer_get_content(native_ptr); + csize = linphone_buffer_get_size(native_ptr); + pylinphone_dispatch_messages(); + + pyresult = PyByteArray_FromStringAndSize((const char *)ccontent, csize); + pyret = Py_BuildValue("O", pyresult); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Buffer_set_content(PyObject *self, PyObject *value, void *closure) { + LinphoneBuffer *native_ptr; + uint8_t * _content; + size_t _size; + LinphonePresenceModel * _presence_native_ptr = NULL; + native_ptr = pylinphone_Buffer_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Buffer instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'content' attribute."); + return -1; + } + if ((value != Py_None) && !PyByteArray_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'content' attribute value must be a ByteArray instance."); + return -1; + } + + _content = (uint8_t *)PyByteArray_AsString(value); + _size = PyByteArray_Size(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, value, _content); + linphone_buffer_set_content(native_ptr, _content, _size); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} + + +static PyObject * pylinphone_Content_get_buffer(PyObject *self, void *closure) { + void * cbuffer; + size_t csize; + PyObject * pyresult; + PyObject * pyret; + const char *pyret_fmt; + const LinphoneContent *native_ptr; + native_ptr = pylinphone_Content_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Content instance"); + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p])", __FUNCTION__, self, native_ptr); + cbuffer = linphone_content_get_buffer(native_ptr); + csize = linphone_content_get_size(native_ptr); + pylinphone_dispatch_messages(); + + pyresult = PyByteArray_FromStringAndSize((const char *)cbuffer, csize); + pyret = Py_BuildValue("O", pyresult); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static int pylinphone_Content_set_buffer(PyObject *self, PyObject *value, void *closure) { + LinphoneContent *native_ptr; + void * _buffer; + size_t _size; + LinphonePresenceModel * _presence_native_ptr = NULL; + native_ptr = pylinphone_Content_get_native_ptr(self); + if (native_ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "Invalid linphone.Content instance"); + return -1; + } + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the 'buffer' attribute."); + return -1; + } + if ((value != Py_None) && !PyByteArray_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The 'buffer' attribute value must be a ByteArray instance."); + return -1; + } + + _buffer = PyByteArray_AsString(value); + _size = PyByteArray_Size(value); + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %p [%p])", __FUNCTION__, self, native_ptr, value, _buffer); + linphone_content_set_buffer(native_ptr, _buffer, _size); + pylinphone_dispatch_messages(); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> 0", __FUNCTION__); + return 0; +} diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py new file mode 100644 index 000000000..16d726850 --- /dev/null +++ b/tools/python/apixml2python/linphone.py @@ -0,0 +1,1357 @@ +# Copyright (C) 2014 Belledonne Communications SARL +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import re +from sets import Set +import sys + + +def strip_leading_linphone(s): + if s.lower().startswith('linphone'): + return s[8:] + else: + return s + +def remove_useless_enum_prefix(senum, svalue): + lenum = re.findall('[A-Z][^A-Z]*', senum) + lvalue = re.findall('[A-Z][^A-Z]*', svalue) + if len(lenum) == 0 or len(lvalue) == 0: + return svalue + if lenum[0] == lvalue[0]: + i = 0 + while i < len(lenum) and lenum[i] == lvalue[i]: + i += 1 + return ''.join(lvalue[i:]) + return svalue + +def is_callback(s): + return s.startswith('Linphone') and s.endswith('Cb') + +def compute_event_name(s, className): + s = strip_leading_linphone(s) + s = s[len(className):-2] # Remove leading class name and tailing 'Cb' + event_name = '' + first = True + for l in s: + if l.isupper() and not first: + event_name += '_' + event_name += l.lower() + first = False + return event_name + + +class HandWrittenCode: + def __init__(self, _class, name, func_list, doc = ''): + self._class = _class + self.name = name + self.func_list = func_list + self.doc = doc + +class HandWrittenInstanceMethod(HandWrittenCode): + def __init__(self, _class, name, cfunction, doc = ''): + HandWrittenCode.__init__(self, _class, name, [cfunction], doc) + +class HandWrittenClassMethod(HandWrittenCode): + def __init__(self, _class, name, cfunction, doc = ''): + HandWrittenCode.__init__(self, _class, name, [cfunction], doc) + +class HandWrittenDeallocMethod(HandWrittenCode): + def __init__(self, _class, cfunction): + HandWrittenCode.__init__(self, _class, 'dealloc', [cfunction], '') + +class HandWrittenProperty(HandWrittenCode): + def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None, doc = ''): + func_list = [] + if getter_cfunction is not None: + func_list.append(getter_cfunction) + if setter_cfunction is not None: + func_list.append(setter_cfunction) + HandWrittenCode.__init__(self, _class, name, func_list, doc) + self.getter_cfunction = getter_cfunction + self.setter_cfunction = setter_cfunction + + +class ArgumentType: + def __init__(self, basic_type, complete_type, contained_type, linphone_module): + self.basic_type = basic_type + self.complete_type = complete_type + self.contained_type = contained_type + self.linphone_module = linphone_module + self.type_str = None + self.check_condition = None + self.convert_code = None + self.convert_from_func = None + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cnativefmt_str = '%p' + self.use_native_pointer = False + self.cast_convert_func_result = True + self.__compute() + if self.basic_type == 'MSList' and self.contained_type is not None: + self.linphone_module.mslist_types.add(self.contained_type) + + def __compute(self): + splitted_type = self.complete_type.split(' ') + if self.basic_type == 'char': + if '*' in splitted_type: + self.type_str = 'string' + self.check_condition = "!PyString_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyString_AsString({arg_name});\n" + self.fmt_str = 'z' + self.cfmt_str = '\\"%s\\"' + else: + self.type_str = 'int' + self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n" + self.fmt_str = 'b' + self.cfmt_str = '%08x' + elif self.basic_type == 'int': + if 'unsigned' in splitted_type: + self.type_str = 'unsigned int' + self.check_condition = "!PyInt_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n" + self.fmt_str = 'I' + self.cfmt_str = '%u' + else: + self.type_str = 'int' + self.check_condition = "!PyInt_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n" + self.fmt_str = 'i' + self.cfmt_str = '%d' + elif self.basic_type in ['int8_t', 'int16_t' 'int32_t']: + self.type_str = 'int' + self.check_condition = "!PyInt_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AS_LONG({arg_name});\n" + if self.basic_type == 'int8_t': + self.fmt_str = 'c' + elif self.basic_type == 'int16_t': + self.fmt_str = 'h' + elif self.basic_type == 'int32_t': + self.fmt_str = 'l' + self.cfmt_str = '%d' + elif self.basic_type in ['uint8_t', 'uint16_t', 'uint32_t']: + self.type_str = 'unsigned int' + self.check_condition = "!PyInt_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsUnsignedLongMask({arg_name});\n" + if self.basic_type == 'uint8_t': + self.fmt_str = 'b' + elif self.basic_type == 'uint16_t': + self.fmt_str = 'H' + elif self.basic_type == 'uint32_t': + self.fmt_str = 'k' + self.cfmt_str = '%u' + elif self.basic_type == 'int64_t': + self.type_str = '64bits int' + self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})" + self.convert_code = \ +"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(PY_LONG_LONG)PyInt_AsLong({arg_name}); + else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}PyLong_AsLongLong({arg_name}); +""" + self.fmt_str = 'L' + self.cfmt_str = '%ld' + elif self.basic_type == 'uint64_t': + self.type_str = '64bits unsigned int' + self.check_condition = "!PyLong_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyLong_AsUnsignedLongLong({arg_name});\n" + self.fmt_str = 'K' + self.cfmt_str = '%lu' + elif self.basic_type == 'size_t': + self.type_str = 'int' + self.check_condition = "!PyInt_Check({arg_name}) && !PyLong_Check({arg_name})" + self.convert_code = \ +"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyInt_AsSsize_t({arg_name}); + else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(size_t)PyLong_AsSsize_t({arg_name}); +""" + self.fmt_str = 'n' + self.cfmt_str = '%lu' + elif self.basic_type == 'float': + self.type_str = 'float' + self.check_condition = "!PyFloat_Check({arg_name})" + self.convert_code = \ +"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyInt_AsLong({arg_name}); + else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyLong_AsLong({arg_name}); + else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(float)PyFloat_AsDouble({arg_name}); +""" + self.fmt_str = 'f' + self.cfmt_str = '%f' + elif self.basic_type == 'double': + self.type_str = 'float' + self.check_condition = "!PyFloat_Check({arg_name})" + self.convert_code = \ +"""if (PyInt_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyInt_AsLong({arg_name}); + else if (PyLong_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyLong_AsLong({arg_name}); + else if (PyFloat_Check({arg_name})) {result_name}{result_suffix} = {cast}(double)PyFloat_AsDouble({arg_name}); +""" + self.fmt_str = 'd' + self.cfmt_str = '%f' + elif self.basic_type == 'bool_t': + self.type_str = 'bool' + self.check_condition = "!PyBool_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyObject_IsTrue({arg_name});\n" + self.convert_from_func = 'PyBool_FromLong' + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cnativefmt_str = '%u' + elif self.basic_type == 'time_t': + self.type_str = 'DateTime' + self.check_condition = "!PyDateTime_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyDateTime_As_time_t({arg_name});\n" + self.convert_from_func = 'PyDateTime_From_time_t' + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cnativefmt_str = '%ld' + elif self.basic_type == 'MSList': + self.type_str = 'list of linphone.' + self.contained_type + self.check_condition = "!PyList_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyList_AsMSListOf" + self.contained_type + "({arg_name});\n" + self.convert_from_func = 'PyList_FromMSListOf' + self.contained_type + self.fmt_str = 'O' + self.cfmt_str = '%p' + elif self.basic_type == 'MSVideoSize': + self.type_str = 'linphone.VideoSize' + self.check_condition = "!PyLinphoneVideoSize_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneVideoSize_AsMSVideoSize({arg_name});\n" + self.convert_from_func = 'PyLinphoneVideoSize_FromMSVideoSize' + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cast_convert_func_result = False + elif self.basic_type == 'LCSipTransports': + self.type_str = 'linphone.SipTransports' + self.check_condition = "!PyLinphoneSipTransports_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyLinphoneSipTransports_AsLCSipTransports({arg_name});\n" + self.convert_from_func = 'PyLinphoneSipTransports_FromLCSipTransports' + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cast_convert_func_result = False + else: + if strip_leading_linphone(self.basic_type) in self.linphone_module.enum_names: + self.type_str = 'int' + self.check_condition = "!PyInt_Check({arg_name})" + self.convert_code = "{result_name}{result_suffix} = {cast}PyInt_AsLong({arg_name});\n" + self.fmt_str = 'i' + self.cfmt_str = '%d' + elif is_callback(self.complete_type): + self.type_str = 'callable' + self.check_condition = "!PyCallable_Check({arg_name})" + self.cnativefmt_str = None + elif '*' in splitted_type: + self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type) + self.use_native_pointer = True + else: + self.type_str = 'linphone.' + strip_leading_linphone(self.basic_type) + + +class MethodDefinition: + def __init__(self, linphone_module, class_, method_node = None): + self.body = '' + self.arg_names = [] + self.parse_tuple_format = '' + self.build_value_format = '' + self.return_type = 'void' + self.return_complete_type = 'void' + self.return_contained_type = None + self.method_node = method_node + self.class_ = class_ + self.linphone_module = linphone_module + self.self_arg = None + self.xml_method_return = None + self.xml_method_args = [] + self.method_type = 'instancemethod' + + def format_local_variables_definition(self): + body = self.format_local_return_variables_definition() + if self.self_arg is not None: + body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n" + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + self.parse_tuple_format += argument_type.fmt_str + if is_callback(arg_complete_type): + body += "\tPyObject * {arg_name};\n".format(arg_name=arg_name) + elif argument_type.fmt_str == 'O' and argument_type.use_native_pointer: + body += "\tPyObject * " + arg_name + ";\n" + body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr = NULL;\n" + elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None: + body += "\tPyObject * " + arg_name + ";\n" + body += "\t" + arg_complete_type + " " + arg_name + "_native_obj;\n" + elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names: + body += "\tint " + arg_name + ";\n" + else: + body += "\t" + arg_complete_type + " " + arg_name + ";\n" + self.arg_names.append(arg_name) + return body + + def format_arguments_parsing(self): + class_native_ptr_check_code = '' + if self.self_arg is not None: + class_native_ptr_check_code = self.format_class_native_pointer_check(False) + parse_tuple_code = '' + if len(self.arg_names) > 0: + parse_tuple_code = \ +"""if (!PyArg_ParseTuple(args, "{fmt}", {args})) {{ + return NULL; + }} +""".format(fmt=self.parse_tuple_format, args=', '.join(map(lambda a: '&' + a, self.arg_names))) + args_conversion_code = '' + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O' and argument_type.convert_code is not None: + args_conversion_code += argument_type.convert_code.format(result_name=arg_name, result_suffix='_native_obj', cast='', arg_name=arg_name) + return \ +""" {class_native_ptr_check_code} + {parse_tuple_code} + {args_type_check_code} + {args_native_ptr_check_code} + {args_conversion_code} +""".format(class_native_ptr_check_code=class_native_ptr_check_code, + parse_tuple_code=parse_tuple_code, + args_type_check_code=self.format_args_type_check(), + args_native_ptr_check_code=self.format_args_native_pointer_check(), + args_conversion_code=args_conversion_code) + + def format_enter_trace(self): + fmt = '' + args = [] + if self.self_arg is not None: + fmt += "%p [%p]" + args += ["self", "native_ptr"] + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + if fmt != '': + fmt += ', ' + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + fmt += argument_type.cfmt_str + args.append(arg_name) + if argument_type.fmt_str == 'O' and argument_type.cnativefmt_str is not None: + fmt += ' [' + argument_type.cnativefmt_str + ']' + if argument_type.use_native_pointer: + args.append(arg_name + '_native_ptr') + else: + args.append(arg_name + '_native_obj') + args = ', '.join(args) + if args != '': + args = ', ' + args + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s({fmt})\", __FUNCTION__{args});\n".format(fmt=fmt, args=args) + + def format_c_function_call(self): + arg_names = [] + c_function_call_code = '' + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O' and argument_type.use_native_pointer: + arg_names.append(arg_name + "_native_ptr") + elif argument_type.fmt_str == 'O' and argument_type.convert_code is not None: + arg_names.append(arg_name + "_native_obj") + else: + arg_names.append(arg_name) + if is_callback(self.return_complete_type): + c_function_call_code = "pyresult = ((pylinphone_{class_name}Object *)self)->{callback_name};".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.return_complete_type, self.class_['class_name'])) + else: + if self.return_complete_type != 'void': + c_function_call_code += "cresult = " + c_function_call_code += self.method_node.get('name') + "(" + if self.self_arg is not None: + c_function_call_code += "native_ptr" + if len(arg_names) > 0: + c_function_call_code += ', ' + c_function_call_code += ', '.join(arg_names) + ");" + from_native_pointer_code = '' + convert_from_code = '' + build_value_code = '' + cfree_code = '' + result_variable = '' + if self.return_complete_type != 'void': + if self.build_value_format == 'O': + stripped_return_type = strip_leading_linphone(self.return_type) + return_type_class = self.find_class_definition(self.return_type) + if return_type_class is not None: + from_native_pointer_code = "pyresult = pylinphone_{return_type}_from_native_ptr(&pylinphone_{return_type}Type, cresult);\n".format(return_type=stripped_return_type) + else: + return_argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module) + if return_argument_type.convert_from_func is not None: + convert_from_code = \ +"""pyresult = {convert_func}(cresult); +""".format(convert_func=return_argument_type.convert_from_func) + result_variable = 'pyresult' + else: + result_variable = 'cresult' + if result_variable != '': + build_value_code = "pyret = Py_BuildValue(\"{fmt}\", {result_variable});".format(fmt=self.build_value_format, result_variable=result_variable) + if self.return_complete_type == 'char *': + cfree_code = 'ms_free(cresult);'; + body = \ +""" {c_function_call_code} + pylinphone_dispatch_messages(); + {from_native_pointer_code} + {convert_from_code} + {build_value_code} + {cfree_code} +""".format(c_function_call_code=c_function_call_code, + from_native_pointer_code=from_native_pointer_code, + convert_from_code=convert_from_code, + build_value_code=build_value_code, + cfree_code=cfree_code) + return body + + def format_return_trace(self): + if self.return_complete_type != 'void': + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, pyret);\n" + else: + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> None\", __FUNCTION__);\n" + + def format_return_result(self): + if self.return_complete_type != 'void': + return "\treturn pyret;" + return "\tPy_RETURN_NONE;" + + def format_return_none_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> None\", __FUNCTION__);\n" + + def format_class_native_pointer_check(self, return_int): + return_value = "NULL" + if return_int: + return_value = "-1" + return \ +"""native_ptr = pylinphone_{class_name}_get_native_ptr(self); + if (native_ptr == NULL) {{ + PyErr_SetString(PyExc_TypeError, "Invalid linphone.{class_name} instance"); + return {return_value}; + }} +""".format(class_name=self.class_['class_name'], return_value=return_value) + + def format_args_type_check(self): + body = '' + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O': + if argument_type.use_native_pointer: + body += \ +""" if (({arg_name} != Py_None) && !PyObject_IsInstance({arg_name}, (PyObject *)&pylinphone_{arg_type}Type)) {{ + PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance."); + return NULL; + }} +""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type), type_str=argument_type.type_str) + else: + body += \ +""" if ({check_condition}) {{ + PyErr_SetString(PyExc_TypeError, "The '{arg_name}' argument must be a {type_str} instance."); + return NULL; + }} +""".format(arg_name=arg_name, check_condition=argument_type.check_condition.format(arg_name=arg_name), type_str=argument_type.type_str) + if body != '': + body = body[1:] # Remove leading '\t' + return body + + def format_args_native_pointer_check(self): + body = '' + for xml_method_arg in self.xml_method_args: + arg_name = "_" + xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O' and argument_type.use_native_pointer: + body += \ +""" if (({arg_name} != NULL) && ({arg_name} != Py_None)) {{ + if (({arg_name}_native_ptr = pylinphone_{arg_type}_get_native_ptr({arg_name})) == NULL) {{ + return NULL; + }} + }} +""".format(arg_name=arg_name, arg_type=strip_leading_linphone(arg_type)) + if body != '': + body = body[1:] # Remove leading '\t' + return body + + def format_local_return_variables_definition(self): + body = '' + if self.xml_method_return is not None: + self.return_type = self.xml_method_return.get('type') + self.return_complete_type = self.xml_method_return.get('completetype') + self.return_contained_type = self.xml_method_return.get('containedtype') + if is_callback(self.return_complete_type): + body += "\tPyObject * pyresult;\n" + body += "\tPyObject * pyret;\n" + argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module) + self.build_value_format = argument_type.fmt_str + elif self.return_complete_type != 'void': + body += "\t" + self.return_complete_type + " cresult;\n" + argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module) + self.build_value_format = argument_type.fmt_str + if self.build_value_format == 'O': + body += "\tPyObject * pyresult;\n" + body += "\tPyObject * pyret;\n" + return body + + def parse_method_node(self): + if self.method_node is not None: + self.xml_method_return = self.method_node.find('./return') + self.xml_method_args = self.method_node.findall('./arguments/argument') + self.method_type = self.method_node.tag + if self.method_type != 'classmethod' and len(self.xml_method_args) > 0: + self.self_arg = self.xml_method_args[0] + self.xml_method_args = self.xml_method_args[1:] + + def remove_const_from_complete_type(self, complete_type): + splitted_type = complete_type.split(' ') + while 'const' in splitted_type: + splitted_type.remove('const') + return ' '.join(splitted_type) + + def find_class_definition(self, basic_type): + basic_type = strip_leading_linphone(basic_type) + for c in self.linphone_module.classes: + if c['class_name'] == basic_type: + return c + return None + + def format(self): + self.parse_method_node() + body = self.format_local_variables_definition() + body += self.format_arguments_parsing() + body += self.format_enter_trace() + body += self.format_c_function_call() + body += self.format_return_trace() + body += self.format_return_result() + return body + +class NewMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + + def format_local_variables_definition(self): + return "\tpylinphone_{class_name}Object *self = (pylinphone_{class_name}Object *)type->tp_alloc(type, 0);\n".format(class_name=self.class_['class_name']) + + def format_arguments_parsing(self): + return '' + + def format_enter_trace(self): + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s()\", __FUNCTION__);\n" + + def format_c_function_call(self): + return '' + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n" + + def format_return_result(self): + return "\treturn (PyObject *)self;" + +class InitMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + + def format_local_variables_definition(self): + return "\tpylinphone_{class_name}Object *self_obj = (pylinphone_{class_name}Object *)self;\n".format(class_name=self.class_['class_name']) + + def format_arguments_parsing(self): + return '' + + def format_enter_trace(self): + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s()\", __FUNCTION__);\n" + + def format_c_function_call(self): + specific_member_initialization_code = '' + for member in self.class_['class_object_members']: + specific_member_initialization_code += "\tself_obj->{member} = NULL;\n".format(member=member) + return \ +""" self_obj->native_ptr = NULL; + self_obj->user_data = NULL; +{specific_member_initialization_code} +""".format(specific_member_initialization_code=specific_member_initialization_code) + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n" + + def format_return_result(self): + return "\treturn 0;" + +class FromNativePointerMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_): + MethodDefinition.__init__(self, linphone_module, class_, None) + + def format_local_variables_definition(self): + return "\tpylinphone_{class_name}Object *self = NULL;\n".format(class_name=self.class_['class_name']) + + def format_arguments_parsing(self): + return '' + + def format_enter_trace(self): + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s(%p)\", __FUNCTION__, native_ptr);\n" + + def format_c_function_call(self): + get_user_data_func_call = '' + set_user_data_func_call = '' + if self.class_['class_has_user_data']: + get_user_data_func_call = "self = (pylinphone_{class_name}Object *){function_prefix}get_user_data(native_ptr);".format(class_name=self.class_['class_name'], function_prefix=self.class_['class_c_function_prefix']) + set_user_data_func_call = "{function_prefix}set_user_data(self->native_ptr, self);".format(function_prefix=self.class_['class_c_function_prefix']) + ref_native_pointer_code = '' + if self.class_['class_refcountable']: + ref_native_pointer_code = "{func}(self->native_ptr);".format(func=self.class_['class_c_function_prefix'] + "ref") + return \ +""" if (native_ptr == NULL) {{ + {none_trace} + Py_RETURN_NONE; + }} + {get_user_data_func_call} + if (self == NULL) {{ + self = (pylinphone_{class_name}Object *)PyObject_CallObject((PyObject *)&pylinphone_{class_name}Type, NULL); + if (self == NULL) {{ + {none_trace} + Py_RETURN_NONE; + }} + self->native_ptr = ({class_cname} *)native_ptr; + {set_user_data_func_call} + {ref_native_pointer_code} + }} +""".format(class_name=self.class_['class_name'], class_cname=self.class_['class_cname'], + none_trace=self.format_return_none_trace(), + get_user_data_func_call=get_user_data_func_call, set_user_data_func_call=set_user_data_func_call, + ref_native_pointer_code=ref_native_pointer_code) + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> %p\", __FUNCTION__, self);\n" + + def format_return_result(self): + return "\treturn (PyObject *)self;" + +class DeallocMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + + def format_local_variables_definition(self): + func = "pylinphone_{class_name}_get_native_ptr".format(class_name=self.class_['class_name']) + return \ +""" {arg_type} * native_ptr = {func}(self); +""".format(arg_type=self.class_['class_cname'], func=func) + + def format_arguments_parsing(self): + # Check that the dealloc is not called a second time because of reentrancy + return "\tif (Py_REFCNT(self) < 0) return;\n" + + def format_enter_trace(self): + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s(%p [%p])\", __FUNCTION__, self, native_ptr);\n" + + def format_c_function_call(self): + reset_user_data_code = '' + if self.class_['class_name'] != 'Core' and self.class_['class_has_user_data']: + reset_user_data_code += \ +"""if (native_ptr != NULL) {{ + {function_prefix}set_user_data(native_ptr, NULL); + }} +""".format(function_prefix=self.class_['class_c_function_prefix']) + native_ptr_dealloc_code = '' + specific_member_decref_code = '' + if self.class_['class_refcountable']: + native_ptr_dealloc_code += \ +""" if (native_ptr != NULL) {{ + {function_prefix}unref(native_ptr); + }} +""".format(function_prefix=self.class_['class_c_function_prefix']) + elif self.class_['class_destroyable']: + native_ptr_dealloc_code += \ +""" if (native_ptr != NULL) {{ + {function_prefix}destroy(native_ptr); + }} +""".format(function_prefix=self.class_['class_c_function_prefix']) + for member in self.class_['class_object_members']: + specific_member_decref_code += "\tPy_XDECREF(((pylinphone_{class_name}Object *)self)->{member});\n".format(class_name=self.class_['class_name'], member=member) + return \ +""" {reset_user_data_code} + {native_ptr_dealloc_code} + pylinphone_dispatch_messages(); + Py_XDECREF(((pylinphone_{class_name}Object *)self)->user_data); +{specific_member_decref_code} + self->ob_type->tp_free(self); +""".format(class_name=self.class_['class_name'], reset_user_data_code=reset_user_data_code, native_ptr_dealloc_code=native_ptr_dealloc_code, specific_member_decref_code=specific_member_decref_code) + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);" + + def format_return_result(self): + return '' + + def format(self): + return \ +"""static void pylinphone_{class_name}_dealloc(PyObject *self) {{ +{method_body} +}}""".format(class_name=self.class_['class_name'], method_body=MethodDefinition.format(self)) + +class GetterMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + +class SetterMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + + def format_arguments_parsing(self): + if self.first_argument_type.check_condition is None: + attribute_type_check_code = \ +"""if ((value != Py_None) && !PyObject_IsInstance(value, (PyObject *)&pylinphone_{class_name}Type)) {{ + PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a linphone.{class_name} instance."); + return -1; + }} +""".format(class_name=self.first_arg_class, attribute_name=self.attribute_name) + else: + checknotnone = '' + if self.first_argument_type.type_str == 'string': + checknotnone = "(value != Py_None) && " + attribute_type_check_code = \ +"""if ({checknotnone}{check_condition}) {{ + PyErr_SetString(PyExc_TypeError, "The '{attribute_name}' attribute value must be a {type_str}."); + return -1; + }} +""".format(checknotnone=checknotnone, check_condition=self.first_argument_type.check_condition.format(arg_name='value'), attribute_name=self.attribute_name, type_str=self.first_argument_type.type_str) + attribute_conversion_code = '' + callback_setting_code = '' + if is_callback(self.first_argument_type.complete_type): + callback_setting_code = \ +"""Py_XDECREF(((pylinphone_{class_name}Object *)self)->{callback_name}); + Py_INCREF(value); + ((pylinphone_{class_name}Object *)self)->{callback_name} = value; +""".format(class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_arg_complete_type, self.class_['class_name'])) + if (self.first_argument_type.convert_code is None) or \ + (self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None): + attribute_conversion_code += "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name) + if self.first_argument_type.convert_code is not None: + cast_code = '' + suffix = '' + if self.first_argument_type.cast_convert_func_result: + cast_code = "({arg_type})".format(arg_type=self.first_arg_complete_type) + if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None: + suffix = '_native_obj' + attribute_conversion_code += self.first_argument_type.convert_code.format(result_name="_" + self.first_arg_name, result_suffix=suffix, cast=cast_code, arg_name='value') + attribute_native_ptr_check_code = '' + if self.first_argument_type.use_native_pointer: + attribute_native_ptr_check_code = \ +"""if ({arg_name} != Py_None) {{ + if (({arg_name}_native_ptr = pylinphone_{arg_class}_get_native_ptr({arg_name})) == NULL) {{ + PyErr_SetString(PyExc_TypeError, "Invalid linphone.{arg_class} instance."); + return -1; + }} + }} +""".format(arg_name="_" + self.first_arg_name, arg_class=self.first_arg_class) + return \ +""" {native_ptr_check_code} + if (value == NULL) {{ + PyErr_SetString(PyExc_TypeError, "Cannot delete the '{attribute_name}' attribute."); + return -1; + }} + {attribute_type_check_code} + {attribute_conversion_code} + {callback_setting_code} + {attribute_native_ptr_check_code} +""".format(attribute_name=self.attribute_name, + native_ptr_check_code=self.format_class_native_pointer_check(True), + attribute_type_check_code=attribute_type_check_code, + attribute_conversion_code=attribute_conversion_code, + callback_setting_code=callback_setting_code, + attribute_native_ptr_check_code=attribute_native_ptr_check_code) + + def format_c_function_call(self): + if is_callback(self.first_argument_type.complete_type): + return \ +""" {method_name}(native_ptr, pylinphone_{class_name}_callback_{callback_name}); + pylinphone_dispatch_messages(); +""".format(method_name=self.method_node.get('name'), class_name=self.class_['class_name'], callback_name=compute_event_name(self.first_argument_type.complete_type, self.class_['class_name'])) + suffix = '' + if self.first_argument_type.fmt_str == 'O' and self.first_argument_type.use_native_pointer: + suffix = '_native_ptr' + elif self.first_argument_type.fmt_str == 'O' and self.first_argument_type.convert_code is not None: + suffix = '_native_obj' + return \ +""" {method_name}(native_ptr, {arg_name}{suffix}); + pylinphone_dispatch_messages(); +""".format(arg_name="_" + self.first_arg_name, method_name=self.method_node.get('name'), suffix=suffix) + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s -> 0\", __FUNCTION__);\n" + + def format_return_result(self): + return "\treturn 0;" + + def parse_method_node(self): + MethodDefinition.parse_method_node(self) + # Force return value type of setter function to prevent declaring useless local variables + # TODO: Investigate. Maybe we should decide that setters must always return an int value. + self.xml_method_return = None + self.attribute_name = self.method_node.get('property_name') + self.first_arg_type = self.xml_method_args[0].get('type') + self.first_arg_complete_type = self.xml_method_args[0].get('completetype') + self.first_arg_contained_type = self.xml_method_args[0].get('containedtype') + self.first_arg_name = self.xml_method_args[0].get('name') + self.first_argument_type = ArgumentType(self.first_arg_type, self.first_arg_complete_type, self.first_arg_contained_type, self.linphone_module) + self.first_arg_class = strip_leading_linphone(self.first_arg_type) + +class EventCallbackMethodDefinition(MethodDefinition): + def __init__(self, linphone_module, class_, method_node = None): + MethodDefinition.__init__(self, linphone_module, class_, method_node) + + def format_local_variables_definition(self): + class_name = self.class_['event_class'] + nocallbacks_class_name = class_name + if class_name.endswith('Cbs'): + nocallbacks_class_name = class_name[:-3] + returnvars = self.format_local_return_variables_definition() + common = \ +""" pylinphone_{class_name}Object *pyself = (pylinphone_{class_name}Object *){function_prefix}get_user_data(self); + PyObject *func; + PyObject *args; + PyGILState_STATE pygil_state;""".format(class_name=nocallbacks_class_name, function_prefix=self.find_class_definition(nocallbacks_class_name)['class_c_function_prefix']) + if class_name.endswith('Cbs'): + common += """ + pylinphone_{class_name}Object *pycbs = (pylinphone_{class_name}Object *){cbs_function_prefix}get_user_data({function_prefix}get_callbacks(self)); +""".format(class_name=class_name, cbs_function_prefix=self.find_class_definition(class_name)['class_c_function_prefix'], function_prefix=self.find_class_definition(nocallbacks_class_name)['class_c_function_prefix']) + specific = '' + for xml_method_arg in self.xml_method_args: + arg_name = xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O': + specific += "\tPyObject * py" + arg_name + " = NULL;\n" + return "{returnvars}\n{common}\n{specific}".format(returnvars=returnvars, common=common, specific=specific) + + def format_arguments_parsing(self): + return_str = '' + if self.return_complete_type != 'void': + argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O': + return_str = 'NULL' + if self.class_['event_class'] == 'Core': + return \ +""" if (Py_REFCNT(pyself) <= 0) return {return_str}; + func = PyDict_GetItemString(pyself->vtable_dict, "{name}"); + pygil_state = PyGILState_Ensure(); +""".format(name=self.class_['event_name'], return_str=return_str) + else: + return \ +""" if (Py_REFCNT(pyself) <= 0) return {return_str}; + func = pycbs->{event_name}; + pygil_state = PyGILState_Ensure(); +""".format(event_name=self.class_['event_name'], return_str=return_str) + + def format_enter_trace(self): + fmt = '%p' + args = ['self'] + for xml_method_arg in self.xml_method_args: + arg_name = xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + if fmt != '': + fmt += ', ' + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + fmt += argument_type.cfmt_str + args.append(arg_name) + args=', '.join(args) + if args != '': + args = ', ' + args + return "\tpylinphone_trace(1, \"[PYLINPHONE] >>> %s({fmt})\", __FUNCTION__{args});\n".format(fmt=fmt, args=args) + + def format_c_function_call(self): + create_python_objects_code = '' + convert_python_result_code = '' + fmt = 'O' + args = ['pyself'] + for xml_method_arg in self.xml_method_args: + arg_name = xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module) + fmt += argument_type.fmt_str + if argument_type.fmt_str == 'O': + args.append('py' + arg_name) + else: + args.append(arg_name) + if argument_type.fmt_str == 'O': + if argument_type.type_str == "bool": + create_python_objects_code += "\t\tpy{name} = {convert_from_func}({name});\n".format(name=arg_name, convert_from_func=argument_type.convert_from_func) + else: + type_class = self.find_class_definition(arg_type) + create_python_objects_code += "\t\tpy{name} = pylinphone_{arg_type}_from_native_ptr(&pylinphone_{arg_type}Type, {name});\n".format(name=arg_name, arg_type=strip_leading_linphone(arg_type)) + args=', '.join(args) + if self.return_complete_type != 'void': + argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module) + if argument_type.fmt_str == 'O': + convert_python_result_code = \ +""" if ((pyresult != Py_None) && !PyObject_IsInstance(pyresult, (PyObject *)&pylinphone_{class_name}Type)) {{ + PyErr_SetString(PyExc_TypeError, "The return value must be a linphone.{class_name} instance."); + return NULL; + }} + if ((cresult = pylinphone_{class_name}_get_native_ptr(pyresult)) == NULL) {{ + return NULL; + }} +""".format(class_name=strip_leading_linphone(self.return_type)) + + else: + convert_python_result_code = '\t\t' + argument_type.convert_code.format(result_name='cresult', result_suffix='', cast='', arg_name='pyresult') + return \ +""" if ((func != NULL) && PyCallable_Check(func)) {{ +{create_python_objects_code} + args = Py_BuildValue("{fmt}", {args}); + pyresult = PyEval_CallObject(func, args); + if (pyresult == NULL) {{ + PyErr_Print(); + }} + Py_DECREF(args); +{convert_python_result_code} + }} +""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code, convert_python_result_code=convert_python_result_code) + + def format_return_trace(self): + return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);\n" + + def format_return_result(self): + s = '\tPyGILState_Release(pygil_state);' + if self.return_complete_type != 'void': + s += '\n\treturn cresult;' + return s + + def format_local_return_variables_definition(self): + body = "\tPyObject * pyresult;" + if self.xml_method_return is not None: + self.return_type = self.xml_method_return.get('type') + self.return_complete_type = self.xml_method_return.get('completetype') + self.return_contained_type = self.xml_method_return.get('containedtype') + if self.return_complete_type != 'void': + body += "\n\t" + self.return_complete_type + " cresult;" + return body + + def format(self): + body = MethodDefinition.format(self) + class_name = self.class_['event_class'] + nocallbacks_class_name = class_name + if class_name.endswith('Cbs'): + nocallbacks_class_name = class_name[:-3] + arguments = ['Linphone' + nocallbacks_class_name + ' * self'] + for xml_method_arg in self.xml_method_args: + arg_name = xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arguments.append(arg_complete_type + ' ' + arg_name) + definition = \ +"""static {returntype} pylinphone_{class_name}_callback_{event_name}({arguments}) {{ +{body} +}} +""".format(returntype=self.return_complete_type, class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body) + return definition + + +class LinphoneModule(object): + def __init__(self, tree, blacklisted_classes, blacklisted_events, blacklisted_functions, hand_written_codes): + self.internal_instance_method_names = ['destroy', 'ref', 'unref'] + self.internal_property_names = ['user_data'] + self.mslist_types = Set([]) + self.enums = [] + self.enum_names = [] + self.cfunction2methodmap = {} + hand_written_functions = [] + for hand_written_code in hand_written_codes: + hand_written_functions += hand_written_code.func_list + xml_enums = tree.findall("./enums/enum") + for xml_enum in xml_enums: + if xml_enum.get('deprecated') == 'true': + continue + e = {} + e['enum_name'] = strip_leading_linphone(xml_enum.get('name')) + e['enum_doc'] = self.__format_doc_content(xml_enum.find('briefdescription'), xml_enum.find('detaileddescription')) + e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc']) + e['enum_doc'] += """ + +.. csv-table:: + :delim: | + :widths: 30, 70 + :header: Value,Description + +""" + e['enum_values'] = [] + e['enum_deprecated_values'] = [] + xml_enum_values = xml_enum.findall("./values/value") + for xml_enum_value in xml_enum_values: + if xml_enum_value.get('deprecated') == 'true': + continue + v = {} + v['enum_value_cname'] = xml_enum_value.get('name') + valname = strip_leading_linphone(v['enum_value_cname']) + v['enum_value_name'] = remove_useless_enum_prefix(e['enum_name'], valname) + v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription')) + e['enum_doc'] += ' ' + v['enum_value_name'] + '|' + v['enum_value_doc'] + '\n' + e['enum_values'].append(v) + if v['enum_value_name'] != valname: + # TODO: To remove. Add deprecated value name. + v = {} + v['enum_value_cname'] = xml_enum_value.get('name') + v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname']) + v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription')) + e['enum_deprecated_values'].append(v) + e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc']) + self.enums.append(e) + self.enum_names.append(e['enum_name']) + self.core_events = [] + self.classes = [] + xml_classes = tree.findall("./classes/class") + for xml_class in xml_classes: + if xml_class.get('deprecated') == 'true': + continue + if xml_class.get('name') in blacklisted_classes: + continue + c = {} + c['class_xml_node'] = xml_class + c['class_cname'] = xml_class.get('name') + c['class_name'] = strip_leading_linphone(c['class_cname']) + c['class_c_function_prefix'] = xml_class.get('cfunctionprefix') + c['class_doc'] = self.__format_doc(xml_class.find('briefdescription'), xml_class.find('detaileddescription')) + c['class_refcountable'] = (xml_class.get('refcountable') == 'true') + c['class_destroyable'] = (xml_class.get('destroyable') == 'true') + c['class_has_user_data'] = False + c['class_type_methods'] = [] + c['class_type_hand_written_methods'] = [] + c['class_instance_hand_written_methods'] = [] + c['class_hand_written_properties'] = [] + c['class_object_members'] = [] + c['class_object_members_code'] = '' + c['class_events'] = [] + if c['class_name'] == 'Core': + c['class_object_members'].append("vtable_dict") + c['class_object_members_code'] = "\tPyObject *vtable_dict;" + xml_events = xml_class.findall("./events/event") + for xml_event in xml_events: + if xml_event.get('deprecated') == 'true': + continue + if xml_event.get('name') in blacklisted_events: + continue + ev = {} + ev['event_class'] = c['class_name'] + ev['event_xml_node'] = xml_event + ev['event_cname'] = xml_event.get('name') + ev['event_name'] = compute_event_name(ev['event_cname'], c['class_name']) + ev['event_doc'] = self.__format_doc(xml_event.find('briefdescription'), xml_event.find('detaileddescription')) + if c['class_name'] == 'Core': + self.core_events.append(ev) + else: + c['class_events'].append(ev) + c['class_object_members'].append(ev['event_name']) + c['class_object_members_code'] += "\tPyObject *" + ev['event_name'] + ";\n" + for hand_written_code in hand_written_codes: + if hand_written_code._class == c['class_name']: + if isinstance(hand_written_code, HandWrittenClassMethod): + m = {} + m['method_name'] = hand_written_code.name + m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) + c['class_type_hand_written_methods'].append(m) + elif isinstance(hand_written_code, HandWrittenInstanceMethod): + m = {} + m['method_name'] = hand_written_code.name + m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) + c['class_instance_hand_written_methods'].append(m) + elif isinstance(hand_written_code, HandWrittenDeallocMethod): + c['class_has_hand_written_dealloc'] = True + elif isinstance(hand_written_code, HandWrittenProperty): + p = {} + p['property_name'] = hand_written_code.name + if hand_written_code.getter_cfunction is None: + p['getter_reference'] = 'NULL' + else: + p['getter_reference'] = '(getter)pylinphone_' + c['class_name'] + '_get_' + p['property_name'] + if hand_written_code.setter_cfunction is None: + p['setter_reference'] = 'NULL' + else: + p['setter_reference'] = '(setter)pylinphone_' + c['class_name'] + '_set_' + p['property_name'] + p['property_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) + c['class_hand_written_properties'].append(p) + xml_type_methods = xml_class.findall("./classmethods/classmethod") + for xml_type_method in xml_type_methods: + if xml_type_method.get('deprecated') == 'true': + continue + method_name = xml_type_method.get('name') + if method_name in blacklisted_functions: + continue + m = {} + m['method_name'] = method_name.replace(c['class_c_function_prefix'], '') + if method_name not in hand_written_functions: + m['method_xml_node'] = xml_type_method + self.cfunction2methodmap[method_name] = ':py:meth:`linphone.' + c['class_name'] + '.' + m['method_name'] + '`' + c['class_type_methods'].append(m) + c['class_instance_methods'] = [] + xml_instance_methods = xml_class.findall("./instancemethods/instancemethod") + for xml_instance_method in xml_instance_methods: + if xml_instance_method.get('deprecated') == 'true': + continue + method_name = xml_instance_method.get('name') + if method_name in blacklisted_functions: + continue + if method_name.replace(c['class_c_function_prefix'], '') in self.internal_instance_method_names: + continue + m = {} + m['method_name'] = method_name.replace(c['class_c_function_prefix'], '') + if method_name not in hand_written_functions: + m['method_xml_node'] = xml_instance_method + self.cfunction2methodmap[method_name] = ':py:meth:`linphone.' + c['class_name'] + '.' + m['method_name'] + '`' + c['class_instance_methods'].append(m) + c['class_properties'] = [] + xml_properties = xml_class.findall("./properties/property") + for xml_property in xml_properties: + property_name = xml_property.get('name') + if property_name == 'user_data': + c['class_has_user_data'] = True + if property_name in self.internal_property_names: + continue + p = {} + p['property_name'] = property_name + xml_property_getter = xml_property.find("./getter") + xml_property_setter = xml_property.find("./setter") + if xml_property_getter is not None: + if xml_property_getter.get('name') in blacklisted_functions or xml_property_getter.get('name') in hand_written_functions or xml_property_getter.get('deprecated') == 'true': + continue + if xml_property_setter is not None: + if xml_property_setter.get('name') in blacklisted_functions or xml_property_setter.get('name') in hand_written_functions or xml_property_setter.get('deprecated') == 'true': + continue + if xml_property_getter is not None: + xml_property_getter.set('property_name', property_name) + p['getter_name'] = xml_property_getter.get('name').replace(c['class_c_function_prefix'], '') + p['getter_xml_node'] = xml_property_getter + p['getter_reference'] = "(getter)pylinphone_" + c['class_name'] + "_" + p['getter_name'] + p['getter_definition_begin'] = "static PyObject * pylinphone_" + c['class_name'] + "_" + p['getter_name'] + "(PyObject *self, void *closure) {" + p['getter_definition_end'] = "}" + self.cfunction2methodmap[xml_property_getter.get('name')] = ':py:attr:`linphone.' + c['class_name'] + '.' + property_name + '`' + else: + p['getter_reference'] = "NULL" + if xml_property_setter is not None: + xml_property_setter.set('property_name', property_name) + p['setter_name'] = xml_property_setter.get('name').replace(c['class_c_function_prefix'], '') + p['setter_xml_node'] = xml_property_setter + p['setter_reference'] = "(setter)pylinphone_" + c['class_name'] + "_" + p['setter_name'] + p['setter_definition_begin'] = "static int pylinphone_" + c['class_name'] + "_" + p['setter_name'] + "(PyObject *self, PyObject *value, void *closure) {" + p['setter_definition_end'] = "}" + self.cfunction2methodmap[xml_property_setter.get('name')] = ':py:attr:`linphone.' + c['class_name'] + '.' + property_name + '`' + else: + p['setter_reference'] = "NULL" + c['class_properties'].append(p) + self.classes.append(c) + # Format events definitions + for ev in self.core_events: + ev['event_callback_definition'] = EventCallbackMethodDefinition(self, ev, ev['event_xml_node']).format() + ev['event_vtable_reference'] = "_vtable.{name} = pylinphone_Core_callback_{name};".format(name=ev['event_name']) + for c in self.classes: + for ev in c['class_events']: + ev['event_callback_definition'] = EventCallbackMethodDefinition(self, ev, ev['event_xml_node']).format() + # Format methods' bodies + for c in self.classes: + xml_new_method = c['class_xml_node'].find("./classmethods/classmethod[@name='" + c['class_c_function_prefix'] + "new']") + try: + c['new_body'] = NewMethodDefinition(self, c, xml_new_method).format() + except Exception, e: + e.args += (c['class_name'], 'new_body') + raise + try: + c['init_body'] = InitMethodDefinition(self, c, xml_new_method).format() + except Exception, e: + e.args += (c['class_name'], 'init_body') + raise + try: + c['from_native_pointer_body'] = FromNativePointerMethodDefinition(self, c).format() + except Exception, e: + e.args += (c['class_name'], 'from_native_pointer_body') + raise + try: + for m in c['class_type_methods']: + m['method_body'] = MethodDefinition(self, c, m['method_xml_node']).format() + m['method_doc'] = self.__format_method_doc(m['method_xml_node']) + for m in c['class_instance_methods']: + m['method_body'] = MethodDefinition(self, c, m['method_xml_node']).format() + m['method_doc'] = self.__format_method_doc(m['method_xml_node']) + except Exception, e: + e.args += (c['class_name'], m['method_name']) + raise + try: + for p in c['class_properties']: + p['property_doc'] = '' + if p.has_key('setter_xml_node'): + p['setter_body'] = SetterMethodDefinition(self, c, p['setter_xml_node']).format() + p['property_doc'] = self.__format_setter_doc(p['setter_xml_node']) + if p.has_key('getter_xml_node'): + p['getter_body'] = GetterMethodDefinition(self, c, p['getter_xml_node']).format() + if p['property_doc'] == '': + p['property_doc'] = self.__format_getter_doc(p['getter_xml_node']) + except Exception, e: + e.args += (c['class_name'], p['property_name']) + raise + if not 'class_has_hand_written_dealloc' in c: + try: + if c['class_refcountable']: + xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "unref']") + c['dealloc_definition'] = DeallocMethodDefinition(self, c, xml_instance_method).format() + elif c['class_destroyable']: + xml_instance_method = c['class_xml_node'].find("./instancemethods/instancemethod[@name='" + c['class_c_function_prefix'] + "destroy']") + c['dealloc_definition'] = DeallocMethodDefinition(self, c, xml_instance_method).format() + else: + c['dealloc_definition'] = DeallocMethodDefinition(self, c).format() + except Exception, e: + e.args += (c['class_name'], 'dealloc_body') + raise + # Convert mslist_types to a list of dictionaries for the template + d = [] + for mslist_type in self.mslist_types: + t = {} + t['c_contained_type'] = mslist_type + t['python_contained_type'] = strip_leading_linphone(mslist_type) + d.append(t) + self.mslist_types = d + + def __format_doc_node(self, node): + desc = '' + if node.tag == 'para': + if node.text is not None: + desc += node.text.strip() + for n in list(node): + desc += self.__format_doc_node(n) + elif node.tag == 'note': + if node.text is not None: + desc += node.text.strip() + for n in list(node): + desc += self.__format_doc_node(n) + elif node.tag == 'ref': + if node.text is not None: + desc += ' ' + node.text.strip() + ' ' + tail = node.tail.strip() + if tail != '': + if node.tag != 'ref': + desc += '\n' + desc += tail + if node.tag == 'para': + desc += '\n' + return desc + + def __format_doc_content(self, brief_description, detailed_description): + doc = '' + if brief_description is None: + brief_description = '' + if detailed_description is None: + detailed_description = '' + else: + desc = '' + for node in list(detailed_description): + desc += self.__format_doc_node(node) + '\n' + detailed_description = desc.strip() + brief_description = brief_description.strip() + doc += brief_description + if detailed_description != '': + if doc != '': + doc += '\n\n' + doc += detailed_description + return doc + + def __replace_doc_special_chars(self, doc): + return doc.replace('"', '').encode('string-escape') + + def __replace_doc_cfunction_by_method(self, doc): + for cfunction, method in self.cfunction2methodmap.iteritems(): + doc = doc.replace(cfunction + '()', method) + for cfunction, method in self.cfunction2methodmap.iteritems(): + doc = doc.replace(cfunction, method) + return doc + + def __replace_doc_keywords(self, doc): + return doc.replace('NULL', 'None') + + def __format_doc(self, brief_description, detailed_description): + doc = self.__format_doc_content(brief_description, detailed_description) + doc = self.__replace_doc_cfunction_by_method(doc) + doc = self.__replace_doc_keywords(doc) + doc = self.__replace_doc_special_chars(doc) + return doc + + def __format_method_doc(self, xml_node): + doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription')) + xml_method_return = xml_node.find('./return') + xml_method_args = xml_node.findall('./arguments/argument') + method_type = xml_node.tag + if method_type != 'classmethod' and len(xml_method_args) > 0: + xml_method_args = xml_method_args[1:] + doc += '\n' + if len(xml_method_args) > 0: + for xml_method_arg in xml_method_args: + arg_name = xml_method_arg.get('name') + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self) + arg_doc = self.__format_doc_content(None, xml_method_arg.find('description')) + doc += '\n:param ' + arg_name + ':' + if arg_doc != '': + doc += ' ' + arg_doc + doc += '\n:type ' + arg_name + ': ' + argument_type.type_str + if xml_method_return is not None: + return_type = xml_method_return.get('type') + return_complete_type = xml_method_return.get('completetype') + return_contained_type = xml_method_return.get('containedtype') + if return_complete_type != 'void': + return_doc = self.__format_doc_content(None, xml_method_return.find('description')) + return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self) + doc += '\n:returns: ' + return_doc + doc += '\n:rtype: ' + return_argument_type.type_str + doc = self.__replace_doc_cfunction_by_method(doc) + doc = self.__replace_doc_keywords(doc) + doc = self.__replace_doc_special_chars(doc) + return doc + + def __format_setter_doc(self, xml_node): + xml_method_arg = xml_node.findall('./arguments/argument')[1] + arg_type = xml_method_arg.get('type') + arg_complete_type = xml_method_arg.get('completetype') + arg_contained_type = xml_method_arg.get('containedtype') + argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self) + doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription')) + doc = '[' + argument_type.type_str + '] ' + doc + doc = self.__replace_doc_cfunction_by_method(doc) + doc = self.__replace_doc_keywords(doc) + doc = self.__replace_doc_special_chars(doc) + return doc + + def __format_getter_doc(self, xml_node): + xml_method_return = xml_node.find('./return') + return_type = xml_method_return.get('type') + return_complete_type = xml_method_return.get('completetype') + return_contained_type = xml_method_return.get('containedtype') + return_argument_type = ArgumentType(return_type, return_complete_type, return_contained_type, self) + doc = self.__format_doc_content(xml_node.find('briefdescription'), xml_node.find('detaileddescription')) + doc = '[' + return_argument_type.type_str + '] ' + doc + doc = self.__replace_doc_cfunction_by_method(doc) + doc = self.__replace_doc_keywords(doc) + doc = self.__replace_doc_special_chars(doc) + return doc diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache new file mode 100644 index 000000000..403a2491a --- /dev/null +++ b/tools/python/apixml2python/linphone_module.mustache @@ -0,0 +1,342 @@ +/* +Copyright (C) 2014 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "gitversion.h" + +#ifdef WIN32 +#include +#endif + +#ifdef _MSC_VER +#define PYLINPHONE_INLINE __inline +#else +#define PYLINPHONE_INLINE inline +#endif + + +static void pylinphone_dispatch_messages(void); +static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...); + + +{{> handwritten_declarations}} + + + +{{#classes}} +static PyTypeObject pylinphone_{{class_name}}Type; +{{/classes}} + +{{#classes}} + +typedef struct { + PyObject_HEAD + PyObject *user_data; + {{class_cname}} *native_ptr; +{{{class_object_members_code}}} +} pylinphone_{{class_name}}Object; + +{{/classes}} + +{{#classes}} +static {{class_cname}} * pylinphone_{{class_name}}_get_native_ptr(PyObject *self); +static PyObject * pylinphone_{{class_name}}_from_native_ptr(PyTypeObject *type, const {{class_cname}} *native_ptr); +{{#class_type_hand_written_methods}} +static PyObject * pylinphone_{{class_name}}_class_method_{{method_name}}(PyObject *cls, PyObject *args); +{{/class_type_hand_written_methods}} +{{#class_instance_hand_written_methods}} +static PyObject * pylinphone_{{class_name}}_instance_method_{{method_name}}(PyObject *self, PyObject *args); +{{/class_instance_hand_written_methods}} +{{/classes}} + +{{#mslist_types}} +PyObject * PyList_FromMSListOf{{c_contained_type}}(const MSList *msl) { + PyObject *pyl = PyList_New(0); + while (msl != NULL) { + {{c_contained_type}} *native_ptr = ({{c_contained_type}} *)msl->data; + PyObject *item = pylinphone_{{python_contained_type}}_from_native_ptr(&pylinphone_{{python_contained_type}}Type, native_ptr); + PyList_Append(pyl, item); + msl = ms_list_next(msl); + } + return pyl; +} + +MSList * PyList_AsMSListOf{{c_contained_type}}(PyObject *pyl) { + MSList *msl = NULL; + Py_ssize_t idx; + Py_ssize_t size = PyList_Size(pyl); + for (idx = 0; idx < size; idx++) { + PyObject *item = PyList_GetItem(pyl, idx); + {{c_contained_type}} *native_ptr = pylinphone_{{python_contained_type}}_get_native_ptr(item); + msl = ms_list_append(msl, native_ptr); + } + return msl; +} + +{{/mslist_types}} + +{{#core_events}} +{{{event_callback_definition}}} +{{/core_events}} + +{{#classes}} +{{#class_events}} +{{{event_callback_definition}}} +{{/class_events}} +{{/classes}} + +{{#classes}} + +static {{class_cname}} * pylinphone_{{class_name}}_get_native_ptr(PyObject *self) { + return ((pylinphone_{{class_name}}Object *)self)->native_ptr; +} + +static PyObject * pylinphone_{{class_name}}_from_native_ptr(PyTypeObject *type, const {{class_cname}} *native_ptr) { +{{{from_native_pointer_body}}} +} + +static PyObject * pylinphone_{{class_name}}_new(PyTypeObject *type, PyObject *args, PyObject *kw) { +{{{new_body}}} +} + +static int pylinphone_{{class_name}}_init(PyObject *self, PyObject *args, PyObject *kw) { +{{{init_body}}} +} + +{{{dealloc_definition}}} + +{{#class_type_methods}} + +static PyObject * pylinphone_{{class_name}}_class_method_{{method_name}}(PyObject *cls, PyObject *args) { +{{{method_body}}} +} + +{{/class_type_methods}} + +{{#class_instance_methods}} + +static PyObject * pylinphone_{{class_name}}_instance_method_{{method_name}}(PyObject *self, PyObject *args) { +{{{method_body}}} +} + +{{/class_instance_methods}} + +static PyMethodDef pylinphone_{{class_name}}_methods[] = { + /* Class methods */ +{{#class_type_hand_written_methods}} + { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" }, +{{/class_type_hand_written_methods}} +{{#class_type_methods}} + { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" }, +{{/class_type_methods}} + /* Instance methods */ +{{#class_instance_hand_written_methods}} + { "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" }, +{{/class_instance_hand_written_methods}} +{{#class_instance_methods}} + { "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" }, +{{/class_instance_methods}} + /* Sentinel */ + { NULL, NULL, 0, NULL } +}; + +static PyMemberDef pylinphone_{{class_name}}_members[] = { + { "user_data", T_OBJECT, offsetof(pylinphone_{{class_name}}Object, user_data), 0, "A place to store some user data." }, + { NULL, 0, 0, 0, NULL } /* Sentinel */ +}; + +{{#class_properties}} + +{{{getter_definition_begin}}} +{{{getter_body}}} +{{{getter_definition_end}}} + +{{{setter_definition_begin}}} +{{{setter_body}}} +{{{setter_definition_end}}} + +{{/class_properties}} + +static PyGetSetDef pylinphone_{{class_name}}_getseters[] = { +{{#class_hand_written_properties}} + { "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" }, +{{/class_hand_written_properties}} +{{#class_properties}} + { "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" }, +{{/class_properties}} + /* Sentinel */ + { NULL, NULL, NULL, NULL, NULL } +}; + +static PyTypeObject pylinphone_{{class_name}}Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "linphone.{{class_name}}", /* tp_name */ + sizeof(pylinphone_{{class_name}}Object), /* tp_basicsize */ + 0, /* tp_itemsize */ + pylinphone_{{class_name}}_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "{{{class_doc}}}", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pylinphone_{{class_name}}_methods, /* tp_methods */ + pylinphone_{{class_name}}_members, /* tp_members */ + pylinphone_{{class_name}}_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pylinphone_{{class_name}}_init, /* tp_init */ + 0, /* tp_alloc */ + pylinphone_{{class_name}}_new, /* tp_new */ + 0, /* tp_free */ +}; + +{{/classes}} + + +{{> handwritten_definitions}} + + +static PyMethodDef pylinphone_ModuleMethods[] = { + { "set_log_handler", pylinphone_module_method_set_log_handler, METH_VARARGS, "" }, + /* Sentinel */ + { NULL, NULL, 0, NULL } +}; + +{{#enums}} +static PyObject * pylinphone_{{enum_name}}_module_method_string(PyObject *self, PyObject *args) { + const char *value_str = "[invalid]"; + int value; + PyObject *pyret; + if (!PyArg_ParseTuple(args, "i", &value)) { + return NULL; + } + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%d)", __FUNCTION__, value); + switch (value) { +{{#enum_values}} + case {{enum_value_cname}}: + value_str = "{{enum_value_name}}"; + break; +{{/enum_values}} + default: + break; + } + pyret = Py_BuildValue("z", value_str); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static PyMethodDef pylinphone_{{enum_name}}_ModuleMethods[] = { + { "string", pylinphone_{{enum_name}}_module_method_string, METH_VARARGS, "Get a string representation of a linphone.{{enum_name}} value." }, + /* Sentinel */ + { NULL, NULL, 0, NULL } +}; + +{{/enums}} + +{{> linphone_testing_module}} + +PyMODINIT_FUNC initlinphone(void) { + PyObject *m; + PyObject *menum; + + PyDateTime_IMPORT; + PyEval_InitThreads(); + pylinphone_init_logging(); + +{{#classes}} + if (PyType_Ready(&pylinphone_{{class_name}}Type) < 0) return; +{{/classes}} + + /* Hand-written classes. */ + if (PyType_Ready(&pylinphone_VideoSizeType) < 0) return; + if (PyType_Ready(&pylinphone_SipTransportsType) < 0) return; + + m = Py_InitModule3("linphone", pylinphone_ModuleMethods, "Python module giving access to the Linphone library."); + if (m == NULL) return; + if (PyModule_AddStringConstant(m, "__version__", LINPHONE_GIT_REVISION) < 0) return; + +{{#enums}} + menum = Py_InitModule3("{{enum_name}}", pylinphone_{{enum_name}}_ModuleMethods, "{{{enum_doc}}}"); + if (menum == NULL) return; + Py_INCREF(menum); + if (PyModule_AddObject(m, "{{enum_name}}", menum) < 0) return; +{{#enum_values}} + if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return; +{{/enum_values}} +{{#enum_deprecated_values}} + if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return; +{{/enum_deprecated_values}} +{{/enums}} + + menum = Py_InitModule3("PayloadTypeType", pylinphone_PayloadTypeType_ModuleMethods, "Type of :py:class:`linphone.PayloadType`.\n\n.. csv-table::\n :delim: |\n :header: Value,Description\n\n AudioContinuous|\n AudioPacketized|\n Video|\n Text|\n Other|\n"); + if (menum == NULL) return; + Py_INCREF(menum); + if (PyModule_AddObject(m, "PayloadTypeType", menum) < 0) return; + if (PyModule_AddIntConstant(menum, "AudioContinuous", PAYLOAD_AUDIO_CONTINUOUS) < 0) return; + if (PyModule_AddIntConstant(menum, "AudioPacketized", PAYLOAD_AUDIO_PACKETIZED) < 0) return; + if (PyModule_AddIntConstant(menum, "Video", PAYLOAD_VIDEO) < 0) return; + if (PyModule_AddIntConstant(menum, "Text", PAYLOAD_TEXT) < 0) return; + if (PyModule_AddIntConstant(menum, "Other", PAYLOAD_OTHER) < 0) return; + // TODO: To remove. Deprecated enum values. + if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_CONTINUOUS", PAYLOAD_AUDIO_CONTINUOUS) < 0) return; + if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_PACKETIZED", PAYLOAD_AUDIO_PACKETIZED) < 0) return; + if (PyModule_AddIntConstant(menum, "PAYLOAD_VIDEO", PAYLOAD_VIDEO) < 0) return; + if (PyModule_AddIntConstant(menum, "PAYLOAD_TEXT", PAYLOAD_TEXT) < 0) return; + if (PyModule_AddIntConstant(menum, "PAYLOAD_OTHER", PAYLOAD_OTHER) < 0) return; + +{{#classes}} + Py_INCREF(&pylinphone_{{class_name}}Type); + PyModule_AddObject(m, "{{class_name}}", (PyObject *)&pylinphone_{{class_name}}Type); +{{/classes}} + + /* Hand-written classes. */ + Py_INCREF(&pylinphone_VideoSizeType); + PyModule_AddObject(m, "VideoSize", (PyObject *)&pylinphone_VideoSizeType); + Py_INCREF(&pylinphone_SipTransportsType); + PyModule_AddObject(m, "SipTransports", (PyObject *)&pylinphone_SipTransportsType); + + pylinphone_init_testing_module(m); +} diff --git a/tools/python/apixml2python/linphone_testing_module.mustache b/tools/python/apixml2python/linphone_testing_module.mustache new file mode 100644 index 000000000..454c81fb2 --- /dev/null +++ b/tools/python/apixml2python/linphone_testing_module.mustache @@ -0,0 +1,60 @@ +#include "private.h" + +static PyObject * pylinphone_testing_module_method_get_random_token(PyObject *self, PyObject *args) { + PyObject *pyret; + char * cresult; + int _len; + + if (!PyArg_ParseTuple(args, "i", &_len)) { + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%d)", __FUNCTION__, _len); + cresult = sal_get_random_token(_len); + pylinphone_dispatch_messages(); + + pyret = Py_BuildValue("z", cresult); + ms_free(cresult); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + return pyret; +} + +static PyObject * pylinphone_testing_module_method_set_dns_user_hosts_file(PyObject *self, PyObject *args) { + PyObject *_core; + char *_path; + LinphoneCore *_core_native_ptr; + + if (!PyArg_ParseTuple(args, "Oz", &_core, &_path)) { + return NULL; + } + if ((_core != Py_None) && !PyObject_IsInstance(_core, (PyObject *)&pylinphone_CoreType)) { + PyErr_SetString(PyExc_TypeError, "The '_core' argument must be a linphone.Core instance."); + return NULL; + } + + if ((_core != NULL) && (_core != Py_None)) { + if ((_core_native_ptr = pylinphone_Core_get_native_ptr(_core)) == NULL) { + return NULL; + } + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p [%p], %s)", __FUNCTION__, _core, _core_native_ptr, _path); + sal_set_dns_user_hosts_file(_core_native_ptr->sal, _path); + pylinphone_dispatch_messages(); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> None", __FUNCTION__); + Py_RETURN_NONE; +} + +static PyMethodDef pylinphone_TestingModuleMethods[] = { + { "get_random_token", pylinphone_testing_module_method_get_random_token, METH_VARARGS, "Gets a random token of the specified length." }, + { "set_dns_user_hosts_file", pylinphone_testing_module_method_set_dns_user_hosts_file, METH_VARARGS, "Allows to set a user specified hosts file." }, + /* Sentinel */ + { NULL, NULL, 0, NULL } +}; + +static void pylinphone_init_testing_module(PyObject *linphone_module) { + PyObject *mtesting = Py_InitModule3("testing", pylinphone_TestingModuleMethods, "Python module adding some testing features for the Linphone library."); + Py_INCREF(mtesting); + if (PyModule_AddObject(linphone_module, "testing", mtesting) < 0) return; +} diff --git a/tools/python/doc/Makefile b/tools/python/doc/Makefile new file mode 100644 index 000000000..158616058 --- /dev/null +++ b/tools/python/doc/Makefile @@ -0,0 +1,181 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + rm -f source/enums.rst + +source/enums.rst: + python generate_enums.py -o source/enums.rst + +html: source/enums.rst + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Linphone.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Linphone.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Linphone" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Linphone" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/tools/python/doc/generate_enums.py b/tools/python/doc/generate_enums.py new file mode 100644 index 000000000..2f24a7a93 --- /dev/null +++ b/tools/python/doc/generate_enums.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +import argparse +import types +import sys + +def main(argv = None): + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser(description="Generate enums documentation of the Linphone API.") + argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output .rst file describing the Linphone API enums.") + args = argparser.parse_args() + if args.outputfile == None: + args.outputfile = open('enums.rst', 'w') + + module = __import__('linphone', globals(), locals()) + + for name in dir(module): + if name == 'testing' or name == 'linphone': + continue + if type(getattr(module, name)) == types.ModuleType: + args.outputfile.write('linphone.' + name + '\n') + args.outputfile.write('^' * len('linphone.' + name) + '\n\n') + args.outputfile.write(getattr(module, name).__doc__) + args.outputfile.write('\n') + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/python/doc/make.bat b/tools/python/doc/make.bat new file mode 100644 index 000000000..9c081c72b --- /dev/null +++ b/tools/python/doc/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +set I18NSPHINXOPTS=%SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Linphone.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Linphone.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/tools/python/doc/source/_static/pylinphone.js b/tools/python/doc/source/_static/pylinphone.js new file mode 100644 index 000000000..b0b7617a0 --- /dev/null +++ b/tools/python/doc/source/_static/pylinphone.js @@ -0,0 +1,52 @@ +$(function (){ +var createList = function(selector){ + + var ul = $('