From 9e6f05e47094d94599813661f4229a26fb068690 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 30 Mar 2012 18:11:36 +0200 Subject: [PATCH 001/909] first belle_sip implementation --- .cproject | 401 ++++++++++------------ .project | 2 +- Makefile.am | 4 +- configure.ac | 60 +++- coreapi/Makefile.am | 16 +- coreapi/linphonecore.c | 7 +- coreapi/sal.c | 1 + coreapi/sal.h | 4 +- coreapi/sal_bellesip.c | 661 ++++++++++++++++++++++++++++++++++++ gtk/update.c | 6 +- tester/Makefile.am | 23 ++ tester/liblinphone_tester.c | 164 +++++++++ 12 files changed, 1094 insertions(+), 255 deletions(-) create mode 100644 coreapi/sal_bellesip.c create mode 100644 tester/Makefile.am create mode 100644 tester/liblinphone_tester.c diff --git a/.cproject b/.cproject index 3ab1fad71..4df5a2726 100644 --- a/.cproject +++ b/.cproject @@ -3,253 +3,202 @@ - - + + - - - - + + + - - - - - - - - + + + + + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - 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 - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project index 2fbbd2688..c66540e4e 100644 --- a/.project +++ b/.project @@ -23,7 +23,7 @@ org.eclipse.cdt.make.core.buildArguments - CFLAGS="-g -Werror -Wall" + CFLAGS="-g -Wall -Werror" org.eclipse.cdt.make.core.buildCommand diff --git a/Makefile.am b/Makefile.am index 5be271da4..49e2ffce1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts + coreapi console gtk share scripts tester @@ -229,4 +229,4 @@ clean-local: rm -rf $(BUNDLEDIR) discovery: touch specs.cpp - $(CC) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) -E -P -v -dD specs.cpp + $(CC) $(CFLAGS) -include $(top_builddir)/config.h $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS)-E -P -v -dD specs.cpp diff --git a/configure.ac b/configure.ac index ce3604451..518757f93 100644 --- a/configure.ac +++ b/configure.ac @@ -511,14 +511,28 @@ if test x$enable_tunnel = xtrue; then AC_SUBST(TUNNEL_LIBS) fi +SIPSTACK_CFLAGS= +SIPSTACK_LIBS= + +AC_ARG_ENABLE([bellesip], + AS_HELP_STRING([--enable-bellesip], [Build with bellesip])) + +PKG_CHECK_MODULES(BELLESIP, [belle-sip],[bellesip_found=yes],foo=bar) + +AM_CONDITIONAL([USE_BELLESIP], [test "x$enable_bellesip" != "xno" && test "x$bellesip_found" == "xyes"]) +if test $USE_BELLESIP_TRUE !='#' ; then + SIPSTACK_CFLAGS=$BELLESIP_CFLAGS + SIPSTACK_LIBS=$BELLESIP_LIBS + AC_DEFINE(USE_BELLESIP,1,[Defined when bellesip is used]) +else + SIPSTACK_CFLAGS=$EXOSIP_CFLAGS $OSIP_CFLAGS + SIPSTACK_LIBS=$EXOSIP_LIBS $OSIP_LIBS +fi - - - - - +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) @@ -568,14 +582,28 @@ AC_SUBST(ORTP_LIBS) AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) -AC_ARG_ENABLE(tests_enabled, - [ --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]) -AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes) +AC_ARG_ENABLE([tests], + AS_HELP_STRING([--disable-tests], [Disable the tests])) + AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" != "xno"]) + +PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no]) + +if test "$found_cunit" = "no" ; then + AC_CHECK_HEADERS(CUnit/CUnit.h, + [ + 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$enable_tests != xno]) @@ -596,6 +624,7 @@ m4/Makefile po/Makefile.in pixmaps/Makefile coreapi/Makefile +tester/Makefile coreapi/help/Makefile coreapi/help/Doxyfile gtk/Makefile @@ -626,6 +655,11 @@ printf "* zRTP encryption (GPLv3)\t%s\n" $zrtp if test "$enable_tunnel" = "true" ; then printf "* Tunnel support\t\ttrue\n" fi +if test $USE_BELLESIP_TRUE !='#' ; then + printf "* bellesip stack\t\ttrue\n" +else + printf "* eXosip stack\t\ttrue\n" +fi echo "Now type 'make' to compile, and then 'make install' as root to install it." diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 7a6040d1a..e9da0bf57 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -22,9 +22,6 @@ liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ offeranswer.c offeranswer.h\ sal.c sal.h \ - sal_eXosip2.c sal_eXosip2.h\ - sal_eXosip2_sdp.c \ - sal_eXosip2_presence.c \ callbacks.c \ misc.c \ address.c \ @@ -42,7 +39,13 @@ liblinphone_la_SOURCES=\ ec-calibrator.c \ conference.c \ linphone_tunnel.cc - +if USE_BELLESIP +liblinphone_la_SOURCES+= sal_bellesip.c +else +liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ + sal_eXosip2_sdp.c \ + sal_eXosip2_presence.c +endif if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c endif @@ -56,7 +59,7 @@ endif liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined liblinphone_la_LIBADD= \ - $(EXOSIP_LIBS) \ + $(SIPSTACK_LIBS) \ $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) $(OPENSSL_LIBS) \ $(TUNNEL_LIBS) \ @@ -78,8 +81,7 @@ endif AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ - $(OSIP_CFLAGS) \ - $(EXOSIP_CFLAGS) \ + $(SIPSTACK_CFLAGS) \ $(LIBSOUP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 63be1a7fc..78cda3e86 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -306,6 +306,7 @@ void linphone_core_enable_logs(FILE *file){ if (file==NULL) file=stdout; ortp_set_log_file(file); ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + sal_enable_logs(); } /** @@ -320,6 +321,7 @@ void linphone_core_enable_logs(FILE *file){ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); ortp_set_log_handler(logfunc); + sal_enable_logs(); } /** @@ -329,6 +331,7 @@ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ **/ void linphone_core_disable_logs(){ ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); + sal_disable_logs(); } @@ -1462,14 +1465,14 @@ int linphone_core_get_sip_port(LinphoneCore *lc) static char _ua_name[64]="Linphone"; static char _ua_version[64]=LINPHONE_VERSION; -#ifdef HAVE_EXOSIP_GET_VERSION +#if HAVE_EXOSIP_GET_VERSION && !USE_BELLESIP extern const char *eXosip_get_version(); #endif static void apply_user_agent(LinphoneCore *lc){ char ua_string[256]; snprintf(ua_string,sizeof(ua_string)-1,"%s/%s (eXosip2/%s)",_ua_name,_ua_version, -#ifdef HAVE_EXOSIP_GET_VERSION +#if HAVE_EXOSIP_GET_VERSION && !USE_BELLESIP eXosip_get_version() #else "unknown" diff --git a/coreapi/sal.c b/coreapi/sal.c index 874c3716d..761fbbe5c 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -38,6 +38,7 @@ const char* sal_transport_to_string(SalTransport transport) { } SalTransport sal_transport_parse(const char* param) { + if (!param) return SalTransportUDP; if (strcasecmp("udp",param)==0) return SalTransportUDP; if (strcasecmp("tcp",param)==0) return SalTransportTCP; if (strcasecmp("tls",param)==0) return SalTransportTLS; diff --git a/coreapi/sal.h b/coreapi/sal.h index 1ae18a9d4..39aeb1984 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -60,7 +60,7 @@ 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_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); @@ -371,6 +371,8 @@ int sal_ping(SalOp *op, const char *from, const char *to); /*misc*/ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); +void sal_enable_logs(); +void sal_disable_logs(); /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); diff --git a/coreapi/sal_bellesip.c b/coreapi/sal_bellesip.c new file mode 100644 index 000000000..ebb074c39 --- /dev/null +++ b/coreapi/sal_bellesip.c @@ -0,0 +1,661 @@ +/* +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.h" +#include "belle-sip/belle-sip.h" +/**/ + + +/* Address manipulation API*/ +SalAddress * sal_address_new(const char *uri){ + belle_sip_header_address_t* result; + if (uri) { + return (SalAddress *)belle_sip_header_address_parse (uri); + } else { + result = belle_sip_header_address_new(); + belle_sip_header_address_set_uri(result,belle_sip_uri_new()); + return (SalAddress *)result; + } +} +SalAddress * sal_address_clone(const SalAddress *addr){ + return (SalAddress *) belle_sip_object_clone(BELLE_SIP_OBJECT(addr)); +} +const char *sal_address_get_scheme(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) { + if (belle_sip_uri_is_secure(uri)) return "sips"; + else return "sip"; + } else + return NULL; +} +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) +} +const char * sal_address_get_port(const SalAddress *addr){ + ms_fatal("sal_address_get_port not implemented yet"); + return NULL; +} +int sal_address_get_port_int(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){ + 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 sal_transport_parse(belle_sip_uri_get_transport_param(uri)); + } else + return SalTransportUDP; +}; + +void sal_address_set_display_name(SalAddress *addr, const char *display_name){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_header_address_set_displayname(header_addr,display_name); +} +void sal_address_set_username(SalAddress *addr, const char *username){ + SAL_ADDRESS_SET(addr,user,username); +} +void sal_address_set_domain(SalAddress *addr, const char *host){ + SAL_ADDRESS_SET(addr,host,host); +} +void sal_address_set_port(SalAddress *addr, const char *port){ + SAL_ADDRESS_SET(addr,port,atoi(port)); +} +void sal_address_set_port_int(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_header_address_set_displayname(header_addr,NULL); + belle_sip_object_unref(belle_sip_header_address_get_uri(header_addr)); + belle_sip_header_address_set_uri(header_addr,belle_sip_uri_new()); + return ; +} +char *sal_address_as_string(const SalAddress *addr){ + return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); +} +char *sal_address_as_string_uri_only(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); +} +void sal_address_destroy(SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_object_unref(header_addr); + return ; +} +void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); + belle_sip_parameters_set_parameter(parameters,name,value); + return ; +} +void sal_address_set_transport(SalAddress* addr,SalTransport transport){ + SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); +} + + +struct Sal{ + SalCallbacks callbacks; + belle_sip_listener_callbacks_t listener_callbacks; + belle_sip_stack_t* stack; + belle_sip_provider_t *prov; + void *up; /*user pointer*/ +}; + + +struct SalOp{ + SalOpBase base; + belle_sip_listener_callbacks_t callbacks; + belle_sip_request_t* register_request; + unsigned long int registration_refresh_timer; +}; + +void sal_enable_logs(){ + belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); +} +void sal_disable_logs() { + belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); +} +static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ + ms_error("process_dialog_terminated not implemented yet"); +} +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} +static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { + ms_error("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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + if (op->callbacks.process_response_event) { + 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->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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); + if (op->calbacks.process_transaction_terminated) { + op->calbacks.process_transaction_terminated(op,event); + } else */{ + ms_error("Unhandled transaction terminated [%p]",event); + } +} + +Sal * sal_init(){ + Sal * sal=ms_new0(Sal,1); + sal->stack = belle_sip_stack_new(NULL); + sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); + sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; + sal->listener_callbacks.process_io_error=process_io_error; + sal->listener_callbacks.process_request_event=process_request_event; + sal->listener_callbacks.process_response_event=process_response_event; + sal->listener_callbacks.process_timeout=process_timeout; + sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; + belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + 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_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; +} + + + +void sal_uninit(Sal* sal){ + belle_sip_object_unref(sal->prov); + belle_sip_object_unref(sal->stack); + ms_free(sal); + return ; +}; + +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ + int result; + belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,addr,port,sal_transport_to_string(tr)); + if (lp) { + result = belle_sip_provider_add_listening_point(ctx->prov,lp); + belle_sip_object_unref(lp); + } else { + return -1; + } + return result; +} +static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { + belle_sip_provider_remove_listening_point(prov,lp); +} +int sal_unlisten_ports(Sal *ctx){ + const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); + belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); + belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); + belle_sip_list_free(tmp_list); + + ms_message("sal_unlisten_ports done"); + return 0; +} +ortp_socket_t sal_get_socket(Sal *ctx){ + ms_fatal("sal_get_socket not implemented yet"); + return -1; +} +void sal_set_user_agent(Sal *ctx, const char *user_agent){ + ms_error("sal_set_user_agent not implemented yet"); + return ; +} +/*keepalive period in ms*/ +void sal_set_keepalive_period(Sal *ctx,unsigned int value){ + ms_error("sal_set_keepalive_period not implemented yet"); + return ; +} +/** + * returns keepalive period in ms + * 0 desactiaved + * */ +unsigned int sal_get_keepalive_period(Sal *ctx){ + ms_fatal("sal_get_keepalive_period not implemented yet"); + return -1; +} +void sal_use_session_timers(Sal *ctx, int expires){ + ms_error("sal_use_session_timers not implemented yet"); + return ; +} +void sal_use_double_registrations(Sal *ctx, bool_t enabled){ + ms_error("sal_use_double_registrations not implemented yet"); + return ; +} +void sal_reuse_authorization(Sal *ctx, bool_t enabled){ + ms_error("sal_reuse_authorization not implemented yet"); + return ; +} +void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ + ms_error("sal_use_one_matching_codec_policy not implemented yet"); + return ; +} +void sal_use_rport(Sal *ctx, bool_t use_rports){ + ms_error("sal_use_rport not implemented yet"); + return ; +} +void sal_use_101(Sal *ctx, bool_t use_101){ + ms_error("sal_use_101 not implemented yet"); + return ; +} +void sal_set_root_ca(Sal* ctx, const char* rootCa){ + ms_error("sal_set_root_ca not implemented yet"); + return ; +} +void sal_verify_server_certificates(Sal *ctx, bool_t verify){ + ms_error("sal_verify_server_certificates not implemented yet"); + return ; +} + +int sal_iterate(Sal *sal){ + /*FIXME should be zero*/ + belle_sip_stack_sleep(sal->stack,1); + return 0; +} +MSList * sal_get_pending_auths(Sal *sal){ + ms_fatal("sal_get_pending_auths not implemented yet"); + return NULL; +} + + + + +/*create an operation */ +SalOp * sal_op_new(Sal *sal){ + SalOp *op=ms_new0(SalOp,1); + __sal_op_init(op,sal); + return op; +} + +void sal_op_release(SalOp *op){ + __sal_op_free(op); + if (op->register_request) belle_sip_object_unref(op->register_request); + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + } + return ; +} +void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ + ms_fatal("sal_op_authenticate not implemented yet"); + return ; +} +void sal_op_cancel_authentication(SalOp *h){ + ms_fatal("sal_op_cancel_authentication not implemented yet"); + return ; +} + +int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username){ + ms_fatal("sal_op_get_auth_requested not implemented yet"); + return -1; +} +/*Call API*/ +int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ + ms_fatal("sal_call_set_local_media_description not implemented yet"); + return -1; +} +int sal_call(SalOp *h, const char *from, const char *to){ + ms_fatal("sal_call not implemented yet"); + return -1; +} +int sal_call_notify_ringing(SalOp *h, bool_t early_media){ + ms_fatal("sal_call_notify_ringing not implemented yet"); + return -1; +} +/*accept an incoming call or, during a call accept a reINVITE*/ +int sal_call_accept(SalOp*h){ + ms_fatal("sal_call_accept not implemented yet"); + return -1; +} +int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ + ms_fatal("sal_call_decline not implemented yet"); + return -1; +} +int sal_call_update(SalOp *h, const char *subject){ + ms_fatal("sal_call_update not implemented yet"); + return -1; +} +SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ + ms_fatal("sal_call_get_remote_media_description not implemented yet"); + return NULL; +} +SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ + ms_fatal("sal_call_get_final_media_description not implemented yet"); + return NULL; +} +int sal_call_refer(SalOp *h, const char *refer_to){ + ms_fatal("sal_call_refer not implemented yet"); + return -1; +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); + return -1; +} +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){ + ms_fatal("sal_call_set_referer not implemented yet"); + return -1; +} +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *h){ + ms_fatal("sal_call_get_replaces not implemented yet"); + return NULL; +} +int sal_call_send_dtmf(SalOp *h, char dtmf){ + ms_fatal("sal_call_send_dtmf not implemented yet"); + return -1; +} +int sal_call_terminate(SalOp *h){ + ms_fatal("sal_call_terminate not implemented yet"); + return -1; +} +bool_t sal_call_autoanswer_asked(SalOp *op){ + ms_fatal("sal_call_autoanswer_asked not implemented yet"); + return -1; +} +void sal_call_send_vfu_request(SalOp *h){ + ms_fatal("sal_call_send_vfu_request not implemented yet"); + return ; +} +int sal_call_is_offerer(const SalOp *h){ + ms_fatal("sal_call_is_offerer not implemented yet"); + return -1; +} + + +/**************************REGISTRATION***************************/////////// +static void send_register_request(SalOp* op, belle_sip_request_t* request); + +static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} + +static void register_refresh(SalOp* op) { + op->registration_refresh_timer=0; + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request(op,op->register_request); +} +static void register_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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + belle_sip_header_expires_t* expires_header; + belle_sip_request_t* old_register_request; + int response_code = belle_sip_response_get_status_code(response); + if (response_code<200) return;/*nothing to do*/ + switch (response_code) { + case 200: { + expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES); + op->base.root->callbacks.register_success(op,expires_header&&belle_sip_header_expires_get_expires(expires_header)>0); + old_register_request=op->register_request; + op->register_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_object_ref(op->register_request); + if (old_register_request) belle_sip_object_unref(old_register_request); + /*FIXME schedule refresh cb*/ + if (belle_sip_header_expires_get_expires(expires_header)>0) { + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + } + op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,belle_sip_header_expires_get_expires(expires_header)*1000); + } + break; + } + default:{ + ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); + break; + } +} +} +static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_error("process_timeout not implemented yet"); +} +static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_error("process_transaction_terminated not implemented yet"); +} + + + +static void send_register_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + op->callbacks.process_io_error=register_process_io_error; + op->callbacks.process_response_event=register_response_event; + op->callbacks.process_timeout=register_process_timeout; + op->callbacks.process_transaction_terminated=register_process_transaction_terminated; + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_client_transaction_send_request(client_transaction); + +} +static void send_register_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) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + belle_sip_header_expires_set_expires(expires_header,expires); + send_register_request(op,request); +} + +int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ + belle_sip_request_t *req; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_uri_t* req_uri; + belle_sip_uri_t* contact_uri; + + char token[10]; + if (expires<0) goto error; + from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); + if (!from_header) goto error; + to_header=belle_sip_header_to_create(from,NULL); + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + belle_sip_uri_set_user(req_uri,NULL); + + if (sal_op_get_contact(op)) + contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); + else + contact_uri=belle_sip_uri_new(); + + if (!contact_uri) goto error; + belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); + sal_op_set_route(op,proxy); + /*FIXME use route info if needed*/ + + + req=belle_sip_request_create( + req_uri, + "REGISTER", + belle_sip_provider_create_call_id(prov), + belle_sip_header_cseq_create(20,"REGISTER"), + from_header, + to_header, + belle_sip_header_via_new(), + 70); + + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); + send_register_request_with_expires(op,req,expires); + +return 0; +error: + ms_error("Cannot initiate register to [%s] for [%s], expire [%i]",proxy,from,expires); + if (contact_header) belle_sip_object_unref(contact_header); + if (from_header) belle_sip_object_unref(from_header); + if (to_header) belle_sip_object_unref(to_header); + return -1; +} +int sal_register_refresh(SalOp *op, int expires){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->register_request,expires); + return 0; +} +int sal_unregister(SalOp *op){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->register_request,0); + return 0; +} + +/*Messaging */ +int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ + ms_fatal("sal_text_send not implemented yet"); + return -1; +} + +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ + ms_fatal("sal_subscribe_presence not implemented yet"); + return -1; +} +int sal_unsubscribe(SalOp *op){ + ms_fatal("sal_unsubscribe not implemented yet"); + return -1; +} +int sal_subscribe_accept(SalOp *op){ + ms_fatal("sal_subscribe_accept not implemented yet"); + return -1; +} +int sal_subscribe_decline(SalOp *op){ + ms_fatal("sal_subscribe_decline not implemented yet"); + return -1; +} +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + ms_fatal("sal_notify_presence not implemented yet"); + return -1; +} +int sal_notify_close(SalOp *op){ + ms_fatal("sal_notify_close not implemented yet"); + return -1; +} + +/*presence publish */ +int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ + ms_fatal("sal_publish not implemented yet"); + return -1; +} + + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to){ + ms_fatal("sal_ping not implemented yet"); + return -1; +} + + + +#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){ + ms_fatal("sal_get_default_local_ip not implemented yet"); + return ; +} diff --git a/gtk/update.c b/gtk/update.c index 6fac1b8ff..34cff9995 100755 --- 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/tester/Makefile.am b/tester/Makefile.am new file mode 100644 index 000000000..375b22912 --- /dev/null +++ b/tester/Makefile.am @@ -0,0 +1,23 @@ + +if BUILD_CUNIT_TESTS + +noinst_PROGRAMS=liblinphone_tester +TESTS=$(noinst_PROGRAMS) + +liblinphone_tester_SOURCES= liblinphone_tester.c + + +#liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) + +#liblinphone_tester_LDFLAGS=$(CUNIT_LIBS) + + +INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi + +LDADD=$(top_builddir)/coreapi/liblinphone.la + +AM_LDFLAGS=$(CUNIT_LIBS) + +AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) + +endif diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c new file mode 100644 index 000000000..a6df5714b --- /dev/null +++ b/tester/liblinphone_tester.c @@ -0,0 +1,164 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" + +const char *test_domain="localhost"; + + +static int init(void) { + return 0; +} +static int uninit(void) { + return 0; +} +static void core_init_test(void) { + LinphoneCoreVTable v_table; + memset (&v_table,0,sizeof(v_table)); + LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_destroy(lc); +} + +static LinphoneAddress * create_linphone_address(void) { + LinphoneAddress *addr = linphone_address_new(NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(addr); + linphone_address_set_username(addr,"tester"); + CU_ASSERT_STRING_EQUAL("tester",linphone_address_get_username(addr)); + linphone_address_set_domain(addr,test_domain); + CU_ASSERT_STRING_EQUAL(test_domain,linphone_address_get_domain(addr)); + linphone_address_set_display_name(addr, NULL); + linphone_address_set_display_name(addr, "Mr Tester"); + CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); + return addr; +} +static void linphone_address_test(void) { + ms_free(create_linphone_address()); +} + +static int number_of_LinphoneRegistrationNone=0; +static int number_of_LinphoneRegistrationProgress =0; +static int number_of_LinphoneRegistrationOk =0; +static int number_of_LinphoneRegistrationCleared =0; +static int number_of_LinphoneRegistrationFailed =0; + + +static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + 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)); + switch (cstate) { + case LinphoneRegistrationNone:number_of_LinphoneRegistrationNone++;break; + case LinphoneRegistrationProgress:number_of_LinphoneRegistrationProgress++;break; + case LinphoneRegistrationOk:number_of_LinphoneRegistrationOk++;break; + case LinphoneRegistrationCleared:number_of_LinphoneRegistrationCleared++;break; + case LinphoneRegistrationFailed:number_of_LinphoneRegistrationFailed++;break; + default: + CU_FAIL("unexpected event");break; + } + +} + +static void simple_register(void) { + LinphoneCoreVTable v_table; + int retry=0; + LCSipTransports transport = {5070,5070,0,5071}; + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_set_sip_transports(lc,&transport); + LinphoneProxyConfig* proxy_cfg; + + proxy_cfg = linphone_proxy_config_new(); + + LinphoneAddress *from = create_linphone_address(); + + linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); + const char* server_addr = linphone_address_get_domain(from); + linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); + linphone_proxy_config_enable_register(proxy_cfg,TRUE); + linphone_proxy_config_expires(proxy_cfg,1); + linphone_address_destroy(from); + + linphone_core_add_proxy_config(lc,proxy_cfg); + linphone_core_set_default_proxy(lc,proxy_cfg); + + while (number_of_LinphoneRegistrationOk<1 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); + /*wait until refresh*/ + while (number_of_LinphoneRegistrationOk<2 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + + linphone_core_destroy(lc); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,2); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,2); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); + +} + +int init_test_suite () { + +CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); + + if (NULL == CU_add_test(pSuite, "linphone address tester", linphone_address_test)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "linphone core init/uninit tester", core_init_test)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple register tester", simple_register)) { + return CU_get_error(); + } + return 0; +} +int main (int argc, char *argv[]) { + int i; + for(i=1;i Date: Thu, 3 May 2012 14:52:56 +0200 Subject: [PATCH 002/909] first registration with authentication --- coreapi/Makefile.am | 4 +- coreapi/bellesip_sal/sal_address_impl.c | 137 +++++ coreapi/bellesip_sal/sal_impl.c | 272 ++++++++++ coreapi/bellesip_sal/sal_impl.h | 45 ++ coreapi/bellesip_sal/sal_op_impl.c | 435 ++++++++++++++++ coreapi/callbacks.c | 21 +- coreapi/linphonecore.c | 15 +- coreapi/proxy.c | 2 +- coreapi/sal.c | 25 +- coreapi/sal.h | 27 +- coreapi/sal_bellesip.c | 661 ------------------------ tester/liblinphone_tester.c | 99 +++- 12 files changed, 1037 insertions(+), 706 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_address_impl.c create mode 100644 coreapi/bellesip_sal/sal_impl.c create mode 100644 coreapi/bellesip_sal/sal_impl.h create mode 100644 coreapi/bellesip_sal/sal_op_impl.c delete mode 100644 coreapi/sal_bellesip.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index e9da0bf57..1a5975a09 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -40,7 +40,9 @@ liblinphone_la_SOURCES=\ conference.c \ linphone_tunnel.cc if USE_BELLESIP -liblinphone_la_SOURCES+= sal_bellesip.c +liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c \ + bellesip_sal/sal_op_impl.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c new file mode 100644 index 000000000..b1b610cf8 --- /dev/null +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -0,0 +1,137 @@ +/* +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) { + return (SalAddress *)belle_sip_header_address_parse (uri); + } else { + result = belle_sip_header_address_new(); + belle_sip_header_address_set_uri(result,belle_sip_uri_new()); + return (SalAddress *)result; + } +} +SalAddress * sal_address_clone(const SalAddress *addr){ + return (SalAddress *) belle_sip_object_clone(BELLE_SIP_OBJECT(addr)); +} +const char *sal_address_get_scheme(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) { + if (belle_sip_uri_is_secure(uri)) return "sips"; + else return "sip"; + } else + return NULL; +} +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) +} +const char * sal_address_get_port(const SalAddress *addr){ + ms_fatal("sal_address_get_port not implemented yet"); + return NULL; +} +int sal_address_get_port_int(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){ + 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 sal_transport_parse(belle_sip_uri_get_transport_param(uri)); + } else + return SalTransportUDP; +}; + +void sal_address_set_display_name(SalAddress *addr, const char *display_name){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_header_address_set_displayname(header_addr,display_name); +} +void sal_address_set_username(SalAddress *addr, const char *username){ + SAL_ADDRESS_SET(addr,user,username); +} +void sal_address_set_domain(SalAddress *addr, const char *host){ + SAL_ADDRESS_SET(addr,host,host); +} +void sal_address_set_port(SalAddress *addr, const char *port){ + SAL_ADDRESS_SET(addr,port,atoi(port)); +} +void sal_address_set_port_int(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_header_address_set_displayname(header_addr,NULL); + belle_sip_object_unref(belle_sip_header_address_get_uri(header_addr)); + belle_sip_header_address_set_uri(header_addr,belle_sip_uri_new()); + return ; +} +char *sal_address_as_string(const SalAddress *addr){ + return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); +} +char *sal_address_as_string_uri_only(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); +} +void sal_address_destroy(SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_object_unref(header_addr); + return ; +} +void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); + belle_sip_parameters_set_parameter(parameters,name,value); + return ; +} +void sal_address_set_transport(SalAddress* addr,SalTransport transport){ + SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); +} + + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c new file mode 100644 index 000000000..2dc887d53 --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.c @@ -0,0 +1,272 @@ +/* +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_enable_logs(){ + belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); +} +void sal_disable_logs() { + belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); +} +static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ + ms_error("process_dialog_terminated not implemented yet"); +} +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} +static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { + ms_error("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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + belle_sip_header_address_t* contact_address; + belle_sip_header_via_t* via_header; + belle_sip_uri_t* contact_uri; + unsigned int contact_port; + const char* received; + int rport; + bool_t contact_updated=FALSE; + char* new_contact; + + if (op->callbacks.process_response_event) { + /*Fix contact if needed*/ + via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); + received = belle_sip_header_via_get_received(via_header); + rport = belle_sip_header_via_get_rport(via_header); + if (received!=NULL || rport>0) { + if (sal_op_get_contact(op)){ + contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } + if (contact_updated) { + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); + sal_op_set_contact(op,new_contact); + belle_sip_free(new_contact); + } + belle_sip_object_unref(contact_address); + } + + } + 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->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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); + if (op->calbacks.process_transaction_terminated) { + op->calbacks.process_transaction_terminated(op,event); + } else */{ + ms_error("Unhandled transaction terminated [%p]",event); + } +} + +Sal * sal_init(){ + Sal * sal=ms_new0(Sal,1); + sal->stack = belle_sip_stack_new(NULL); + sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); + sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; + sal->listener_callbacks.process_io_error=process_io_error; + sal->listener_callbacks.process_request_event=process_request_event; + sal->listener_callbacks.process_response_event=process_response_event; + sal->listener_callbacks.process_timeout=process_timeout; + sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; + belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + 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_requested_legacy==NULL) + ctx->callbacks.auth_requested_legacy=(SalOnAuthRequestedLegacy)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; + if (ctx->callbacks.auth_requested==NULL) + ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; +} + + + +void sal_uninit(Sal* sal){ + belle_sip_object_unref(sal->prov); + belle_sip_object_unref(sal->stack); + ms_free(sal); + return ; +}; + +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ + int result; + belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,addr,port,sal_transport_to_string(tr)); + if (lp) { + result = belle_sip_provider_add_listening_point(ctx->prov,lp); + belle_sip_object_unref(lp); + } else { + return -1; + } + return result; +} +static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { + belle_sip_provider_remove_listening_point(prov,lp); +} +int sal_unlisten_ports(Sal *ctx){ + const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); + belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); + belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); + belle_sip_list_free(tmp_list); + + ms_message("sal_unlisten_ports done"); + return 0; +} +ortp_socket_t sal_get_socket(Sal *ctx){ + ms_fatal("sal_get_socket not implemented yet"); + return -1; +} +void sal_set_user_agent(Sal *ctx, const char *user_agent){ + ms_error("sal_set_user_agent not implemented yet"); + return ; +} +/*keepalive period in ms*/ +void sal_set_keepalive_period(Sal *ctx,unsigned int value){ + ms_error("sal_set_keepalive_period not implemented yet"); + return ; +} +/** + * returns keepalive period in ms + * 0 desactiaved + * */ +unsigned int sal_get_keepalive_period(Sal *ctx){ + ms_fatal("sal_get_keepalive_period not implemented yet"); + return -1; +} +void sal_use_session_timers(Sal *ctx, int expires){ + ms_error("sal_use_session_timers not implemented yet"); + return ; +} +void sal_use_double_registrations(Sal *ctx, bool_t enabled){ + ms_error("sal_use_double_registrations not implemented yet"); + return ; +} +void sal_reuse_authorization(Sal *ctx, bool_t enabled){ + ms_error("sal_reuse_authorization not implemented yet"); + return ; +} +void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ + ms_error("sal_use_one_matching_codec_policy not implemented yet"); + return ; +} +void sal_use_rport(Sal *ctx, bool_t use_rports){ + ms_error("sal_use_rport not implemented yet"); + return ; +} +void sal_use_101(Sal *ctx, bool_t use_101){ + ms_error("sal_use_101 not implemented yet"); + return ; +} +void sal_set_root_ca(Sal* ctx, const char* rootCa){ + ms_error("sal_set_root_ca not implemented yet"); + return ; +} +void sal_verify_server_certificates(Sal *ctx, bool_t verify){ + ms_error("sal_verify_server_certificates not implemented yet"); + return ; +} + +int sal_iterate(Sal *sal){ + /*FIXME should be zero*/ + 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){ + ms_fatal("sal_get_default_local_ip not implemented yet"); + return ; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h new file mode 100644 index 000000000..63b97b351 --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.h @@ -0,0 +1,45 @@ +/* +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.h" +#include "belle-sip/belle-sip.h" + +struct Sal{ + SalCallbacks callbacks; + MSList *pending_auths;/*MSList of SalOp */ + belle_sip_listener_callbacks_t listener_callbacks; + belle_sip_stack_t* stack; + belle_sip_provider_t *prov; + void *up; /*user pointer*/ +}; + + +struct SalOp{ + SalOpBase base; + belle_sip_listener_callbacks_t callbacks; + belle_sip_request_t* register_request; + belle_sip_response_t* register_response; + SalAuthInfo auth_info; + unsigned long int registration_refresh_timer; +}; + + +#endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c new file mode 100644 index 000000000..6de7ea051 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -0,0 +1,435 @@ +/* +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 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); +} + +/*create an operation */ +SalOp * sal_op_new(Sal *sal){ + SalOp *op=ms_new0(SalOp,1); + __sal_op_init(op,sal); + return op; +} + +void sal_op_release(SalOp *op){ + __sal_op_free(op); + if (op->register_request) belle_sip_object_unref(op->register_request); + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + } + return ; +} +void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ + belle_sip_header_www_authenticate_t* authenticate; + belle_sip_header_authorization_t* authorization; + const char* ha1; + char computed_ha1[33]; + + if (info->ha1) { + ha1=info->ha1; + } else { + if(belle_sip_auth_helper_compute_ha1(info->userid,info->realm,info->password, computed_ha1)) { + goto error; + } else + ha1=computed_ha1; + } + if (!op->register_response) { + ms_error("try to authenticate an unchallenged op [%p]",op); + goto error; + } + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_response),BELLE_SIP_WWW_AUTHENTICATE)); + if (authenticate) { + authorization = belle_sip_auth_helper_create_authorization(authenticate); + } else { + /*proxy inerite from www*/ + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_response),BELLE_SIP_PROXY_AUTHENTICATE)); + authorization = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_auth_helper_create_proxy_authorization(BELLE_SIP_HEADER_PROXY_AUTHENTICATE(authenticate))); + } + belle_sip_header_authorization_set_uri(authorization,belle_sip_request_get_uri(op->register_request)); + belle_sip_header_authorization_set_username(authorization,info->userid); + + if (belle_sip_auth_helper_fill_authorization(authorization + ,belle_sip_request_get_method(op->register_request) + ,ha1)) { + belle_sip_object_unref(authorization); + goto error; + } + belle_sip_message_set_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_HEADER(authorization)); + sal_register_refresh(op,-1); + return; + +error: + ms_error("cannot generate authorization for [%s] at [%s]",info->userid,info->realm); + + return ; +} +void sal_op_cancel_authentication(SalOp *h){ + ms_fatal("sal_op_cancel_authentication not implemented yet"); + return ; +} + +int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ + *realm=op->auth_info.realm; + *username=op->auth_info.username; + return 0; +} +/*Call API*/ +int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ + ms_fatal("sal_call_set_local_media_description not implemented yet"); + return -1; +} +int sal_call(SalOp *h, const char *from, const char *to){ + ms_fatal("sal_call not implemented yet"); + return -1; +} +int sal_call_notify_ringing(SalOp *h, bool_t early_media){ + ms_fatal("sal_call_notify_ringing not implemented yet"); + return -1; +} +/*accept an incoming call or, during a call accept a reINVITE*/ +int sal_call_accept(SalOp*h){ + ms_fatal("sal_call_accept not implemented yet"); + return -1; +} +int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ + ms_fatal("sal_call_decline not implemented yet"); + return -1; +} +int sal_call_update(SalOp *h, const char *subject){ + ms_fatal("sal_call_update not implemented yet"); + return -1; +} +SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ + ms_fatal("sal_call_get_remote_media_description not implemented yet"); + return NULL; +} +SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ + ms_fatal("sal_call_get_final_media_description not implemented yet"); + return NULL; +} +int sal_call_refer(SalOp *h, const char *refer_to){ + ms_fatal("sal_call_refer not implemented yet"); + return -1; +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); + return -1; +} +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){ + ms_fatal("sal_call_set_referer not implemented yet"); + return -1; +} +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *h){ + ms_fatal("sal_call_get_replaces not implemented yet"); + return NULL; +} +int sal_call_send_dtmf(SalOp *h, char dtmf){ + ms_fatal("sal_call_send_dtmf not implemented yet"); + return -1; +} +int sal_call_terminate(SalOp *h){ + ms_fatal("sal_call_terminate not implemented yet"); + return -1; +} +bool_t sal_call_autoanswer_asked(SalOp *op){ + ms_fatal("sal_call_autoanswer_asked not implemented yet"); + return -1; +} +void sal_call_send_vfu_request(SalOp *h){ + ms_fatal("sal_call_send_vfu_request not implemented yet"); + return ; +} +int sal_call_is_offerer(const SalOp *h){ + ms_fatal("sal_call_is_offerer not implemented yet"); + return -1; +} + +static void process_authentication(SalOp *op, belle_sip_message_t *response) { + /*only process a single header for now*/ + belle_sip_header_www_authenticate_t* authenticate; + belle_sip_header_address_t* from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(response,BELLE_SIP_FROM)); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(from); + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_WWW_AUTHENTICATE)); + if (!authenticate) { + /*search for proxy authenticate*/ + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_PROXY_AUTHENTICATE)); + + } + + + op->auth_info.realm=(char*)belle_sip_header_www_authenticate_get_realm(authenticate); + op->auth_info.username=(char*)belle_sip_uri_get_user(uri); + if (authenticate) { + if (op->base.root->callbacks.auth_requested(op,&op->auth_info)) { + sal_op_authenticate(op,&op->auth_info); + } else { + ms_message("No auth info found for [%s] at [%s]",op->auth_info.username,op->auth_info.realm); + sal_add_pending_auth(op->base.root,op); + } + } else { + ms_error(" missing authenticate header"); + } + +} + +/**************************REGISTRATION***************************/////////// +static void send_register_request(SalOp* op, belle_sip_request_t* request); + +static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} + +static void register_refresh(SalOp* op) { + op->registration_refresh_timer=0; + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request(op,op->register_request); +} +static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) { + if (!a | !b) return FALSE; + return !belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b))); +} +static void register_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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + belle_sip_header_expires_t* expires_header; + belle_sip_request_t* old_register_request=NULL;; + belle_sip_response_t* old_register_response=NULL;; + const belle_sip_list_t* contact_header_list; + int response_code = belle_sip_response_get_status_code(response); + int expires=-1; + if (response_code<200) return;/*nothing to do*/ + + /*begin + * maybe only the transaction should be kept*/ + old_register_request=op->register_request; + op->register_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_object_ref(op->register_request); + if (old_register_request) belle_sip_object_unref(old_register_request); + + old_register_response=op->register_response; + op->register_response=response; /*kept for use at authorization time*/ + belle_sip_object_ref(op->register_response); + if (old_register_response) belle_sip_object_unref(old_register_response); + /*end*/ + switch (response_code) { + case 200: { + + contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); + if (contact_header_list) { + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)is_contact_equal, (const void*)sal_op_get_contact_address(op)); + if (!contact_header_list) { + ms_error("no matching contact for [%s]", sal_op_get_contact(op)); + return; + } + expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header_list->data)); + + } + + if (expires<0 ) { + /*no contact with expire, looking for Expires header*/ + if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { + expires = belle_sip_header_expires_get_expires(expires_header); + } + } + if (expires<0) { + ms_message("Neither Expires header nor corresponding Contact header found"); + expires=0; + } + + op->base.root->callbacks.register_success(op,expires_header&&expires>=0); + if (expires>0) { + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + } + op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,belle_sip_header_expires_get_expires(expires_header)*1000); + } + sal_remove_pending_auth(op->base.root,op);/*just in case*/ + break; + } + case 401: + case 407:{ + + process_authentication(op,BELLE_SIP_MESSAGE(response)); + break; + } + default:{ + ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); + op->base.root->callbacks.register_failure(op,SalErrorFailure,SalReasonUnknown,belle_sip_response_get_reason_phrase(response)); + break; + } +} +} +static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_error("process_timeout not implemented yet"); +} +static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_error("process_transaction_terminated not implemented yet"); +} + + + +static void send_register_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + op->callbacks.process_io_error=register_process_io_error; + op->callbacks.process_response_event=register_response_event; + op->callbacks.process_timeout=register_process_timeout; + op->callbacks.process_transaction_terminated=register_process_transaction_terminated; + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_client_transaction_send_request(client_transaction); + +} +/*if expire = -1, does not change expires*/ +static void send_register_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) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + if (expires>=0) belle_sip_header_expires_set_expires(expires_header,expires); + send_register_request(op,request); +} + +int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ + belle_sip_request_t *req; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_uri_t* req_uri; + belle_sip_uri_t* contact_uri; + sal_op_set_from(op,from); + sal_op_set_to(op,from); + char token[10]; + if (expires<0) goto error; + from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); + if (!from_header) goto error; + to_header=belle_sip_header_to_create(from,NULL); + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + belle_sip_uri_set_user(req_uri,NULL); + + if (sal_op_get_contact(op)) + contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); + else + contact_uri=belle_sip_uri_new(); + + if (!contact_uri) goto error; + belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); + sal_op_set_route(op,proxy); + /*FIXME use route info if needed*/ + + + req=belle_sip_request_create( + req_uri, + "REGISTER", + belle_sip_provider_create_call_id(prov), + belle_sip_header_cseq_create(20,"REGISTER"), + from_header, + to_header, + belle_sip_header_via_new(), + 70); + + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); + send_register_request_with_expires(op,req,expires); + +return 0; +error: + ms_error("Cannot initiate register to [%s] for [%s], expire [%i]",proxy,from,expires); + if (contact_header) belle_sip_object_unref(contact_header); + if (from_header) belle_sip_object_unref(from_header); + if (to_header) belle_sip_object_unref(to_header); + return -1; +} + +int sal_register_refresh(SalOp *op, int expires){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->register_request,expires); + return 0; +} +int sal_unregister(SalOp *op){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->register_request,0); + return 0; +} + +/*Messaging */ +int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ + ms_fatal("sal_text_send not implemented yet"); + return -1; +} + +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ + ms_fatal("sal_subscribe_presence not implemented yet"); + return -1; +} +int sal_unsubscribe(SalOp *op){ + ms_fatal("sal_unsubscribe not implemented yet"); + return -1; +} +int sal_subscribe_accept(SalOp *op){ + ms_fatal("sal_subscribe_accept not implemented yet"); + return -1; +} +int sal_subscribe_decline(SalOp *op){ + ms_fatal("sal_subscribe_decline not implemented yet"); + return -1; +} +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + ms_fatal("sal_notify_presence not implemented yet"); + return -1; +} +int sal_notify_close(SalOp *op){ + ms_fatal("sal_notify_close not implemented yet"); + return -1; +} + +/*presence publish */ +int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ + ms_fatal("sal_publish not implemented yet"); + return -1; +} + + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to){ + ms_fatal("sal_ping not implemented yet"); + return -1; +} + + diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 63bff23a9..7a12c9ea7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -600,7 +600,7 @@ static void call_released(SalOp *op){ }else ms_error("call_released() for already destroyed call ?"); } -static void auth_requested(SalOp *h, const char *realm, const char *username){ +static void auth_requested_legacy(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)); @@ -794,7 +794,19 @@ static void ping_reply(SalOp *op){ ms_warning("ping reply without call attached..."); } } - +static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); + if (ai) { + sai->userid=ai->userid?ai->userid:ai->username; + sai->password=ai->passwd; + ai->usecount++; + ai->last_use_time=ms_time(NULL); + return TRUE; + } else { + return FALSE; + } +} SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -804,7 +816,7 @@ SalCallbacks linphone_sal_callbacks={ call_terminated, call_failure, call_released, - auth_requested, + auth_requested_legacy, auth_success, register_success, register_failure, @@ -816,7 +828,8 @@ SalCallbacks linphone_sal_callbacks={ notify_presence, subscribe_received, subscribe_closed, - ping_reply + ping_reply, + auth_requested }; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 78cda3e86..03db6aeb2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1621,13 +1621,13 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ - static time_t last_check=0; - static bool_t last_status=FALSE; + static time_t last_check=0; /*shared beetwen multi linphonecore*/ + bool_t last_status=linphone_core_is_network_reachabled(lc); char result[LINPHONE_IPADDR_SIZE]; bool_t new_status=last_status; /* only do the network up checking every five seconds */ - if (last_check==0 || (curtime-last_check)>=5){ + if (lc->netup_time==0 || (curtime-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){ new_status=TRUE; @@ -4144,6 +4144,7 @@ void sip_config_uninit(LinphoneCore *lc) MSList *elem; int i; sip_config_t *config=&lc->sip_conf; + bool_t all_unregistered=FALSE; lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); @@ -4156,13 +4157,17 @@ void sip_config_uninit(LinphoneCore *lc) - for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); linphone_proxy_config_edit(cfg); /* to unregister */ } - for (i=0;i<20;i++){ + for (i=0;i<20&&!all_unregistered;i++){ sal_iterate(lc->sal); + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + all_unregistered|=!linphone_proxy_config_is_registered(cfg); + } #ifndef WIN32 usleep(100000); #else diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 49e0ec3cc..ea530e6b2 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -237,7 +237,7 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ /* unregister */ - if (obj->state != LinphoneRegistrationNone && obj->state != LinphoneRegistrationCleared) { + if (obj->state == LinphoneRegistrationOk) { sal_unregister(obj->op); } } diff --git a/coreapi/sal.c b/coreapi/sal.c index 761fbbe5c..09bb6e02d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -203,6 +203,14 @@ bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMed } return TRUE; } +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){ @@ -212,9 +220,22 @@ static void assign_string(char **str, const char *arg){ if (arg) *str=ms_strdup(arg); } - +void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ + char* address_string=sal_address_as_string(address); /*can probably be optimized*/ + sal_op_set_contact(op,address_string); + ms_free(address_string); +} +const SalAddress* sal_op_get_contact_address(const SalOp *op) { + return ((SalOpBase*)op)->contact_address; +} void sal_op_set_contact(SalOp *op, const char *contact){ - assign_string(&((SalOpBase*)op)->contact,contact); + char* contact_string=NULL; + assign_address(&((SalOpBase*)op)->contact_address,contact); + if (((SalOpBase*)op)->contact_address) { + contact_string=sal_address_as_string(((SalOpBase*)op)->contact_address); + } + assign_string(&((SalOpBase*)op)->contact,contact_string); + if(contact_string) ms_free(contact_string); } void sal_op_set_route(SalOp *op, const char *route){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 39aeb1984..5b3883d89 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -164,6 +164,7 @@ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ char *contact; + SalAddress* contact_address; char *from; char *to; char *origin; @@ -211,6 +212,14 @@ typedef enum SalSubscribeState{ SalSubscribeTerminated }SalSubscribeState; +typedef struct SalAuthInfo{ + char *username; + char *userid; + char *password; + char *realm; + char *ha1; +}SalAuthInfo; + typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); @@ -219,7 +228,8 @@ typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is recei typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); typedef void (*SalOnCallReleased)(SalOp *salop); -typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); +typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); +typedef bool_t (*SalOnAuthRequested)(SalOp *salop,SalAuthInfo* info); typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); @@ -232,6 +242,9 @@ typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeState ss, SalPresence typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); +/*allows sal implementation to access auth info if available, return TRUE if found*/ + + typedef struct SalCallbacks{ SalOnCallReceived call_received; @@ -242,7 +255,7 @@ typedef struct SalCallbacks{ SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; SalOnCallReleased call_released; - SalOnAuthRequested auth_requested; + SalOnAuthRequestedLegacy auth_requested_legacy; SalOnAuthSuccess auth_success; SalOnRegisterSuccess register_success; SalOnRegisterFailure register_failure; @@ -255,14 +268,10 @@ typedef struct SalCallbacks{ SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; SalOnPingReply ping_reply; + SalOnAuthRequested auth_requested; }SalCallbacks; -typedef struct SalAuthInfo{ - char *username; - char *userid; - char *password; - char *realm; -}SalAuthInfo; + SalAuthInfo* sal_auth_info_new(); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); @@ -298,6 +307,7 @@ SalOp * sal_op_new(Sal *sal); /*generic SalOp API, working for all operations */ Sal *sal_op_get_sal(const SalOp *op); void sal_op_set_contact(SalOp *op, const char *contact); +void sal_op_set_contact_address(SalOp *op, const SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_to(SalOp *op, const char *to); @@ -309,6 +319,7 @@ int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **usernam const char *sal_op_get_from(const SalOp *op); const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); +const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ diff --git a/coreapi/sal_bellesip.c b/coreapi/sal_bellesip.c deleted file mode 100644 index ebb074c39..000000000 --- a/coreapi/sal_bellesip.c +++ /dev/null @@ -1,661 +0,0 @@ -/* -linphone -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ -#include "sal.h" -#include "belle-sip/belle-sip.h" -/**/ - - -/* Address manipulation API*/ -SalAddress * sal_address_new(const char *uri){ - belle_sip_header_address_t* result; - if (uri) { - return (SalAddress *)belle_sip_header_address_parse (uri); - } else { - result = belle_sip_header_address_new(); - belle_sip_header_address_set_uri(result,belle_sip_uri_new()); - return (SalAddress *)result; - } -} -SalAddress * sal_address_clone(const SalAddress *addr){ - return (SalAddress *) belle_sip_object_clone(BELLE_SIP_OBJECT(addr)); -} -const char *sal_address_get_scheme(const SalAddress *addr){ - belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - if (uri) { - if (belle_sip_uri_is_secure(uri)) return "sips"; - else return "sip"; - } else - return NULL; -} -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) -} -const char * sal_address_get_port(const SalAddress *addr){ - ms_fatal("sal_address_get_port not implemented yet"); - return NULL; -} -int sal_address_get_port_int(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){ - 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 sal_transport_parse(belle_sip_uri_get_transport_param(uri)); - } else - return SalTransportUDP; -}; - -void sal_address_set_display_name(SalAddress *addr, const char *display_name){ - belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_header_address_set_displayname(header_addr,display_name); -} -void sal_address_set_username(SalAddress *addr, const char *username){ - SAL_ADDRESS_SET(addr,user,username); -} -void sal_address_set_domain(SalAddress *addr, const char *host){ - SAL_ADDRESS_SET(addr,host,host); -} -void sal_address_set_port(SalAddress *addr, const char *port){ - SAL_ADDRESS_SET(addr,port,atoi(port)); -} -void sal_address_set_port_int(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_header_address_set_displayname(header_addr,NULL); - belle_sip_object_unref(belle_sip_header_address_get_uri(header_addr)); - belle_sip_header_address_set_uri(header_addr,belle_sip_uri_new()); - return ; -} -char *sal_address_as_string(const SalAddress *addr){ - return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); -} -char *sal_address_as_string_uri_only(const SalAddress *addr){ - belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); -} -void sal_address_destroy(SalAddress *addr){ - belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_object_unref(header_addr); - return ; -} -void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ - belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); - belle_sip_parameters_set_parameter(parameters,name,value); - return ; -} -void sal_address_set_transport(SalAddress* addr,SalTransport transport){ - SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); -} - - -struct Sal{ - SalCallbacks callbacks; - belle_sip_listener_callbacks_t listener_callbacks; - belle_sip_stack_t* stack; - belle_sip_provider_t *prov; - void *up; /*user pointer*/ -}; - - -struct SalOp{ - SalOpBase base; - belle_sip_listener_callbacks_t callbacks; - belle_sip_request_t* register_request; - unsigned long int registration_refresh_timer; -}; - -void sal_enable_logs(){ - belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); -} -void sal_disable_logs() { - belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); -} -static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ - ms_error("process_dialog_terminated not implemented yet"); -} -static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); -} -static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { - ms_error("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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - if (op->callbacks.process_response_event) { - 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->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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); - if (op->calbacks.process_transaction_terminated) { - op->calbacks.process_transaction_terminated(op,event); - } else */{ - ms_error("Unhandled transaction terminated [%p]",event); - } -} - -Sal * sal_init(){ - Sal * sal=ms_new0(Sal,1); - sal->stack = belle_sip_stack_new(NULL); - sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); - sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; - sal->listener_callbacks.process_io_error=process_io_error; - sal->listener_callbacks.process_request_event=process_request_event; - sal->listener_callbacks.process_response_event=process_response_event; - sal->listener_callbacks.process_timeout=process_timeout; - sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; - belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); - 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_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; -} - - - -void sal_uninit(Sal* sal){ - belle_sip_object_unref(sal->prov); - belle_sip_object_unref(sal->stack); - ms_free(sal); - return ; -}; - -int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ - int result; - belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,addr,port,sal_transport_to_string(tr)); - if (lp) { - result = belle_sip_provider_add_listening_point(ctx->prov,lp); - belle_sip_object_unref(lp); - } else { - return -1; - } - return result; -} -static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { - belle_sip_provider_remove_listening_point(prov,lp); -} -int sal_unlisten_ports(Sal *ctx){ - const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); - belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); - belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); - belle_sip_list_free(tmp_list); - - ms_message("sal_unlisten_ports done"); - return 0; -} -ortp_socket_t sal_get_socket(Sal *ctx){ - ms_fatal("sal_get_socket not implemented yet"); - return -1; -} -void sal_set_user_agent(Sal *ctx, const char *user_agent){ - ms_error("sal_set_user_agent not implemented yet"); - return ; -} -/*keepalive period in ms*/ -void sal_set_keepalive_period(Sal *ctx,unsigned int value){ - ms_error("sal_set_keepalive_period not implemented yet"); - return ; -} -/** - * returns keepalive period in ms - * 0 desactiaved - * */ -unsigned int sal_get_keepalive_period(Sal *ctx){ - ms_fatal("sal_get_keepalive_period not implemented yet"); - return -1; -} -void sal_use_session_timers(Sal *ctx, int expires){ - ms_error("sal_use_session_timers not implemented yet"); - return ; -} -void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ms_error("sal_use_double_registrations not implemented yet"); - return ; -} -void sal_reuse_authorization(Sal *ctx, bool_t enabled){ - ms_error("sal_reuse_authorization not implemented yet"); - return ; -} -void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ms_error("sal_use_one_matching_codec_policy not implemented yet"); - return ; -} -void sal_use_rport(Sal *ctx, bool_t use_rports){ - ms_error("sal_use_rport not implemented yet"); - return ; -} -void sal_use_101(Sal *ctx, bool_t use_101){ - ms_error("sal_use_101 not implemented yet"); - return ; -} -void sal_set_root_ca(Sal* ctx, const char* rootCa){ - ms_error("sal_set_root_ca not implemented yet"); - return ; -} -void sal_verify_server_certificates(Sal *ctx, bool_t verify){ - ms_error("sal_verify_server_certificates not implemented yet"); - return ; -} - -int sal_iterate(Sal *sal){ - /*FIXME should be zero*/ - belle_sip_stack_sleep(sal->stack,1); - return 0; -} -MSList * sal_get_pending_auths(Sal *sal){ - ms_fatal("sal_get_pending_auths not implemented yet"); - return NULL; -} - - - - -/*create an operation */ -SalOp * sal_op_new(Sal *sal){ - SalOp *op=ms_new0(SalOp,1); - __sal_op_init(op,sal); - return op; -} - -void sal_op_release(SalOp *op){ - __sal_op_free(op); - if (op->register_request) belle_sip_object_unref(op->register_request); - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - } - return ; -} -void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ - ms_fatal("sal_op_authenticate not implemented yet"); - return ; -} -void sal_op_cancel_authentication(SalOp *h){ - ms_fatal("sal_op_cancel_authentication not implemented yet"); - return ; -} - -int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username){ - ms_fatal("sal_op_get_auth_requested not implemented yet"); - return -1; -} -/*Call API*/ -int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ - ms_fatal("sal_call_set_local_media_description not implemented yet"); - return -1; -} -int sal_call(SalOp *h, const char *from, const char *to){ - ms_fatal("sal_call not implemented yet"); - return -1; -} -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - ms_fatal("sal_call_notify_ringing not implemented yet"); - return -1; -} -/*accept an incoming call or, during a call accept a reINVITE*/ -int sal_call_accept(SalOp*h){ - ms_fatal("sal_call_accept not implemented yet"); - return -1; -} -int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ - ms_fatal("sal_call_decline not implemented yet"); - return -1; -} -int sal_call_update(SalOp *h, const char *subject){ - ms_fatal("sal_call_update not implemented yet"); - return -1; -} -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - ms_fatal("sal_call_get_remote_media_description not implemented yet"); - return NULL; -} -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - ms_fatal("sal_call_get_final_media_description not implemented yet"); - return NULL; -} -int sal_call_refer(SalOp *h, const char *refer_to){ - ms_fatal("sal_call_refer not implemented yet"); - return -1; -} -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; -} -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){ - ms_fatal("sal_call_set_referer not implemented yet"); - return -1; -} -/* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *h){ - ms_fatal("sal_call_get_replaces not implemented yet"); - return NULL; -} -int sal_call_send_dtmf(SalOp *h, char dtmf){ - ms_fatal("sal_call_send_dtmf not implemented yet"); - return -1; -} -int sal_call_terminate(SalOp *h){ - ms_fatal("sal_call_terminate not implemented yet"); - return -1; -} -bool_t sal_call_autoanswer_asked(SalOp *op){ - ms_fatal("sal_call_autoanswer_asked not implemented yet"); - return -1; -} -void sal_call_send_vfu_request(SalOp *h){ - ms_fatal("sal_call_send_vfu_request not implemented yet"); - return ; -} -int sal_call_is_offerer(const SalOp *h){ - ms_fatal("sal_call_is_offerer not implemented yet"); - return -1; -} - - -/**************************REGISTRATION***************************/////////// -static void send_register_request(SalOp* op, belle_sip_request_t* request); - -static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); -} - -static void register_refresh(SalOp* op) { - op->registration_refresh_timer=0; - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request(op,op->register_request); -} -static void register_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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_response_t* response = belle_sip_response_event_get_response(event); - belle_sip_header_expires_t* expires_header; - belle_sip_request_t* old_register_request; - int response_code = belle_sip_response_get_status_code(response); - if (response_code<200) return;/*nothing to do*/ - switch (response_code) { - case 200: { - expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES); - op->base.root->callbacks.register_success(op,expires_header&&belle_sip_header_expires_get_expires(expires_header)>0); - old_register_request=op->register_request; - op->register_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_object_ref(op->register_request); - if (old_register_request) belle_sip_object_unref(old_register_request); - /*FIXME schedule refresh cb*/ - if (belle_sip_header_expires_get_expires(expires_header)>0) { - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - } - op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,belle_sip_header_expires_get_expires(expires_header)*1000); - } - break; - } - default:{ - ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); - break; - } -} -} -static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - ms_error("process_timeout not implemented yet"); -} -static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - ms_error("process_transaction_terminated not implemented yet"); -} - - - -static void send_register_request(SalOp* op, belle_sip_request_t* request) { - belle_sip_client_transaction_t* client_transaction; - belle_sip_provider_t* prov=op->base.root->prov; - op->callbacks.process_io_error=register_process_io_error; - op->callbacks.process_response_event=register_response_event; - op->callbacks.process_timeout=register_process_timeout; - op->callbacks.process_transaction_terminated=register_process_transaction_terminated; - client_transaction = belle_sip_provider_create_client_transaction(prov,request); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - belle_sip_client_transaction_send_request(client_transaction); - -} -static void send_register_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) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); - } - belle_sip_header_expires_set_expires(expires_header,expires); - send_register_request(op,request); -} - -int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ - belle_sip_request_t *req; - belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); - belle_sip_header_from_t* from_header; - belle_sip_header_to_t* to_header; - belle_sip_uri_t* req_uri; - belle_sip_uri_t* contact_uri; - - char token[10]; - if (expires<0) goto error; - from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); - if (!from_header) goto error; - to_header=belle_sip_header_to_create(from,NULL); - req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); - belle_sip_uri_set_user(req_uri,NULL); - - if (sal_op_get_contact(op)) - contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); - else - contact_uri=belle_sip_uri_new(); - - if (!contact_uri) goto error; - belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); - sal_op_set_route(op,proxy); - /*FIXME use route info if needed*/ - - - req=belle_sip_request_create( - req_uri, - "REGISTER", - belle_sip_provider_create_call_id(prov), - belle_sip_header_cseq_create(20,"REGISTER"), - from_header, - to_header, - belle_sip_header_via_new(), - 70); - - - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); - send_register_request_with_expires(op,req,expires); - -return 0; -error: - ms_error("Cannot initiate register to [%s] for [%s], expire [%i]",proxy,from,expires); - if (contact_header) belle_sip_object_unref(contact_header); - if (from_header) belle_sip_object_unref(from_header); - if (to_header) belle_sip_object_unref(to_header); - return -1; -} -int sal_register_refresh(SalOp *op, int expires){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->register_request,expires); - return 0; -} -int sal_unregister(SalOp *op){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->register_request,0); - return 0; -} - -/*Messaging */ -int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ - ms_fatal("sal_text_send not implemented yet"); - return -1; -} - -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ - ms_fatal("sal_subscribe_presence not implemented yet"); - return -1; -} -int sal_unsubscribe(SalOp *op){ - ms_fatal("sal_unsubscribe not implemented yet"); - return -1; -} -int sal_subscribe_accept(SalOp *op){ - ms_fatal("sal_subscribe_accept not implemented yet"); - return -1; -} -int sal_subscribe_decline(SalOp *op){ - ms_fatal("sal_subscribe_decline not implemented yet"); - return -1; -} -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ - ms_fatal("sal_notify_presence not implemented yet"); - return -1; -} -int sal_notify_close(SalOp *op){ - ms_fatal("sal_notify_close not implemented yet"); - return -1; -} - -/*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ - ms_fatal("sal_publish not implemented yet"); - return -1; -} - - -/*ping: main purpose is to obtain its own contact address behind firewalls*/ -int sal_ping(SalOp *op, const char *from, const char *to){ - ms_fatal("sal_ping not implemented yet"); - return -1; -} - - - -#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){ - ms_fatal("sal_get_default_local_ip not implemented yet"); - return ; -} diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a6df5714b..f834aedfe 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -19,8 +19,10 @@ #include "CUnit/Basic.h" #include "linphonecore.h" -const char *test_domain="localhost"; - +const char *test_domain="sip.example.org"; +const char *auth_domain="auth.example.org"; +const char* test_username="liblinphone_tester"; +const char* test_password="secret"; static int init(void) { return 0; @@ -36,20 +38,21 @@ static void core_init_test(void) { linphone_core_destroy(lc); } -static LinphoneAddress * create_linphone_address(void) { +static LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(addr); - linphone_address_set_username(addr,"tester"); - CU_ASSERT_STRING_EQUAL("tester",linphone_address_get_username(addr)); - linphone_address_set_domain(addr,test_domain); - CU_ASSERT_STRING_EQUAL(test_domain,linphone_address_get_domain(addr)); + linphone_address_set_username(addr,test_username); + CU_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); + if (!domain) domain= test_domain; + linphone_address_set_domain(addr,domain); + CU_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); linphone_address_set_display_name(addr, NULL); linphone_address_set_display_name(addr, "Mr Tester"); CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); return addr; } static void linphone_address_test(void) { - ms_free(create_linphone_address()); + ms_free(create_linphone_address(NULL)); } static int number_of_LinphoneRegistrationNone=0; @@ -57,7 +60,16 @@ static int number_of_LinphoneRegistrationProgress =0; static int number_of_LinphoneRegistrationOk =0; static int number_of_LinphoneRegistrationCleared =0; static int number_of_LinphoneRegistrationFailed =0; +static int number_of_auth_info_requested =0; +static void reset_counters() { + number_of_LinphoneRegistrationNone=0; + number_of_LinphoneRegistrationProgress =0; + number_of_LinphoneRegistrationOk =0; + number_of_LinphoneRegistrationCleared =0; + number_of_LinphoneRegistrationFailed =0; + number_of_auth_info_requested =0; +} static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ ms_message("New registration state %s for user id [%s] at proxy [%s]\n" @@ -76,26 +88,40 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo } -static void simple_register(void) { +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + number_of_auth_info_requested++; + +} +static LinphoneCore* create_lc() { LinphoneCoreVTable v_table; - int retry=0; - LCSipTransports transport = {5070,5070,0,5071}; + memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; - LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + v_table.auth_info_requested=auth_info_requested; + return linphone_core_new(&v_table,NULL,NULL,NULL); +} +static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + int retry=0; + LCSipTransports transport = {5070,5070,0,5071}; + reset_counters(); CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_set_sip_transports(lc,&transport); LinphoneProxyConfig* proxy_cfg; proxy_cfg = linphone_proxy_config_new(); - LinphoneAddress *from = create_linphone_address(); + LinphoneAddress *from = create_linphone_address(domain); linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); const char* server_addr = linphone_address_get_domain(from); linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); linphone_proxy_config_enable_register(proxy_cfg,TRUE); - linphone_proxy_config_expires(proxy_cfg,1); + linphone_proxy_config_expires(proxy_cfg,30); + if (route) linphone_proxy_config_set_route(proxy_cfg,route); linphone_address_destroy(from); linphone_core_add_proxy_config(lc,proxy_cfg); @@ -106,21 +132,43 @@ static void simple_register(void) { ms_usleep(100000); } CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); - /*wait until refresh*/ - while (number_of_LinphoneRegistrationOk<2 && retry++ <20) { - linphone_core_iterate(lc); - ms_usleep(100000); + if (refresh) { + /*wait until refresh*/ + while (number_of_LinphoneRegistrationOk<2 && retry++ <310) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + linphone_core_destroy(lc); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,2); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,2); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); + } else { + linphone_core_destroy(lc); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,1); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,1); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); } - linphone_core_destroy(lc); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,2); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,2); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); } +static void simple_register(){ + register_with_refresh(create_lc(),FALSE,NULL,NULL); + CU_ASSERT_EQUAL(number_of_auth_info_requested,0); +} +static void simple_authenticated_register(){ + number_of_auth_info_requested=0; + LinphoneCore* lc = create_lc(); + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh(lc,FALSE,auth_domain,NULL); + CU_ASSERT_EQUAL(number_of_auth_info_requested,1); +} int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); @@ -134,6 +182,9 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "simple register tester", simple_register)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { From 3fa572b2624f7a7e7099ec8b02ace7b430b1c320 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 4 May 2012 15:44:56 +0200 Subject: [PATCH 003/909] multi proxy management --- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/callbacks.c | 17 +- coreapi/linphonecore.c | 7 +- tester/flexisip.conf | 333 +++++++++++++++++++++++++++++ tester/liblinphone_tester.c | 58 ++++- tester/multi_account_lrc | 48 +++++ 6 files changed, 452 insertions(+), 13 deletions(-) create mode 100644 tester/flexisip.conf create mode 100644 tester/multi_account_lrc diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 6de7ea051..238ca225c 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -272,7 +272,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } - op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,belle_sip_header_expires_get_expires(expires_header)*1000); + op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); } sal_remove_pending_auth(op->base.root,op);/*just in case*/ break; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7a12c9ea7..9ce4e1162 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -794,7 +794,8 @@ static void ping_reply(SalOp *op){ ms_warning("ping reply without call attached..."); } } -static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { + +static bool_t fill_auth_info(SalOp*op, SalAuthInfo* sai) { LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); if (ai) { @@ -807,6 +808,20 @@ static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { return FALSE; } } +static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + if (fill_auth_info(op,sai)) { + return TRUE; + } else { + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,sai->realm,sai->username); + if (fill_auth_info(op,sai)) { + return TRUE; + } + } + return FALSE; + } +} SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 03db6aeb2..668874e2b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4144,7 +4144,7 @@ void sip_config_uninit(LinphoneCore *lc) MSList *elem; int i; sip_config_t *config=&lc->sip_conf; - bool_t all_unregistered=FALSE; + 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); @@ -4162,11 +4162,12 @@ void sip_config_uninit(LinphoneCore *lc) linphone_proxy_config_edit(cfg); /* to unregister */ } - for (i=0;i<20&&!all_unregistered;i++){ + 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); - all_unregistered|=!linphone_proxy_config_is_registered(cfg); + still_registered|=linphone_proxy_config_is_registered(cfg); } #ifndef WIN32 usleep(100000); diff --git a/tester/flexisip.conf b/tester/flexisip.conf new file mode 100644 index 000000000..ffd6acf5f --- /dev/null +++ b/tester/flexisip.conf @@ -0,0 +1,333 @@ +## +## This is the default Flexisip configuration file +## + +## +## Some global settings of the flexisip proxy. +## +[global] +# Outputs very detailed logs +# Default value: false +debug=false + +# List of white space separated host names pointing to this machine. +# This is to prevent loops while routing SIP messages. +# Default value: localhost +aliases=auth.example.org auth1.example.org auth2.example.org sip.example.org + +# The public ip address of the proxy. +# Default value: guess +ip-address=guess + +# The local interface's ip address where to listen. The wildcard +# (*) means all interfaces. +# Default value: * +bind-address=sip.example.org + +# UDP/TCP port number to listen for sip messages. +# Default value: 5060 +port=5060 + + +## +## TLS specific parameters. +## +[tls] +# Enable SIP/TLS (sips) +# Default value: true +enabled=true + +# The port used for SIP/TLS +# Default value: 5061 +port=5061 + +# An absolute path of a directory where TLS certificate can be found. +# The private key for TLS server must be in a agent.pem file within +# this directory +# Default value: /etc/flexisip/tls +certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip + + +## +## STUN server parameters. +## +[stun-server] +# Enable or disable stun server. +# Default value: true +enabled=true + +# 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=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + + +## +## 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 + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=auth.example.org auth1.example.org auth2.example.org + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# List of whitespace separated domain names to challenge. Others +# are denied. +# Default value: +auth-domains=auth.example.org auth1.example.org auth2.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=localhost;DATABASE=dbname;USER=username;PASSWORD=passname;OPTION=3; +# for a DSN-less connection. ex3: /etc/flexisip/passwd; for a file +# containing one 'user@domain password' by line. +# Default value: +datasource=./userdb.conf + +# Odbc SQL request to execute to obtain the password. Named parameters +# are :id, :domain and :authid.' +# Default value: select password from accounts where id = :id and domain = :domain and authid=:authid +request=select password from accounts where id = :id and domain = :domain and authid=:authid + +# Maximum length of the login column in database. +# Default value: 100 +max-id-length=100 + +# Maximum length of the password column in database +# Default value: 100 +max-password-length=100 + +# Use pooling in odbc +# Default value: true +odbc-pooling=true + +# Display timing statistics after this count of seconds +# Default value: 0 +odbc-display-timings-interval=0 + +# Display timing statistics once the number of samples reach this +# number. +# Default value: 0 +odbc-display-timings-after-count=0 + +# Retrieve passwords asynchronously. +# Default value: false +odbc-asynchronous=false + +# Duration of the validity of the credentials added to the cache +# in seconds. +# Default value: 1800 +cache-expire=1800 + +# Retrieve password immediately so that it is cached when an authenticated +# request arrives. +# Default value: true +immediate-retrieve-password=true + +# True if the passwords retrieved from the database are already +# SIP hashed (HA1=MD5(A1)=MD5(username:realm:password)). +# Default value: false +hashed-passwords=false + + + +## +## 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 + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# List of whitelist separated domain names to be managed by the +# registrar. +# Default value: localhost +reg-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org + + +## +## The purpose of the ContactRouteInserter module is to masquerade +## the contact header of incoming registers that are not handled +## locally (think about flexisip used as a SBC gateway) in such a +## way that it is then possible to route back outgoing invites to +## the original address. It is a kind of similar mechanism as Record-Route, +## but for REGISTER. +## +[module::ContactRouteInserter] +# Indicate whether the module is activated. +# Default value: true +enabled=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# 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 + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# 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=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + + +## +## 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=true + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=freephonie.net + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=freephonie.net + +# 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 telephone-event/8000 +audio-codecs=amr/8000 pcmu/8000 pcma/8000 telephone-event/8000 + + +## +## 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 + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# A sip uri where to send all requests +# Default value: +#route= + +# Rewrite request-uri's host and port according to above route +# Default value: false +rewrite-req-uri=false + + diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f834aedfe..3365f5f77 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -88,19 +88,12 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo } -static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { - ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); - number_of_auth_info_requested++; -} static LinphoneCore* create_lc() { LinphoneCoreVTable v_table; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested; return linphone_core_new(&v_table,NULL,NULL,NULL); } static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { @@ -161,14 +154,57 @@ static void simple_register(){ CU_ASSERT_EQUAL(number_of_auth_info_requested,0); } static void simple_authenticated_register(){ - number_of_auth_info_requested=0; LinphoneCore* lc = create_lc(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + register_with_refresh(lc,FALSE,auth_domain,NULL); + CU_ASSERT_EQUAL(number_of_auth_info_requested,0); +} + +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + number_of_auth_info_requested++; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + +} + +static void authenticated_register_with_no_initial_credentials(){ + number_of_auth_info_requested=0; + LinphoneCoreVTable v_table; + LinphoneCore* lc; + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + v_table.auth_info_requested=auth_info_requested; + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(number_of_auth_info_requested,1); } + + +static void multiple_proxy(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int retry=0; + memset (&v_table,0,sizeof(v_table)); + reset_counters(); + v_table.registration_state_changed=registration_state_changed; + lc = linphone_core_new(&v_table,NULL,"./multi_account_lrc",NULL); + + CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),3); + + while (number_of_LinphoneRegistrationOk<3 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,3); + linphone_core_destroy(lc); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); @@ -185,6 +221,12 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc new file mode 100644 index 000000000..5f1bf21a0 --- /dev/null +++ b/tester/multi_account_lrc @@ -0,0 +1,48 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 + +[auth_info_0] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth.example.org" + +[auth_info_1] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth1.example.org" + +[auth_info_2] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth2.example.org" + +[proxy_0] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_1] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_2] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth2.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + From f1bb770e2a64923cd26c5e3b7a6a162f18ec32b8 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 4 May 2012 18:02:29 +0200 Subject: [PATCH 004/909] test both tcp and tls proxies --- coreapi/bellesip_sal/sal_op_impl.c | 17 ++++++++++++++++- tester/liblinphone_tester.c | 26 ++++++++++++++++++++++++-- tester/userdb.conf | 3 +++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tester/userdb.conf diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 238ca225c..8eb1b3893 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -332,6 +332,8 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_uri_t* contact_uri; sal_op_set_from(op,from); sal_op_set_to(op,from); + belle_sip_uri_t* route_uri=NULL; + belle_sip_header_route_t* route_header; char token[10]; if (expires<0) goto error; from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); @@ -349,7 +351,9 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); sal_op_set_route(op,proxy); /*FIXME use route info if needed*/ - + if (proxy) { + route_uri=belle_sip_uri_parse(proxy); + } req=belle_sip_request_create( req_uri, @@ -363,6 +367,16 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); + + if (route_uri && !belle_sip_uri_equals(req_uri,route_uri)) { + route_header = belle_sip_header_route_new(); + belle_sip_uri_set_lr_param(route_uri,1); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(route_header),route_uri); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); + } else if (route_uri){ + belle_sip_object_unref(route_uri); + route_uri=NULL; + } send_register_request_with_expires(op,req,expires); return 0; @@ -371,6 +385,7 @@ error: if (contact_header) belle_sip_object_unref(contact_header); if (from_header) belle_sip_object_unref(from_header); if (to_header) belle_sip_object_unref(to_header); + if (route_uri) belle_sip_object_unref(route_uri); return -1; } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 3365f5f77..c86acbf65 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -111,10 +111,15 @@ static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* d linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); const char* server_addr = linphone_address_get_domain(from); - linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); + linphone_proxy_config_enable_register(proxy_cfg,TRUE); linphone_proxy_config_expires(proxy_cfg,30); - if (route) linphone_proxy_config_set_route(proxy_cfg,route); + 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); @@ -153,6 +158,17 @@ static void simple_register(){ register_with_refresh(create_lc(),FALSE,NULL,NULL); CU_ASSERT_EQUAL(number_of_auth_info_requested,0); } +static void simple_tcp_register(){ + char route[256]; + sprintf(route,"sip:%s;transport=tcp",test_domain); + register_with_refresh(create_lc(),FALSE,NULL,route); +} +static void simple_tls_register(){ + char route[256]; + sprintf(route,"sip:%s;transport=tls",test_domain); + register_with_refresh(create_lc(),FALSE,NULL,route); +} + static void simple_authenticated_register(){ LinphoneCore* lc = create_lc(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ @@ -218,6 +234,12 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "simple register tester", simple_register)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "tls register tester", simple_tls_register)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { return CU_get_error(); } diff --git a/tester/userdb.conf b/tester/userdb.conf new file mode 100644 index 000000000..65e2b549d --- /dev/null +++ b/tester/userdb.conf @@ -0,0 +1,3 @@ +liblinphone_tester@auth.example.org secret +liblinphone_tester@auth1.example.org secret +liblinphone_tester@auth2.example.org secret From c8b1916696b11f6ec213e17cf566d3309626f700 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 9 May 2012 19:49:21 +0200 Subject: [PATCH 005/909] start sal sdp implementation --- coreapi/Makefile.am | 3 +- coreapi/bellesip_sal/sal_impl.h | 4 + coreapi/bellesip_sal/sal_op_impl.c | 23 ++- coreapi/bellesip_sal/sal_sdp.c | 281 +++++++++++++++++++++++++++++ coreapi/proxy.c | 8 +- coreapi/sal.c | 57 +++++- coreapi/sal.h | 6 + 7 files changed, 364 insertions(+), 18 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_sdp.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 1a5975a09..208ab3ff6 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -42,7 +42,8 @@ liblinphone_la_SOURCES=\ if USE_BELLESIP liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ - bellesip_sal/sal_op_impl.c + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_sdp.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 63b97b351..e322bd052 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SAL_IMPL_H_ #include "sal.h" #include "belle-sip/belle-sip.h" +#include "belle-sip/belle-sdp.h" struct Sal{ SalCallbacks callbacks; @@ -41,5 +42,8 @@ struct SalOp{ unsigned long int registration_refresh_timer; }; +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); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 8eb1b3893..67a9ac098 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -314,7 +314,11 @@ static void send_register_request(SalOp* op, belle_sip_request_t* request) { /*if expire = -1, does not change expires*/ static void send_register_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); - + belle_sip_header_route_t* route_header; + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } if (!expires_header) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); } @@ -327,25 +331,30 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); belle_sip_header_from_t* from_header; + const char* from_user; belle_sip_header_to_t* to_header; belle_sip_uri_t* req_uri; belle_sip_uri_t* contact_uri; sal_op_set_from(op,from); sal_op_set_to(op,from); belle_sip_uri_t* route_uri=NULL; - belle_sip_header_route_t* route_header; + belle_sip_header_address_t* route_address; + char token[10]; if (expires<0) goto error; from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); if (!from_header) goto error; to_header=belle_sip_header_to_create(from,NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + from_user=belle_sip_uri_get_user(req_uri); /*save username for contact header*/ belle_sip_uri_set_user(req_uri,NULL); if (sal_op_get_contact(op)) contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); - else + else { contact_uri=belle_sip_uri_new(); + belle_sip_uri_set_user(contact_uri,from_user); + } if (!contact_uri) goto error; belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); @@ -369,10 +378,12 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); if (route_uri && !belle_sip_uri_equals(req_uri,route_uri)) { - route_header = belle_sip_header_route_new(); belle_sip_uri_set_lr_param(route_uri,1); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(route_header),route_uri); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); + route_address=belle_sip_header_address_new(); + belle_sip_header_address_set_uri(route_address,route_uri); + sal_op_set_route_address(op,(const SalAddress*)route_address); /*save route for subsequent register*/ + belle_sip_object_unref(route_address); + } else if (route_uri){ belle_sip_object_unref(route_uri); route_uri=NULL; diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c new file mode 100644 index 000000000..417ee58b7 --- /dev/null +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -0,0 +1,281 @@ +/* +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)) + +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; + belle_sdp_mime_parameter_t* mime_param; + belle_sdp_media_description_t* media_desc; + int i,j; + MSList* pt_it; + PayloadType* pt; + char buffer[1024]; + + if (strchr(desc->addr,':')!=NULL){ + inet6=1; + }else inet6=0; + belle_sdp_session_description_set_version(session_desc,belle_sdp_version_create(0)); + + origin = belle_sdp_origin_create(desc->username + ,desc->session_id + ,desc->session_ver + ,"IN" + , inet6 ? "IP6" :"IP4" + ,desc->addr); + + belle_sdp_session_description_set_origin(session_desc,origin); + + belle_sdp_session_description_set_session_name(session_desc,belle_sdp_session_name_create("Talk")); + + if(!sal_media_description_has_dir (desc,SalStreamSendOnly) && !sal_media_description_has_dir (desc,SalStreamInactive)) { + 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); + } + + for (i=0; instreams;i++) { + media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type) + ,desc->streams[i].port + ,1 + ,sal_media_proto_to_string(desc->streams[i].proto) + ,NULL); + for (pt_it=desc->streams[i].payloads;pt_it!=NULL;pt_it=pt_it->next) { + pt=(PayloadType*)pt_it->data; + mime_param= belle_sdp_mime_parameter_create(pt->mime_type + , pt->type + , pt->clock_rate + ,desc->streams[i].type==SalAudio?1:-1); + belle_sdp_mime_parameter_set_parameters(mime_param,pt->recv_fmtp); + if (desc->streams[i].ptime>0) { + belle_sdp_mime_parameter_set_ptime(mime_param,desc->streams[i].ptime); + } + belle_sdp_media_description_append_values_from_mime_parameter(media_desc,mime_param); + belle_sip_object_unref(mime_param); + } + if (desc->streams[i].bandwidth>0) + belle_sdp_media_description_set_bandwidth(media_desc,"AS",desc->streams[i].bandwidth); + + if (desc->streams[i].proto == SalProtoRtpSavp) { + /* add crypto lines */ + for(j=0; jstreams[i].crypto[j].algo) { + case AES_128_SHA1_80: + snprintf(buffer, sizeof(buffer), "%d %s inline:%s", + desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", desc->streams[i].crypto[j].master_key); + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); + break; + case AES_128_SHA1_32: + snprintf(buffer, sizeof(buffer), "%d %s inline:%s", + desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", desc->streams[i].crypto[j].master_key); + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); + break; + case AES_128_NO_AUTH: + ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); + break; + case NO_CIPHER_SHA1_80: + ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); + break; + default: + j = SAL_CRYPTO_ALGO_MAX; + /* no break */ + } + } + + } + belle_sdp_session_description_add_media_description(session_desc,media_desc); + + } + return session_desc; + +} + + +int sdp_to_media_description(belle_sdp_session_description_t *session_desc, SalMediaDescription *desc) { + /* + typedef struct SalMediaDescription{ + int refcount; + char addr[64]; + char username[64]; + int nstreams; + int bandwidth; + unsigned int session_ver; + unsigned int session_id; + SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + } SalMediaDescription; + */ + belle_sdp_connection_t* cnx; + belle_sip_list_t* media_desc_it; + belle_sdp_media_description_t* media_desc; + const char *mtype,*proto; + SalStreamDescription *stream; + belle_sdp_media_t* media; + belle_sip_list_t* mime_param_it=NULL; + belle_sdp_mime_parameter_t* mime_param; + PayloadType *pt; + belle_sip_list_t* attribute_it; + belle_sdp_attribute_t* attribute; + int valid_count = 0; + char tmp[256], tmp2[256]; + int nb=0; + + desc->nstreams=0; + + if ((cnx=belle_sdp_session_description_get_connection(session_desc)) && belle_sdp_connection_get_address(cnx)) { + strncpy(desc->addr,belle_sdp_connection_get_address(cnx),sizeof(desc->addr)); + } + if (belle_sdp_session_description_get_bandwidth(session_desc,"AS") >0) { + desc->bandwidth=belle_sdp_session_description_get_bandwidth(session_desc,"AS"); + } + for(media_desc_it=belle_sdp_session_description_get_media_descriptions(session_desc) + ;media_desc_it!=NULL + ;media_desc_it=media_desc_it->next) { + media_desc=BELLE_SDP_MEDIA_DESCRIPTION(media_desc_it->data); + stream=&desc->streams[desc->nstreams]; + media=belle_sdp_media_description_get_media(media_desc); + + memset(stream,0,sizeof(*stream)); + + proto = belle_sdp_media_get_protocol(media); + stream->proto=SalProtoUnknown; + if (proto){ + if (strcasecmp(proto,"RTP/AVP")==0) + stream->proto=SalProtoRtpAvp; + else if (strcasecmp(proto,"RTP/SAVP")==0){ + stream->proto=SalProtoRtpSavp; + } + } + if ((cnx=belle_sdp_media_description_get_connection(media_desc)) && belle_sdp_connection_get_address(cnx)) { + strncpy(stream->addr,belle_sdp_connection_get_address(cnx),sizeof(stream->addr)); + } + + stream->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=SalStreamSendRecv; + } + + /* for each payload type */ + for(mime_param_it=belle_sdp_media_description_build_mime_parameters(media_desc) + ;mime_param_it!=NULL + ;mime_param_it=mime_param_it->next) { + mime_param=BELLE_SDP_MIME_PARAMETER(mime_param_it->data) + + pt=payload_type_new(); + payload_type_set_number(pt,belle_sdp_mime_parameter_get_media_format(mime_param)); + pt->clock_rate=belle_sdp_mime_parameter_get_rate(mime_param); + pt->mime_type=ms_strdup(belle_sdp_mime_parameter_get_type(mime_param)); + pt->channels=belle_sdp_mime_parameter_get_channel_count(mime_param); + payload_type_set_send_fmtp(pt,belle_sdp_mime_parameter_get_parameters(mime_param)); + stream->payloads=ms_list_append(stream->payloads,pt); + stream->ptime=belle_sdp_mime_parameter_get_ptime(mime_param); + ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : ""); + } + if (mime_param_it) belle_sip_list_free_with_data(mime_param_it,belle_sip_object_unref); + /* read crypto lines if any */ + if (stream->proto == SalProtoRtpSavp) { + + memset(&stream->crypto, 0, sizeof(stream->crypto)); + for (attribute_it=belle_sdp_media_description_get_attributes(media_desc) + ;valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; + attribute_it=attribute_it->next){ + attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); + + if (keywordcmp("crypto",belle_sdp_attribute_get_name(attribute))==0 && belle_sdp_attribute_get_value(attribute)!=NULL){ + nb = sscanf(belle_sdp_attribute_get_value(attribute), "%d %256s inline:%256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2); + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + tmp2); + if (nb == 3) { + if (keywordcmp("AES_CM_128_HMAC_SHA1_80",tmp) == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_80; + else if (keywordcmp("AES_CM_128_HMAC_SHA1_32",tmp) == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_32; + else { + ms_warning("Failed to parse crypto-algo: '%s'", tmp); + stream->crypto[valid_count].algo = 0; + } + if (stream->crypto[valid_count].algo) { + strncpy(stream->crypto[valid_count].master_key, tmp2, 41); + stream->crypto[valid_count].master_key[40] = '\0'; + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + stream->crypto[valid_count].master_key); + valid_count++; + } + } else { + ms_warning("sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value(attribute),nb); + } + } + } + ms_message("Found: %d valid crypto lines", valid_count); + } + desc->nstreams++; + } + + return 0; +} + + + + diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ea530e6b2..f25a1cbaa 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -248,7 +248,7 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) obj->lc=lc; linphone_proxy_config_done(obj); } - +#ifndef USE_BELLESIP static char *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); char *ret=NULL; @@ -280,16 +280,20 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_destroy (proxy); return ret; } - +#endif static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ +#ifndef USE_BELLESIP char *contact; +#endif if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); +#ifndef USE_BELLESIP /*contact is automatically guessed by belle-sip*/ contact=guess_contact_for_register(obj); sal_op_set_contact(obj->op,contact); ms_free(contact); +#endif 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"); diff --git a/coreapi/sal.c b/coreapi/sal.c index 09bb6e02d..afddc0e3a 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -220,6 +220,8 @@ static void assign_string(char **str, const char *arg){ if (arg) *str=ms_strdup(arg); } + + void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ char* address_string=sal_address_as_string(address); /*can probably be optimized*/ sal_op_set_contact(op,address_string); @@ -228,20 +230,31 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ const SalAddress* sal_op_get_contact_address(const SalOp *op) { return ((SalOpBase*)op)->contact_address; } + +#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_contact(SalOp *op, const char *contact){ - char* contact_string=NULL; - assign_address(&((SalOpBase*)op)->contact_address,contact); - if (((SalOpBase*)op)->contact_address) { - contact_string=sal_address_as_string(((SalOpBase*)op)->contact_address); - } - assign_string(&((SalOpBase*)op)->contact,contact_string); - if(contact_string) ms_free(contact_string); + SET_PARAM(op,contact); } void sal_op_set_route(SalOp *op, const char *route){ - assign_string(&((SalOpBase*)op)->route,route); + SET_PARAM(op,route); +} +const SalAddress* sal_op_get_route_address(const SalOp *op) { + return ((SalOpBase*)op)->route_address; +} +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_set_from(SalOp *op, const char *from){ assign_string(&((SalOpBase*)op)->from,from); } @@ -354,3 +367,29 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info) { ms_free((void*)auth_info); } +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_media_proto_to_string(SalMediaProto type) { + switch (type) { + case SalProtoRtpAvp:return "RTP/AVP"; + case SalProtoRtpSavp:return "RTP/SAVP"; + default: return "unknown"; + } +} + + +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"; + } +} diff --git a/coreapi/sal.h b/coreapi/sal.h index 5b3883d89..6ca4deb32 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -91,12 +91,14 @@ typedef enum { SalVideo, SalOther } SalStreamType; +const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ SalProtoUnknown, SalProtoRtpAvp, SalProtoRtpSavp }SalMediaProto; +const char* sal_media_proto_to_string(SalMediaProto type); typedef enum{ SalStreamSendRecv, @@ -104,6 +106,7 @@ typedef enum{ SalStreamRecvOnly, SalStreamInactive }SalStreamDir; +const char* sal_stream_dir_to_string(SalStreamDir type); typedef struct SalEndpointCandidate{ char addr[64]; @@ -163,6 +166,7 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ + SalAddress* route_address; char *contact; SalAddress* contact_address; char *from; @@ -309,6 +313,7 @@ Sal *sal_op_get_sal(const SalOp *op); void sal_op_set_contact(SalOp *op, const char *contact); void sal_op_set_contact_address(SalOp *op, const SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); +void sal_op_set_route_address(SalOp *op, const SalAddress* address); void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_to(SalOp *op, const char *to); void sal_op_release(SalOp *h); @@ -321,6 +326,7 @@ const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); +const SalAddress* sal_op_get_route_address(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); From 885d4a076dd290748214f49a80074e4ed29de2da Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 11 May 2012 15:42:14 +0200 Subject: [PATCH 006/909] start incomming call implemention --- coreapi/Makefile.am | 2 + coreapi/bellesip_sal/sal_impl.c | 69 ++++- coreapi/bellesip_sal/sal_impl.h | 8 +- coreapi/bellesip_sal/sal_op_call.c | 170 +++++++++++ coreapi/bellesip_sal/sal_op_impl.c | 337 ++------------------- coreapi/bellesip_sal/sal_op_registration.c | 159 ++++++++++ coreapi/bellesip_sal/sal_sdp.c | 2 +- coreapi/sal.c | 22 +- coreapi/sal.h | 6 + tester/liblinphone_tester.c | 107 ++++++- tester/multi_account_lrc | 25 +- tester/userdb.conf | 3 + 12 files changed, 573 insertions(+), 337 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_call.c create mode 100644 coreapi/bellesip_sal/sal_op_registration.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 208ab3ff6..028db827c 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -43,6 +43,8 @@ if USE_BELLESIP liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_sdp.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 2dc887d53..0a0a1248c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -24,6 +24,41 @@ void sal_enable_logs(){ void sal_disable_logs() { belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); } +static void sal_add_pending_auth(Sal *sal, SalOp *op){ + sal->pending_auths=ms_list_append(sal->pending_auths,op); +} + + void sal_remove_pending_auth(Sal *sal, SalOp *op){ + sal->pending_auths=ms_list_remove(sal->pending_auths,op); +} + +static void process_authentication(SalOp *op, belle_sip_message_t *response) { + /*only process a single header for now*/ + belle_sip_header_www_authenticate_t* authenticate; + belle_sip_header_address_t* from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(response,BELLE_SIP_FROM)); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(from); + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_WWW_AUTHENTICATE)); + if (!authenticate) { + /*search for proxy authenticate*/ + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_PROXY_AUTHENTICATE)); + + } + + + op->auth_info.realm=(char*)belle_sip_header_www_authenticate_get_realm(authenticate); + op->auth_info.username=(char*)belle_sip_uri_get_user(uri); + if (authenticate) { + if (op->base.root->callbacks.auth_requested(op,&op->auth_info)) { + sal_op_authenticate(op,&op->auth_info); + } else { + ms_message("No auth info found for [%s] at [%s]",op->auth_info.username,op->auth_info.realm); + sal_add_pending_auth(op->base.root,op); + } + } else { + ms_error(" missing authenticate header"); + } + +} static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ ms_error("process_dialog_terminated not implemented yet"); } @@ -31,7 +66,9 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e ms_error("process_io_error not implemented yet"); } static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { - ms_error("process_request_event not implemented yet"); + belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(server_transaction)); + ms_error("sal process_request_event not implemented yet"); } static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ @@ -46,6 +83,9 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even int rport; bool_t contact_updated=FALSE; char* new_contact; + belle_sip_request_t* old_request=NULL;; + belle_sip_response_t* old_response=NULL;; + int response_code = belle_sip_response_get_status_code(response); if (op->callbacks.process_response_event) { /*Fix contact if needed*/ @@ -76,6 +116,31 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_object_unref(contact_address); } + } + /*update request/response + * maybe only the transaction should be kept*/ + old_request=op->request; + op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_object_ref(op->request); + if (old_request) belle_sip_object_unref(old_request); + + old_response=op->response; + op->response=response; /*kept for use at authorization time*/ + belle_sip_object_ref(op->response); + if (old_response) belle_sip_object_unref(old_response); + + /*handle authozation*/ + switch (response_code) { + case 200: { + sal_remove_pending_auth(op->base.root,op);/*just in case*/ + break; + } + case 401: + case 407:{ + + process_authentication(op,BELLE_SIP_MESSAGE(response)); + return; + } } op->callbacks.process_response_event(op,event); } else { @@ -221,7 +286,7 @@ unsigned int sal_get_keepalive_period(Sal *ctx){ return -1; } void sal_use_session_timers(Sal *ctx, int expires){ - ms_error("sal_use_session_timers not implemented yet"); + ctx->session_expires=expires; return ; } void sal_use_double_registrations(Sal *ctx, bool_t enabled){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index e322bd052..9fb6c73ba 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -30,20 +30,22 @@ struct Sal{ belle_sip_stack_t* stack; belle_sip_provider_t *prov; void *up; /*user pointer*/ + int session_expires; }; struct SalOp{ SalOpBase base; belle_sip_listener_callbacks_t callbacks; - belle_sip_request_t* register_request; - belle_sip_response_t* register_response; + belle_sip_request_t* request; + belle_sip_response_t* response; SalAuthInfo auth_info; unsigned long int registration_refresh_timer; + bool_t sdp_offering; }; 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); #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..543cdcd0c --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -0,0 +1,170 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + +static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} +static void call_response_event(void *user_ctx, const belle_sip_response_event_t *event){ + ms_error("response_event not implemented yet"); +} +static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_error("process_timeout not implemented yet"); +} +static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_error("process_transaction_terminated not implemented yet"); +} +static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ + belle_sdp_session_description_t* session_desc=media_description_to_sdp(desc); + belle_sip_header_content_type_t* content_type ; + belle_sip_header_content_length_t* content_length; + int length; + char buff[1024]; + + if (session_desc) { + content_type = belle_sip_header_content_type_create("application","sdp"); + length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff)); + if (length==sizeof(buff)) { + ms_error("Buffer too small or sdp too big"); + } + + content_length= belle_sip_header_content_length_create(length); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type)); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length)); + belle_sip_message_set_body(msg,buff,length); + return 0; + } else { + return -1; + } +} +/*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; + return 0; +} +int sal_call(SalOp *op, const char *from, const char *to){ + belle_sip_request_t* req; + belle_sip_header_allow_t* header_allow; + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_header_route_t* route_header; + + sal_op_set_from(op,from); + sal_op_set_to(op,to); + + req=sal_op_build_request(op,"INVITE"); + header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(header_allow)); + + if (op->base.root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Session-expires", "200")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Supported", "timer")); + } + if (op->base.local_media){ + op->sdp_offering=TRUE; + set_sdp_from_desc(BELLE_SIP_MESSAGE(req),op->base.local_media); + }else op->sdp_offering=FALSE; + + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); + } + + op->callbacks.process_io_error=call_process_io_error; + op->callbacks.process_response_event=call_response_event; + op->callbacks.process_timeout=call_process_timeout; + op->callbacks.process_transaction_terminated=call_process_transaction_terminated; + client_transaction = belle_sip_provider_create_client_transaction(prov,req); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_client_transaction_send_request(client_transaction); + + return 0; +} +int sal_call_notify_ringing(SalOp *h, bool_t early_media){ + ms_fatal("sal_call_notify_ringing not implemented yet"); + return -1; +} +/*accept an incoming call or, during a call accept a reINVITE*/ +int sal_call_accept(SalOp*h){ + ms_fatal("sal_call_accept not implemented yet"); + return -1; +} +int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ + ms_fatal("sal_call_decline not implemented yet"); + return -1; +} +int sal_call_update(SalOp *h, const char *subject){ + ms_fatal("sal_call_update not implemented yet"); + return -1; +} +SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ + ms_fatal("sal_call_get_remote_media_description not implemented yet"); + return NULL; +} +SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ + ms_fatal("sal_call_get_final_media_description not implemented yet"); + return NULL; +} +int sal_call_refer(SalOp *h, const char *refer_to){ + ms_fatal("sal_call_refer not implemented yet"); + return -1; +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); + return -1; +} +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){ + ms_fatal("sal_call_set_referer not implemented yet"); + return -1; +} +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *h){ + ms_fatal("sal_call_get_replaces not implemented yet"); + return NULL; +} +int sal_call_send_dtmf(SalOp *h, char dtmf){ + ms_fatal("sal_call_send_dtmf not implemented yet"); + return -1; +} +int sal_call_terminate(SalOp *h){ + ms_fatal("sal_call_terminate not implemented yet"); + return -1; +} +bool_t sal_call_autoanswer_asked(SalOp *op){ + ms_fatal("sal_call_autoanswer_asked not implemented yet"); + return -1; +} +void sal_call_send_vfu_request(SalOp *h){ + ms_fatal("sal_call_send_vfu_request not implemented yet"); + return ; +} +int sal_call_is_offerer(const SalOp *h){ + return h->sdp_offering; +} + + diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 67a9ac098..cd5eeecc3 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -18,13 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" -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); -} /*create an operation */ SalOp * sal_op_new(Sal *sal){ @@ -35,7 +28,7 @@ SalOp * sal_op_new(Sal *sal){ void sal_op_release(SalOp *op){ __sal_op_free(op); - if (op->register_request) belle_sip_object_unref(op->register_request); + if (op->request) belle_sip_object_unref(op->request); if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } @@ -55,28 +48,28 @@ void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ } else ha1=computed_ha1; } - if (!op->register_response) { + if (!op->response) { ms_error("try to authenticate an unchallenged op [%p]",op); goto error; } - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_response),BELLE_SIP_WWW_AUTHENTICATE)); + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->response),BELLE_SIP_WWW_AUTHENTICATE)); if (authenticate) { authorization = belle_sip_auth_helper_create_authorization(authenticate); } else { /*proxy inerite from www*/ - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_response),BELLE_SIP_PROXY_AUTHENTICATE)); + authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->response),BELLE_SIP_PROXY_AUTHENTICATE)); authorization = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_auth_helper_create_proxy_authorization(BELLE_SIP_HEADER_PROXY_AUTHENTICATE(authenticate))); } - belle_sip_header_authorization_set_uri(authorization,belle_sip_request_get_uri(op->register_request)); + belle_sip_header_authorization_set_uri(authorization,belle_sip_request_get_uri(op->request)); belle_sip_header_authorization_set_username(authorization,info->userid); if (belle_sip_auth_helper_fill_authorization(authorization - ,belle_sip_request_get_method(op->register_request) + ,belle_sip_request_get_method(op->request) ,ha1)) { belle_sip_object_unref(authorization); goto error; } - belle_sip_message_set_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_HEADER(authorization)); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_HEADER(authorization)); sal_register_refresh(op,-1); return; @@ -95,323 +88,41 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna *username=op->auth_info.username; return 0; } -/*Call API*/ -int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ - ms_fatal("sal_call_set_local_media_description not implemented yet"); - return -1; -} -int sal_call(SalOp *h, const char *from, const char *to){ - ms_fatal("sal_call not implemented yet"); - return -1; -} -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - ms_fatal("sal_call_notify_ringing not implemented yet"); - return -1; -} -/*accept an incoming call or, during a call accept a reINVITE*/ -int sal_call_accept(SalOp*h){ - ms_fatal("sal_call_accept not implemented yet"); - return -1; -} -int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ - ms_fatal("sal_call_decline not implemented yet"); - return -1; -} -int sal_call_update(SalOp *h, const char *subject){ - ms_fatal("sal_call_update not implemented yet"); - return -1; -} -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - ms_fatal("sal_call_get_remote_media_description not implemented yet"); - return NULL; -} -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - ms_fatal("sal_call_get_final_media_description not implemented yet"); - return NULL; -} -int sal_call_refer(SalOp *h, const char *refer_to){ - ms_fatal("sal_call_refer not implemented yet"); - return -1; -} -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; -} -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){ - ms_fatal("sal_call_set_referer not implemented yet"); - return -1; -} -/* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *h){ - ms_fatal("sal_call_get_replaces not implemented yet"); - return NULL; -} -int sal_call_send_dtmf(SalOp *h, char dtmf){ - ms_fatal("sal_call_send_dtmf not implemented yet"); - return -1; -} -int sal_call_terminate(SalOp *h){ - ms_fatal("sal_call_terminate not implemented yet"); - return -1; -} -bool_t sal_call_autoanswer_asked(SalOp *op){ - ms_fatal("sal_call_autoanswer_asked not implemented yet"); - return -1; -} -void sal_call_send_vfu_request(SalOp *h){ - ms_fatal("sal_call_send_vfu_request not implemented yet"); - return ; -} -int sal_call_is_offerer(const SalOp *h){ - ms_fatal("sal_call_is_offerer not implemented yet"); - return -1; -} -static void process_authentication(SalOp *op, belle_sip_message_t *response) { - /*only process a single header for now*/ - belle_sip_header_www_authenticate_t* authenticate; - belle_sip_header_address_t* from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(response,BELLE_SIP_FROM)); - belle_sip_uri_t* uri = belle_sip_header_address_get_uri(from); - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_WWW_AUTHENTICATE)); - if (!authenticate) { - /*search for proxy authenticate*/ - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_PROXY_AUTHENTICATE)); - - } - - - op->auth_info.realm=(char*)belle_sip_header_www_authenticate_get_realm(authenticate); - op->auth_info.username=(char*)belle_sip_uri_get_user(uri); - if (authenticate) { - if (op->base.root->callbacks.auth_requested(op,&op->auth_info)) { - sal_op_authenticate(op,&op->auth_info); - } else { - ms_message("No auth info found for [%s] at [%s]",op->auth_info.username,op->auth_info.realm); - sal_add_pending_auth(op->base.root,op); - } - } else { - ms_error(" missing authenticate header"); - } - -} - -/**************************REGISTRATION***************************/////////// -static void send_register_request(SalOp* op, belle_sip_request_t* request); - -static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); -} - -static void register_refresh(SalOp* op) { - op->registration_refresh_timer=0; - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request(op,op->register_request); -} -static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) { - if (!a | !b) return FALSE; - return !belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b))); -} -static void register_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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_response_t* response = belle_sip_response_event_get_response(event); - belle_sip_header_expires_t* expires_header; - belle_sip_request_t* old_register_request=NULL;; - belle_sip_response_t* old_register_response=NULL;; - const belle_sip_list_t* contact_header_list; - int response_code = belle_sip_response_get_status_code(response); - int expires=-1; - if (response_code<200) return;/*nothing to do*/ - - /*begin - * maybe only the transaction should be kept*/ - old_register_request=op->register_request; - op->register_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_object_ref(op->register_request); - if (old_register_request) belle_sip_object_unref(old_register_request); - - old_register_response=op->register_response; - op->register_response=response; /*kept for use at authorization time*/ - belle_sip_object_ref(op->register_response); - if (old_register_response) belle_sip_object_unref(old_register_response); - /*end*/ - switch (response_code) { - case 200: { - - contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); - if (contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)is_contact_equal, (const void*)sal_op_get_contact_address(op)); - if (!contact_header_list) { - ms_error("no matching contact for [%s]", sal_op_get_contact(op)); - return; - } - expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header_list->data)); - - } - - if (expires<0 ) { - /*no contact with expire, looking for Expires header*/ - if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { - expires = belle_sip_header_expires_get_expires(expires_header); - } - } - if (expires<0) { - ms_message("Neither Expires header nor corresponding Contact header found"); - expires=0; - } - - op->base.root->callbacks.register_success(op,expires_header&&expires>=0); - if (expires>0) { - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - } - op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); - } - sal_remove_pending_auth(op->base.root,op);/*just in case*/ - break; - } - case 401: - case 407:{ - - process_authentication(op,BELLE_SIP_MESSAGE(response)); - break; - } - default:{ - ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); - op->base.root->callbacks.register_failure(op,SalErrorFailure,SalReasonUnknown,belle_sip_response_get_reason_phrase(response)); - break; - } -} -} -static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - ms_error("process_timeout not implemented yet"); -} -static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - ms_error("process_transaction_terminated not implemented yet"); -} - - - -static void send_register_request(SalOp* op, belle_sip_request_t* request) { - belle_sip_client_transaction_t* client_transaction; - belle_sip_provider_t* prov=op->base.root->prov; - op->callbacks.process_io_error=register_process_io_error; - op->callbacks.process_response_event=register_response_event; - op->callbacks.process_timeout=register_process_timeout; - op->callbacks.process_transaction_terminated=register_process_transaction_terminated; - client_transaction = belle_sip_provider_create_client_transaction(prov,request); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - belle_sip_client_transaction_send_request(client_transaction); - -} -/*if expire = -1, does not change expires*/ -static void send_register_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); - belle_sip_header_route_t* route_header; - if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); - } - if (!expires_header) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); - } - if (expires>=0) belle_sip_header_expires_set_expires(expires_header,expires); - send_register_request(op,request); -} - -int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ - belle_sip_request_t *req; - belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); +belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_from_t* from_header; - const char* from_user; 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* contact_uri; - sal_op_set_from(op,from); - sal_op_set_to(op,from); - belle_sip_uri_t* route_uri=NULL; - belle_sip_header_address_t* route_address; - + belle_sip_header_contact_t* contact_header; char token[10]; - if (expires<0) goto error; - from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); - if (!from_header) goto error; - to_header=belle_sip_header_to_create(from,NULL); + + from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) + ,belle_sip_random_token(token,sizeof(token))); + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); - from_user=belle_sip_uri_get_user(req_uri); /*save username for contact header*/ - belle_sip_uri_set_user(req_uri,NULL); - if (sal_op_get_contact(op)) - contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); - else { - contact_uri=belle_sip_uri_new(); - belle_sip_uri_set_user(contact_uri,from_user); + 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(); + belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,belle_sip_uri_new()); + belle_sip_uri_set_user(belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact_header),belle_sip_uri_get_user(req_uri)); } - - if (!contact_uri) goto error; - belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); - sal_op_set_route(op,proxy); - /*FIXME use route info if needed*/ - if (proxy) { - route_uri=belle_sip_uri_parse(proxy); - } - req=belle_sip_request_create( req_uri, - "REGISTER", + method, belle_sip_provider_create_call_id(prov), - belle_sip_header_cseq_create(20,"REGISTER"), + belle_sip_header_cseq_create(20,method), from_header, to_header, belle_sip_header_via_new(), 70); - - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); - - if (route_uri && !belle_sip_uri_equals(req_uri,route_uri)) { - belle_sip_uri_set_lr_param(route_uri,1); - route_address=belle_sip_header_address_new(); - belle_sip_header_address_set_uri(route_address,route_uri); - sal_op_set_route_address(op,(const SalAddress*)route_address); /*save route for subsequent register*/ - belle_sip_object_unref(route_address); - - } else if (route_uri){ - belle_sip_object_unref(route_uri); - route_uri=NULL; - } - send_register_request_with_expires(op,req,expires); - -return 0; -error: - ms_error("Cannot initiate register to [%s] for [%s], expire [%i]",proxy,from,expires); - if (contact_header) belle_sip_object_unref(contact_header); - if (from_header) belle_sip_object_unref(from_header); - if (to_header) belle_sip_object_unref(to_header); - if (route_uri) belle_sip_object_unref(route_uri); - return -1; + return req; } -int sal_register_refresh(SalOp *op, int expires){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->register_request,expires); - return 0; -} -int sal_unregister(SalOp *op){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->register_request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->register_request,0); - return 0; -} /*Messaging */ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c new file mode 100644 index 000000000..fb7257319 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -0,0 +1,159 @@ +/* +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 send_register_request(SalOp* op, belle_sip_request_t* request); + +static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("process_io_error not implemented yet"); +} + +static void register_refresh(SalOp* op) { + op->registration_refresh_timer=0; + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request(op,op->request); +} +static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) { + if (!a | !b) return FALSE; + return !belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b))); +} +static void register_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); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + belle_sip_header_expires_t* expires_header; + + const belle_sip_list_t* contact_header_list; + int response_code = belle_sip_response_get_status_code(response); + int expires=-1; + if (response_code<200) return;/*nothing to do*/ + + + switch (response_code) { + case 200: { + + contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); + if (contact_header_list) { + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)is_contact_equal, (const void*)sal_op_get_contact_address(op)); + if (!contact_header_list) { + ms_error("no matching contact for [%s]", sal_op_get_contact(op)); + } else { + expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header_list->data)); + } + } + + if (expires<0 ) { + /*no contact with expire, looking for Expires header*/ + if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { + expires = belle_sip_header_expires_get_expires(expires_header); + } + } + if (expires<0) { + ms_message("Neither Expires header nor corresponding Contact header found"); + expires=0; + } + + op->base.root->callbacks.register_success(op,expires_header&&expires>=0); + if (expires>0) { + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + } + op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); + } + + break; + } + + default:{ + ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); + op->base.root->callbacks.register_failure(op,SalErrorFailure,SalReasonUnknown,belle_sip_response_get_reason_phrase(response)); + break; + } +} +} +static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_error("process_timeout not implemented yet"); +} +static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_error("process_transaction_terminated not implemented yet"); +} + + + +static void send_register_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + op->callbacks.process_io_error=register_process_io_error; + op->callbacks.process_response_event=register_response_event; + op->callbacks.process_timeout=register_process_timeout; + op->callbacks.process_transaction_terminated=register_process_transaction_terminated; + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_client_transaction_send_request(client_transaction); + +} +/*if expire = -1, does not change expires*/ +static void send_register_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); + belle_sip_header_route_t* route_header; + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } + if (!expires_header) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + if (expires>=0) belle_sip_header_expires_set_expires(expires_header,expires); + send_register_request(op,request); +} + + +int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ + belle_sip_request_t *req; + + 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"); + belle_sip_uri_t* req_uri = belle_sip_request_get_uri(req); + belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ + + send_register_request_with_expires(op,req,expires); + return 0; +} + +int sal_register_refresh(SalOp *op, int expires){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->request,expires); + return 0; +} +int sal_unregister(SalOp *op){ + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + send_register_request_with_expires(op,op->request,0); + return 0; +} + + diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 417ee58b7..7a2f918f1 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -73,7 +73,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip for (pt_it=desc->streams[i].payloads;pt_it!=NULL;pt_it=pt_it->next) { pt=(PayloadType*)pt_it->data; mime_param= belle_sdp_mime_parameter_create(pt->mime_type - , pt->type + , payload_type_get_number(pt) , pt->clock_rate ,desc->streams[i].type==SalAudio?1:-1); belle_sdp_mime_parameter_set_parameters(mime_param,pt->recv_fmtp); diff --git a/coreapi/sal.c b/coreapi/sal.c index afddc0e3a..77b2d5e6c 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -256,11 +256,20 @@ void sal_op_set_route_address(SalOp *op, const SalAddress *address){ ms_free(address_string); } 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){ @@ -274,11 +283,17 @@ 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 SalAddress *sal_op_get_to_address(const SalOp *op){ + return ((SalOpBase*)op)->to_address; +} const char *sal_op_get_contact(const SalOp *op){ return ((SalOpBase*)op)->contact; } @@ -392,4 +407,5 @@ const char* sal_stream_dir_to_string(SalStreamDir type) { case SalStreamInactive:return "inative"; default: return "unknown"; } + } diff --git a/coreapi/sal.h b/coreapi/sal.h index 6ca4deb32..32d5c514c 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -170,7 +170,9 @@ typedef struct SalOpBase{ char *contact; SalAddress* contact_address; char *from; + SalAddress* from_address; char *to; + SalAddress* to_address; char *origin; char *remote_ua; SalMediaDescription *local_media; @@ -315,14 +317,18 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_route_address(SalOp *op, const SalAddress* address); void sal_op_set_from(SalOp *op, const char *from); +void sal_op_set_from_address(SalOp *op, const SalAddress *from); void sal_op_set_to(SalOp *op, const char *to); +void sal_op_set_to_address(SalOp *op, const SalAddress *to); void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username); const char *sal_op_get_from(const SalOp *op); +const SalAddress *sal_op_get_from_address(const SalOp *op); const char *sal_op_get_to(const SalOp *op); +const SalAddress *sal_op_get_to_address(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index c86acbf65..1a4ec8d40 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -62,6 +62,26 @@ static int number_of_LinphoneRegistrationCleared =0; static int number_of_LinphoneRegistrationFailed =0; static int number_of_auth_info_requested =0; + +static int number_of_LinphoneCallIncomingReceived=0; +static int number_of_LinphoneCallOutgoingInit=0; +static int number_of_LinphoneCallOutgoingProgress=0; +static int number_of_LinphoneCallOutgoingRinging=0; +static int number_of_LinphoneCallOutgoingEarlyMedia=0; +static int number_of_LinphoneCallConnected=0; +static int number_of_LinphoneCallStreamsRunning=0; +static int number_of_LinphoneCallPausing=0; +static int number_of_LinphoneCallPaused=0; +static int number_of_LinphoneCallResuming=0; +static int number_of_LinphoneCallRefered=0; +static int number_of_LinphoneCallError=0; +static int number_of_LinphoneCallEnd=0; +static int number_of_LinphoneCallPausedByRemote=0; +static int number_of_LinphoneCallUpdatedByRemote=0; +static int number_of_LinphoneCallIncomingEarlyMedia=0; +static int number_of_LinphoneCallUpdated=0; +static int number_of_LinphoneCallReleased=0; + static void reset_counters() { number_of_LinphoneRegistrationNone=0; number_of_LinphoneRegistrationProgress =0; @@ -69,6 +89,24 @@ static void reset_counters() { number_of_LinphoneRegistrationCleared =0; number_of_LinphoneRegistrationFailed =0; number_of_auth_info_requested =0; + number_of_LinphoneCallIncomingReceived=0; + number_of_LinphoneCallOutgoingInit=0; + number_of_LinphoneCallOutgoingProgress=0; + number_of_LinphoneCallOutgoingRinging=0; + number_of_LinphoneCallOutgoingEarlyMedia=0; + number_of_LinphoneCallConnected=0; + number_of_LinphoneCallStreamsRunning=0; + number_of_LinphoneCallPausing=0; + number_of_LinphoneCallPaused=0; + number_of_LinphoneCallResuming=0; + number_of_LinphoneCallRefered=0; + number_of_LinphoneCallError=0; + number_of_LinphoneCallEnd=0; + number_of_LinphoneCallPausedByRemote=0; + number_of_LinphoneCallUpdatedByRemote=0; + number_of_LinphoneCallIncomingEarlyMedia=0; + number_of_LinphoneCallUpdated=0; + number_of_LinphoneCallReleased=0; } static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ @@ -202,14 +240,13 @@ static void authenticated_register_with_no_initial_credentials(){ } -static void multiple_proxy(){ - LinphoneCoreVTable v_table; +static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { + LinphoneCore* lc; int retry=0; - memset (&v_table,0,sizeof(v_table)); + memset (v_table,0,sizeof(LinphoneCoreVTable)); reset_counters(); - v_table.registration_state_changed=registration_state_changed; - lc = linphone_core_new(&v_table,NULL,"./multi_account_lrc",NULL); + lc = linphone_core_new(v_table,NULL,"./multi_account_lrc",NULL); CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),3); @@ -218,13 +255,68 @@ static void multiple_proxy(){ ms_usleep(100000); } CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,3); + return lc; +} +static void multiple_proxy(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); linphone_core_destroy(lc); } +static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + char* to=linphone_call_get_remote_address_as_string(call); + ms_message("call from [??] to [%s], new state is [%s]",to,linphone_call_state_to_string(cstate)); + ms_free(to); + switch (cstate) { + case LinphoneCallIncomingReceived:number_of_LinphoneCallIncomingReceived++;break; + case LinphoneCallOutgoingInit :number_of_LinphoneCallOutgoingInit++;break; + case LinphoneCallOutgoingProgress :number_of_LinphoneCallOutgoingProgress++;break; + case LinphoneCallOutgoingRinging :number_of_LinphoneCallOutgoingRinging++;break; + case LinphoneCallOutgoingEarlyMedia :number_of_LinphoneCallOutgoingEarlyMedia++;break; + case LinphoneCallConnected :number_of_LinphoneCallConnected++;break; + case LinphoneCallStreamsRunning :number_of_LinphoneCallStreamsRunning++;break; + case LinphoneCallPausing :number_of_LinphoneCallPausing++;break; + case LinphoneCallPaused :number_of_LinphoneCallPaused++;break; + case LinphoneCallResuming :number_of_LinphoneCallResuming++;break; + case LinphoneCallRefered :number_of_LinphoneCallRefered++;break; + case LinphoneCallError :number_of_LinphoneCallError++;break; + case LinphoneCallEnd :number_of_LinphoneCallEnd++;break; + case LinphoneCallPausedByRemote :number_of_LinphoneCallPausedByRemote++;break; + case LinphoneCallUpdatedByRemote :number_of_LinphoneCallUpdatedByRemote++;break; + case LinphoneCallIncomingEarlyMedia :number_of_LinphoneCallIncomingEarlyMedia++;break; + case LinphoneCallUpdated :number_of_LinphoneCallUpdated++;break; + case LinphoneCallReleased :number_of_LinphoneCallReleased++;break; + default: + CU_FAIL("unexpected event");break; + } +} +static void simple_call_declined() { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int retry=0; + v_table.registration_state_changed=registration_state_changed; + v_table.call_state_changed=call_state_changed; + lc=configure_lc(&v_table); + linphone_core_invite(lc,"marie"); + + while (number_of_LinphoneCallIncomingReceived<1 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(number_of_LinphoneCallIncomingReceived,1); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc)); + linphone_core_terminate_call(lc,linphone_core_get_current_call(lc)); + CU_ASSERT_EQUAL(number_of_LinphoneCallReleased,1); + linphone_core_destroy(lc); +} int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); - + if (NULL == CU_add_test(pSuite, "simple call declined", simple_call_declined)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "linphone address tester", linphone_address_test)) { return CU_get_error(); } @@ -249,6 +341,9 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple call declined", simple_call_declined)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc index 5f1bf21a0..6f362c533 100644 --- a/tester/multi_account_lrc +++ b/tester/multi_account_lrc @@ -2,6 +2,7 @@ sip_port=5072 sip_tcp_port=5072 sip_tls_port=5073 +default_proxy=0 [auth_info_0] username=liblinphone_tester @@ -10,28 +11,34 @@ passwd=secret realm="auth.example.org" [auth_info_1] -username=liblinphone_tester -userid=liblinphone_tester +username=pauline +userid=pauline passwd=secret -realm="auth1.example.org" +realm="auth.example.org" [auth_info_2] username=liblinphone_tester userid=liblinphone_tester passwd=secret -realm="auth2.example.org" +realm="auth1.example.org" + +[auth_info_3] +username=marie +userid=marie +passwd=secret +realm="auth.example.org" [proxy_0] -reg_proxy=auth.example.org -reg_identity=sip:liblinphone_tester@auth.example.org +reg_proxy=auth.example.org;transport=tls +reg_identity=sip:pauline@auth.example.org reg_expires=3600 reg_sendregister=1 publish=0 dial_escape_plus=0 [proxy_1] -reg_proxy=auth.example.org -reg_identity=sip:liblinphone_tester@auth1.example.org +reg_proxy=auth.example.org;transport=tcp +reg_identity=sip:marie@auth.example.org reg_expires=3600 reg_sendregister=1 publish=0 @@ -39,7 +46,7 @@ dial_escape_plus=0 [proxy_2] reg_proxy=auth.example.org -reg_identity=sip:liblinphone_tester@auth2.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org reg_expires=3600 reg_sendregister=1 publish=0 diff --git a/tester/userdb.conf b/tester/userdb.conf index 65e2b549d..14c510237 100644 --- a/tester/userdb.conf +++ b/tester/userdb.conf @@ -1,3 +1,6 @@ liblinphone_tester@auth.example.org secret liblinphone_tester@auth1.example.org secret liblinphone_tester@auth2.example.org secret + +pauline@auth.example.org secret +marie@auth.example.org secret From 19f236fa8f6e22c03cd83dc900e9a577982ab892 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 11 May 2012 17:15:20 +0200 Subject: [PATCH 007/909] implement useragent --- .cproject | 2 +- .project | 2 +- coreapi/bellesip_sal/sal_impl.c | 18 ++++++++++++++---- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_impl.c | 1 + coreapi/linphonecore.c | 6 +++++- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.cproject b/.cproject index 4df5a2726..539e03aa9 100644 --- a/.cproject +++ b/.cproject @@ -56,7 +56,7 @@ - + diff --git a/.project b/.project index c66540e4e..be0bf116a 100644 --- a/.project +++ b/.project @@ -23,7 +23,7 @@ org.eclipse.cdt.make.core.buildArguments - CFLAGS="-g -Wall -Werror" + CFLAGS="-g -Wall -Werror" V=1 org.eclipse.cdt.make.core.buildCommand diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 0a0a1248c..696f55807 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -17,7 +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. */ #include "sal_impl.h" - +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif void sal_enable_logs(){ belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); } @@ -66,8 +68,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e ms_error("process_io_error not implemented yet"); } static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { - belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(server_transaction)); + /*belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(server_transaction));*/ ms_error("sal process_request_event not implemented yet"); } @@ -168,7 +170,13 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } Sal * sal_init(){ + char stack_string[64]; Sal * sal=ms_new0(Sal,1); + snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); + sal->user_agent=belle_sip_header_user_agent_new(); + belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); + belle_sip_header_user_agent_add_product(sal->user_agent,stack_string); + belle_sip_object_ref(sal->user_agent); sal->stack = belle_sip_stack_new(NULL); sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; @@ -235,6 +243,7 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ void sal_uninit(Sal* sal){ + belle_sip_object_unref(sal->user_agent); belle_sip_object_unref(sal->prov); belle_sip_object_unref(sal->stack); ms_free(sal); @@ -269,7 +278,8 @@ ortp_socket_t sal_get_socket(Sal *ctx){ return -1; } void sal_set_user_agent(Sal *ctx, const char *user_agent){ - ms_error("sal_set_user_agent not implemented yet"); + belle_sip_header_user_agent_set_products(ctx->user_agent,NULL); + belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent); return ; } /*keepalive period in ms*/ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 9fb6c73ba..33a7e0ea2 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -29,6 +29,7 @@ struct Sal{ belle_sip_listener_callbacks_t listener_callbacks; belle_sip_stack_t* stack; belle_sip_provider_t *prov; + belle_sip_header_user_agent_t* user_agent; void *up; /*user pointer*/ int session_expires; }; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index cd5eeecc3..89d6e8644 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -120,6 +120,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->base.root->user_agent)); return req; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 668874e2b..f02a457b5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1470,15 +1470,17 @@ extern const char *eXosip_get_version(); #endif static void apply_user_agent(LinphoneCore *lc){ +#if !USE_BELLESIP /*default user agent is handled at sal level*/ char ua_string[256]; snprintf(ua_string,sizeof(ua_string)-1,"%s/%s (eXosip2/%s)",_ua_name,_ua_version, -#if HAVE_EXOSIP_GET_VERSION && !USE_BELLESIP +#if HAVE_EXOSIP_GET_VERSION eXosip_get_version() #else "unknown" #endif ); if (lc->sal) sal_set_user_agent(lc->sal,ua_string); +#endif } /** @@ -1537,7 +1539,9 @@ static int apply_transports(LinphoneCore *lc){ transport_error(lc,"tls",tr->tls_port); } } + apply_user_agent(lc); + return 0; } From 447076314e3482e429232f54b3f5754802bcb1d7 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 11 Jun 2012 17:34:40 +0200 Subject: [PATCH 008/909] implement sal_call_decline --- coreapi/bellesip_sal/sal_impl.c | 55 +++++++++-- coreapi/bellesip_sal/sal_impl.h | 11 +++ coreapi/bellesip_sal/sal_op_call.c | 109 +++++++++++++++++++-- coreapi/bellesip_sal/sal_op_impl.c | 30 +++++- coreapi/bellesip_sal/sal_op_registration.c | 40 +++----- coreapi/linphonecore.c | 3 +- coreapi/sal.c | 7 +- coreapi/sal.h | 3 + tester/liblinphone_tester.c | 10 +- 9 files changed, 220 insertions(+), 48 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 696f55807..5176669ee 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -45,8 +45,6 @@ static void process_authentication(SalOp *op, belle_sip_message_t *response) { authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_PROXY_AUTHENTICATE)); } - - op->auth_info.realm=(char*)belle_sip_header_www_authenticate_get_realm(authenticate); op->auth_info.username=(char*)belle_sip_uri_get_user(uri); if (authenticate) { @@ -67,10 +65,55 @@ static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_ter static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } -static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { - /*belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(server_transaction));*/ - ms_error("sal process_request_event not implemented yet"); +static void process_request_event(void *sal, const belle_sip_request_event_t *event) { + SalOp* op; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); + belle_sip_header_address_t* origin_address; + belle_sip_header_address_t* address; + belle_sip_header_from_t* from; + belle_sip_header_to_t* to; + + if (dialog) { + op=(SalOp*)belle_sip_dialog_get_application_data(dialog); + } else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { + op=sal_op_new((Sal*)sal); + sal_op_call_fill_cbs(op); + } else { + ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); + } + + if (!op->base.from_address) { + from=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + sal_op_set_from_address(op,(SalAddress*)address); + belle_sip_object_unref(address); + } + if (!op->base.to_address) { + to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))); + sal_op_set_to_address(op,(SalAddress*)address); + belle_sip_object_unref(address); + } + + if (!op->base.origin) { + /*set origin uri*/ + origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req)); + __sal_op_set_network_origin_address(op,(SalAddress*)origin_address); + belle_sip_object_unref(origin_address); + } + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(req)); + } + + if (op->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){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 33a7e0ea2..4369e687f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -40,13 +40,24 @@ struct SalOp{ belle_sip_listener_callbacks_t callbacks; belle_sip_request_t* request; belle_sip_response_t* response; + belle_sip_server_transaction_t* pending_server_trans; SalAuthInfo auth_info; unsigned long int registration_refresh_timer; bool_t sdp_offering; + belle_sip_dialog_t* dialog; + belle_sip_header_address_t *replaces; + belle_sip_header_address_t *referred_by; + bool_t auto_answer_asked; }; 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 sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); +void sal_op_send_request(SalOp* op, belle_sip_request_t* request); +void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 543cdcd0c..a2050616b 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -29,6 +29,59 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t } static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { ms_error("process_transaction_terminated not implemented yet"); +} +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 = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + 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; + + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_header_t* replace_header; + belle_sip_dialog_state_t dialog_state; + belle_sdp_session_description_t* sdp; + belle_sip_header_t* call_info; + if (!op->dialog) { + op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)); + belle_sip_dialog_set_application_data(op->dialog,op); + 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 (!op->replaces && (replace_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"replaces"))) { + op->replaces=belle_sip_header_address_parse(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(replace_header))); + belle_sip_object_ref(op->replaces); + } else if(op->replaces) { + ms_warning("replace header already set"); + } + if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))) { + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + belle_sip_object_unref(sdp); + }else + op->sdp_offering=TRUE; + + if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { + if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { + op->auto_answer_asked=TRUE; + ms_message("The caller asked to automatically answer the call(Emergency?)\n"); + } + } + + op->base.root->callbacks.call_received(op); + + break; + } + default: { + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + } + } + + } static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ belle_sdp_session_description_t* session_desc=media_description_to_sdp(desc); @@ -89,16 +142,20 @@ int sal_call(SalOp *op, const char *from, const char *to){ route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); } + sal_op_call_fill_cbs(op); + client_transaction = belle_sip_provider_create_client_transaction(prov,req); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_client_transaction_send_request(client_transaction); + return 0; +} +void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_io_error=call_process_io_error; op->callbacks.process_response_event=call_response_event; op->callbacks.process_timeout=call_process_timeout; op->callbacks.process_transaction_terminated=call_process_transaction_terminated; - client_transaction = belle_sip_provider_create_client_transaction(prov,req); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - belle_sip_client_transaction_send_request(client_transaction); - - return 0; + op->callbacks.process_request_event=process_request_event; } int sal_call_notify_ringing(SalOp *h, bool_t early_media){ ms_fatal("sal_call_notify_ringing not implemented yet"); @@ -109,9 +166,45 @@ int sal_call_accept(SalOp*h){ ms_fatal("sal_call_accept not implemented yet"); return -1; } -int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/){ - ms_fatal("sal_call_decline not implemented yet"); - return -1; +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; + switch(reason) { + case SalReasonBusy: + status=486; + break; + case SalReasonTemporarilyUnavailable: + status=480; + break; + case SalReasonDoNotDisturb: + status=600; + break; + case SalReasonMedia: + status=415; + break; + case SalReasonRedirect: + if(redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + status=380; + contact= belle_sip_header_contact_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + break; + } else { + ms_error("Cannot redirect to null"); + } + /* no break */ + + default: + status=500; + ms_error("Unexpected decline reason [%i]",reason); + /* no break */ + } + response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); + if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + belle_sip_server_transaction_send_response(op->pending_server_trans,response); + return 0; + } int sal_call_update(SalOp *h, const char *subject){ ms_fatal("sal_call_update not implemented yet"); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 89d6e8644..1fad0188f 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -27,11 +27,11 @@ SalOp * sal_op_new(Sal *sal){ } void sal_op_release(SalOp *op){ - __sal_op_free(op); if (op->request) belle_sip_object_unref(op->request); if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } + __sal_op_free(op); return ; } void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ @@ -70,7 +70,7 @@ void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ goto error; } belle_sip_message_set_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_HEADER(authorization)); - sal_register_refresh(op,-1); + sal_op_resend_request(op,op->request); return; error: @@ -78,6 +78,7 @@ error: return ; } + void sal_op_cancel_authentication(SalOp *h){ ms_fatal("sal_op_cancel_authentication not implemented yet"); return ; @@ -170,4 +171,29 @@ int sal_ping(SalOp *op, const char *from, const char *to){ return -1; } +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(belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + op->base.remote_ua=ms_strdup(user_agent_string); + } +} +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(op->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); +} +void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_header_route_t* route_header; + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_client_transaction_send_request(client_transaction); + +} diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index fb7257319..20ec119a9 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -20,8 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -static void send_register_request(SalOp* op, belle_sip_request_t* request); - static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } @@ -30,7 +28,7 @@ static void register_refresh(SalOp* op) { op->registration_refresh_timer=0; belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request(op,op->request); + sal_op_send_request(op,op->request); } static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) { if (!a | !b) return FALSE; @@ -74,10 +72,12 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve } op->base.root->callbacks.register_success(op,expires_header&&expires>=0); + /*always cancel pending refresh if any*/ + if (op->registration_refresh_timer>0) { + belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); + op->registration_refresh_timer=0; + } if (expires>0) { - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - } op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); } @@ -100,31 +100,15 @@ static void register_process_transaction_terminated(void *user_ctx, const belle_ -static void send_register_request(SalOp* op, belle_sip_request_t* request) { - belle_sip_client_transaction_t* client_transaction; - belle_sip_provider_t* prov=op->base.root->prov; - op->callbacks.process_io_error=register_process_io_error; - op->callbacks.process_response_event=register_response_event; - op->callbacks.process_timeout=register_process_timeout; - op->callbacks.process_transaction_terminated=register_process_transaction_terminated; - client_transaction = belle_sip_provider_create_client_transaction(prov,request); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - belle_sip_client_transaction_send_request(client_transaction); - -} /*if expire = -1, does not change expires*/ static void send_register_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); - belle_sip_header_route_t* route_header; - if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); - } - if (!expires_header) { + + if (!expires_header && expires>=0) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + belle_sip_header_expires_set_expires(expires_header,expires); } - if (expires>=0) belle_sip_header_expires_set_expires(expires_header,expires); - send_register_request(op,request); + sal_op_send_request(op,request); } @@ -134,6 +118,10 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ sal_op_set_from(op,from); sal_op_set_to(op,from); sal_op_set_route(op,proxy); + op->callbacks.process_io_error=register_process_io_error; + op->callbacks.process_response_event=register_response_event; + op->callbacks.process_timeout=register_process_timeout; + op->callbacks.process_transaction_terminated=register_process_transaction_terminated; req = sal_op_build_request(op,"REGISTER"); belle_sip_uri_t* req_uri = belle_sip_request_get_uri(req); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f02a457b5..f64edcb83 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2585,6 +2585,7 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { call = the_call; } + sal_call_terminate(call->op); terminate_call(lc,call); @@ -4179,7 +4180,7 @@ void sip_config_uninit(LinphoneCore *lc) Sleep(100); #endif } - + if (i>=20) ms_warning("Cannot complete unregistration, giving up"); ms_list_for_each(config->proxies,(void (*)(void*)) linphone_proxy_config_destroy); ms_list_free(config->proxies); config->proxies=NULL; diff --git a/coreapi/sal.c b/coreapi/sal.c index 77b2d5e6c..90fa26fab 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -324,9 +324,14 @@ void __sal_op_init(SalOp *b, Sal *sal){ } void __sal_op_set_network_origin(SalOp *op, const char *origin){ - assign_string(&((SalOpBase*)op)->origin,origin); + SET_PARAM(op,origin); } +void __sal_op_set_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; diff --git a/coreapi/sal.h b/coreapi/sal.h index 32d5c514c..941b23516 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -174,6 +174,7 @@ typedef struct SalOpBase{ char *to; SalAddress* to_address; char *origin; + SalAddress* origin_address; char *remote_ua; SalMediaDescription *local_media; SalMediaDescription *remote_media; @@ -336,6 +337,7 @@ const SalAddress* sal_op_get_route_address(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); +const SalAddress *sal_op_get_network_origin_address(const SalOp *op); /*returns far-end "User-Agent" string */ const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); @@ -400,6 +402,7 @@ void sal_disable_logs(); /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); +void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin); void __sal_op_free(SalOp *b); #endif diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 1a4ec8d40..4f6ae1b16 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -244,7 +244,7 @@ static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { LinphoneCore* lc; int retry=0; - memset (v_table,0,sizeof(LinphoneCoreVTable)); + reset_counters(); lc = linphone_core_new(v_table,NULL,"./multi_account_lrc",NULL); @@ -260,6 +260,7 @@ static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { static void multiple_proxy(){ LinphoneCoreVTable v_table; LinphoneCore* lc; + memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); linphone_core_destroy(lc); @@ -296,6 +297,7 @@ static void simple_call_declined() { LinphoneCore* lc; int retry=0; + memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; v_table.call_state_changed=call_state_changed; lc=configure_lc(&v_table); @@ -314,6 +316,7 @@ static void simple_call_declined() { int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); + if (NULL == CU_add_test(pSuite, "simple call declined", simple_call_declined)) { return CU_get_error(); } @@ -341,9 +344,8 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } - if (NULL == CU_add_test(pSuite, "simple call declined", simple_call_declined)) { - return CU_get_error(); - } + + return 0; } int main (int argc, char *argv[]) { From e2d0579e6b632f189af49c470f85ab10183303e4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 27 Jul 2012 18:24:08 +0200 Subject: [PATCH 009/909] First working version --- coreapi/bellesip_sal/sal_address_impl.c | 4 +- coreapi/bellesip_sal/sal_impl.c | 105 ++++--- coreapi/bellesip_sal/sal_impl.h | 18 ++ coreapi/bellesip_sal/sal_op_call.c | 323 +++++++++++++++++--- coreapi/bellesip_sal/sal_op_impl.c | 65 ++-- coreapi/bellesip_sal/sal_op_registration.c | 4 +- coreapi/callbacks.c | 11 +- coreapi/friend.c | 6 +- coreapi/sal.h | 2 +- tester/flexisip.conf | 18 +- tester/liblinphone_tester.c | 338 ++++++++++++++------- tester/marie_rc | 38 +++ tester/pauline_rc | 37 +++ tester/userdb.conf | 2 + 14 files changed, 711 insertions(+), 260 deletions(-) mode change 100644 => 100755 tester/flexisip.conf create mode 100644 tester/marie_rc create mode 100644 tester/pauline_rc diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index b1b610cf8..e2bb58daf 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -107,9 +107,7 @@ void sal_address_set_port_int(SalAddress *addr, int port){ } void sal_address_clean(SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_header_address_set_displayname(header_addr,NULL); - belle_sip_object_unref(belle_sip_header_address_get_uri(header_addr)); - belle_sip_header_address_set_uri(header_addr,belle_sip_uri_new()); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr)); return ; } char *sal_address_as_string(const SalAddress *addr){ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 5176669ee..110a1b04f 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -34,28 +34,14 @@ static void sal_add_pending_auth(Sal *sal, SalOp *op){ sal->pending_auths=ms_list_remove(sal->pending_auths,op); } -static void process_authentication(SalOp *op, belle_sip_message_t *response) { - /*only process a single header for now*/ - belle_sip_header_www_authenticate_t* authenticate; - belle_sip_header_address_t* from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(response,BELLE_SIP_FROM)); - belle_sip_uri_t* uri = belle_sip_header_address_get_uri(from); - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_WWW_AUTHENTICATE)); - if (!authenticate) { - /*search for proxy authenticate*/ - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(response,BELLE_SIP_PROXY_AUTHENTICATE)); - - } - op->auth_info.realm=(char*)belle_sip_header_www_authenticate_get_realm(authenticate); - op->auth_info.username=(char*)belle_sip_uri_get_user(uri); - if (authenticate) { - if (op->base.root->callbacks.auth_requested(op,&op->auth_info)) { - sal_op_authenticate(op,&op->auth_info); - } else { - ms_message("No auth info found for [%s] at [%s]",op->auth_info.username,op->auth_info.realm); - sal_add_pending_auth(op->base.root,op); - } - } else { - ms_error(" missing authenticate header"); +void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_AUTHORIZATION); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_PROXY_AUTHORIZATION); + if (belle_sip_provider_add_authorization(op->base.root->prov,op->request,response)) { + sal_op_resend_request(op,op->request); + }else { + ms_message("No auth info found for [%s]",sal_op_get_from(op)); + sal_add_pending_auth(op->base.root,op); } } @@ -66,7 +52,7 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e ms_error("process_io_error not implemented yet"); } static void process_request_event(void *sal, const belle_sip_request_event_t *event) { - SalOp* op; + 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; @@ -78,9 +64,11 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op=(SalOp*)belle_sip_dialog_get_application_data(dialog); } else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { op=sal_op_new((Sal*)sal); + op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); } else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); + return; } if (!op->base.from_address) { @@ -120,7 +108,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_response_t* response = belle_sip_response_event_get_response(event); - belle_sip_header_address_t* contact_address; + belle_sip_header_address_t* contact_address=NULL; belle_sip_header_via_t* via_header; belle_sip_uri_t* contact_uri; unsigned int contact_port; @@ -132,11 +120,31 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); + } + if (op->callbacks.process_response_event) { /*Fix contact if needed*/ via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); received = belle_sip_header_via_get_received(via_header); rport = belle_sip_header_via_get_rport(via_header); + if (!sal_op_get_contact(op)) { + /*hmm update contact from via*/ + contact_address=belle_sip_header_address_new(); + contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); + belle_sip_header_address_set_uri(contact_address,contact_uri); + + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + } + if (belle_sip_header_via_get_listening_port(via_header) + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + } + contact_updated=TRUE; + } + if (received!=NULL || rport>0) { if (sal_op_get_contact(op)){ contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); @@ -152,16 +160,30 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_uri_set_port(contact_uri,rport); contact_updated=TRUE; } - if (contact_updated) { - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); - sal_op_set_contact(op,new_contact); - belle_sip_free(new_contact); - } - belle_sip_object_unref(contact_address); - } + /*try to fix transport if needed (very unlikely)*/ + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + if (!belle_sip_uri_get_transport_param(contact_uri) + ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); + } + } + } } + if (contact_updated) { + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); + sal_op_set_contact(op,new_contact); + belle_sip_free(new_contact); + } + if (contact_address)belle_sip_object_unref(contact_address); + /*update request/response * maybe only the transaction should be kept*/ old_request=op->request; @@ -182,8 +204,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } case 401: case 407:{ - - process_authentication(op,BELLE_SIP_MESSAGE(response)); + sal_process_authentication(op,response); return; } } @@ -211,7 +232,17 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans ms_error("Unhandled transaction terminated [%p]",event); } } - +static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { + SalAuthInfo auth_info; + memset(&auth_info,0,sizeof(SalAuthInfo)); + auth_info.username=(char*)belle_sip_auth_event_get_username(auth_event); + auth_info.realm=(char*)belle_sip_auth_event_get_realm(auth_event); + ((Sal*)sal)->callbacks.auth_requested(sal,&auth_info); + belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info.password); + belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info.ha1); + belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info.userid); + return; +} Sal * sal_init(){ char stack_string[64]; Sal * sal=ms_new0(Sal,1); @@ -228,6 +259,7 @@ Sal * sal_init(){ sal->listener_callbacks.process_response_event=process_response_event; sal->listener_callbacks.process_timeout=process_timeout; sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; + sal->listener_callbacks.process_auth_requested=process_auth_requested; belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); return sal; } @@ -351,8 +383,7 @@ void sal_reuse_authorization(Sal *ctx, bool_t enabled){ return ; } void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ms_error("sal_use_one_matching_codec_policy not implemented yet"); - return ; + ctx->one_matching_codec=one_matching_codec; } void sal_use_rport(Sal *ctx, bool_t use_rports){ ms_error("sal_use_rport not implemented yet"); diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 4369e687f..309e779ba 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -32,8 +32,19 @@ struct Sal{ belle_sip_header_user_agent_t* user_agent; void *up; /*user pointer*/ int session_expires; + bool_t one_matching_codec; }; +typedef enum SalOpSate { + SalOpStateEarly=0 + ,SalOpStateActive + ,SalOpStateTerminated +}SalOpSate_t; + +typedef enum SalOpDir { + SalOpDirIncoming=0 + ,SalOpDirOutgoing +}SalOpDir_t; struct SalOp{ SalOpBase base; @@ -48,6 +59,11 @@ struct SalOp{ belle_sip_header_address_t *replaces; belle_sip_header_address_t *referred_by; bool_t auto_answer_asked; + SalMediaDescription *result; + belle_sdp_session_description_t *sdp_answer; + bool_t supports_session_timers; + SalOpSate_t state; + SalOpDir_t dir; }; belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); @@ -60,4 +76,6 @@ void sal_op_call_fill_cbs(SalOp*op); void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); void sal_op_send_request(SalOp* op, belle_sip_request_t* request); void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); +void sal_process_authentication(SalOp *op, belle_sip_response_t *response); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index a2050616b..d5a65b44c 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -17,12 +17,193 @@ 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 void sdp_process(SalOp *h){ + ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); + if (h->result){ + sal_media_description_unref(h->result); + } + h->result=sal_media_description_new(); + if (h->sdp_offering){ + offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); + }else{ + int i; + if (h->sdp_answer){ + belle_sip_object_unref(h->sdp_answer); + } + offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); + h->sdp_answer=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->nstreams;++i){ + if (h->result->streams[i].port>0){ + strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].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].port=h->base.remote_media->streams[i].port; + + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; + } + } + } + } + +} +static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { + belle_sip_header_content_type_t* content_type ; + belle_sip_header_content_length_t* content_length; + int length; + char buff[1024]; + + if (session_desc) { + content_type = belle_sip_header_content_type_create("application","sdp"); + length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff)); + if (length==sizeof(buff)) { + ms_error("Buffer too small or sdp too big"); + } + + content_length= belle_sip_header_content_length_create(length); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type)); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length)); + belle_sip_message_set_body(msg,buff,length); + return 0; + } else { + return -1; + } +} +static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ + return set_sdp(msg,media_description_to_sdp(desc)); + +} static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } -static void call_response_event(void *user_ctx, const belle_sip_response_event_t *event){ - ms_error("response_event not implemented yet"); +static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { + belle_sdp_session_description_t* sdp; + if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + if (op->base.local_media) sdp_process(op); + } +} +static void call_response_event(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_response_t* response=belle_sip_response_event_get_response(event); + int code = belle_sip_response_get_status_code(response); + char* reason; + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + reason=(char*)belle_sip_response_get_reason_phrase(response); + if (reason_header){ + reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); + } + if (code >=400) { + switch(code) { + case 400: + error=SalErrorUnknown; + break; + case 404: + error=SalErrorFailure; + sr=SalReasonNotFound; + break; + case 415: + error=SalErrorFailure; + sr=SalReasonMedia; + break; + case 422: + ms_error ("422 not implemented yet");; + break; + case 480: + error=SalErrorFailure; + sr=SalReasonTemporarilyUnavailable; + break; + case 486: + error=SalErrorFailure; + sr=SalReasonBusy; + break; + case 487: + break; + case 600: + error=SalErrorFailure; + sr=SalReasonDoNotDisturb; + break; + case 603: + error=SalErrorFailure; + sr=SalReasonDeclined; + break; + default: + if (code>0){ + error=SalErrorFailure; + sr=SalReasonUnknown; + }else error=SalErrorNoResponse; + /* no break */ + } + + op->base.root->callbacks.call_failure(op,error,sr,reason,code); + if (reason_header != NULL){ + ms_free(reason); + } + return; + } + /*else dialog*/ + + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + + case BELLE_SIP_DIALOG_NULL: { + ms_error("op [%p] receive an unexpected answer [%i]",op,code); + break; + } + case BELLE_SIP_DIALOG_EARLY: { + if (code >= 180) { + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_ringing(op); + } else { + ms_error("op [%p] receive an unexpected answer [%i]",op,code); + } + break; + } + case BELLE_SIP_DIALOG_CONFIRMED: { + switch (op->state) { + case SalOpStateEarly: + 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(response),op->sdp_answer); + op->sdp_answer=NULL; + } + belle_sip_dialog_send_ack(op->dialog,ack); + op->base.root->callbacks.call_accepted(op); + break; + case SalOpStateActive: + case SalOpStateTerminated: + default: + ms_error("op [%p] receive answer [%i] not implemented",op,code); + } + break; + } + case BELLE_SIP_DIALOG_TERMINATED: + default: { + ms_error("op [%p] receive answer [%i] not implemented",op,code); + } + /* no break */ + } + + } static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { ms_error("process_timeout not implemented yet"); @@ -42,6 +223,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_dialog_state_t dialog_state; belle_sdp_session_description_t* sdp; belle_sip_header_t* call_info; + belle_sip_response_t* resp; if (!op->dialog) { op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_dialog_set_application_data(op->dialog,op); @@ -76,36 +258,41 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t break; } + case BELLE_SIP_DIALOG_CONFIRMED: + /*great ACK received*/ + if (strcmp("ACK",belle_sip_request_get_method(req))==0) { + if (op->sdp_offering){ + if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))){ + if (op->base.remote_media) + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_process(op); + belle_sip_object_unref(sdp); + } + } + /*FIXME + if (op->reinvite){ + op->reinvite=FALSE; + }*/ + op->base.root->callbacks.call_ack(op); + } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else { + ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); + } + break; default: { ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); } + /* no break */ } } -static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ - belle_sdp_session_description_t* session_desc=media_description_to_sdp(desc); - belle_sip_header_content_type_t* content_type ; - belle_sip_header_content_length_t* content_length; - int length; - char buff[1024]; - if (session_desc) { - content_type = belle_sip_header_content_type_create("application","sdp"); - length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff)); - if (length==sizeof(buff)) { - ms_error("Buffer too small or sdp too big"); - } - - content_length= belle_sip_header_content_length_create(length); - belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type)); - belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length)); - belle_sip_message_set_body(msg,buff,length); - return 0; - } else { - return -1; - } -} /*Call API*/ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ if (desc) @@ -121,7 +308,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; - + op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); @@ -157,14 +344,58 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_transaction_terminated=call_process_transaction_terminated; op->callbacks.process_request_event=process_request_event; } -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - ms_fatal("sal_call_notify_ringing not implemented yet"); - return -1; +int sal_call_notify_ringing(SalOp *op, bool_t early_media){ + belle_sip_response_t* ringing_response; + + /*if early media send also 180 and 183 */ + if (early_media){ + ms_fatal("not implemented yet"); + }else{ + ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),180); + 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){ - ms_fatal("sal_call_accept not implemented yet"); - return -1; + belle_sip_response_t *response; + belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(h); + belle_sip_header_contact_t* contact_header; + /* sends a 200 OK */ + response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200); + + if (response==NULL){ + ms_error("Fail to build answer for call"); + return -1; + } + if (h->base.root->session_expires!=0){ + if (h->supports_session_timers) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer")); + } + } + + if (contact && (contact_header=belle_sip_header_contact_create(contact))) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); + } + + if (h->base.local_media){ + /*this is the case where we received an invite without SDP*/ + if (h->sdp_offering) { + set_sdp_from_desc(BELLE_SIP_MESSAGE(response),h->base.local_media); + }else{ + if (h->sdp_answer==NULL) sdp_process(h); + if (h->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(response),h->sdp_answer); + h->sdp_answer=NULL; + } + } + }else{ + ms_error("You are accepting a call but not defined any media capabilities !"); + } + belle_sip_server_transaction_send_response(h->pending_server_trans,response); + return 0; } int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ belle_sip_response_t* response; @@ -214,9 +445,13 @@ SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ ms_fatal("sal_call_get_remote_media_description not implemented yet"); return NULL; } + + SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - ms_fatal("sal_call_get_final_media_description not implemented yet"); - return NULL; + if (h->base.local_media && h->base.remote_media && !h->result){ + sdp_process(h); + } + return h->result; } int sal_call_refer(SalOp *h, const char *refer_to){ ms_fatal("sal_call_refer not implemented yet"); @@ -237,20 +472,32 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){ } /* returns the SalOp of a call that should be replaced by h, if any */ SalOp *sal_call_get_replaces(SalOp *h){ - ms_fatal("sal_call_get_replaces not implemented yet"); + if (h!=NULL && h->replaces!=NULL){ + ms_fatal("sal_call_get_replaces not implemented yet"); + } return NULL; } int sal_call_send_dtmf(SalOp *h, char dtmf){ ms_fatal("sal_call_send_dtmf not implemented yet"); return -1; } -int sal_call_terminate(SalOp *h){ - ms_fatal("sal_call_terminate not implemented yet"); - return -1; +int sal_call_terminate(SalOp *op){ + belle_sip_dialog_state_t dialog_state=belle_sip_dialog_get_state(op->dialog); + + switch(dialog_state) { + case BELLE_SIP_DIALOG_CONFIRMED: { + sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + } + break; + default: { + ms_fatal("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){ - ms_fatal("sal_call_autoanswer_asked not implemented yet"); - return -1; + return op->auto_answer_asked; } void sal_call_send_vfu_request(SalOp *h){ ms_fatal("sal_call_send_vfu_request not implemented yet"); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 1fad0188f..2de7d8388 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -35,47 +35,8 @@ void sal_op_release(SalOp *op){ return ; } void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ - belle_sip_header_www_authenticate_t* authenticate; - belle_sip_header_authorization_t* authorization; - const char* ha1; - char computed_ha1[33]; - - if (info->ha1) { - ha1=info->ha1; - } else { - if(belle_sip_auth_helper_compute_ha1(info->userid,info->realm,info->password, computed_ha1)) { - goto error; - } else - ha1=computed_ha1; - } - if (!op->response) { - ms_error("try to authenticate an unchallenged op [%p]",op); - goto error; - } - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->response),BELLE_SIP_WWW_AUTHENTICATE)); - if (authenticate) { - authorization = belle_sip_auth_helper_create_authorization(authenticate); - } else { - /*proxy inerite from www*/ - authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->response),BELLE_SIP_PROXY_AUTHENTICATE)); - authorization = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_auth_helper_create_proxy_authorization(BELLE_SIP_HEADER_PROXY_AUTHENTICATE(authenticate))); - } - belle_sip_header_authorization_set_uri(authorization,belle_sip_request_get_uri(op->request)); - belle_sip_header_authorization_set_username(authorization,info->userid); - - if (belle_sip_auth_helper_fill_authorization(authorization - ,belle_sip_request_get_method(op->request) - ,ha1)) { - belle_sip_object_unref(authorization); - goto error; - } - belle_sip_message_set_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_HEADER(authorization)); - sal_op_resend_request(op,op->request); - return; - -error: - ms_error("cannot generate authorization for [%s] at [%s]",info->userid,info->realm); - + /*for sure auth info will be accesible from the provider*/ + sal_process_authentication(op, NULL); return ; } @@ -174,7 +135,7 @@ int sal_ping(SalOp *op, const char *from, const char *to){ 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(belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + if(user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { op->base.remote_ua=ms_strdup(user_agent_string); } } @@ -188,12 +149,26 @@ void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; - if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + if (!op->dialog || belle_sip_dialog_get_state(op->dialog)!=BELLE_SIP_DIALOG_CONFIRMED) { + /*don't put route header if dialog is in confirmed state*/ + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } } client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + /*in case DIALOG is in state NULL create a new dialog*/ + if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL) { + belle_sip_dialog_delete(op->dialog); + op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_dialog_set_application_data(op->dialog,op); + } else + 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); + } belle_sip_client_transaction_send_request(client_transaction); } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 20ec119a9..ae7a6e116 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -71,7 +71,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve expires=0; } - op->base.root->callbacks.register_success(op,expires_header&&expires>=0); + op->base.root->callbacks.register_success(op,expires>0); /*always cancel pending refresh if any*/ if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); @@ -106,8 +106,8 @@ static void send_register_request_with_expires(SalOp* op, belle_sip_request_t* r if (!expires_header && expires>=0) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); - belle_sip_header_expires_set_expires(expires_header,expires); } + if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); sal_op_send_request(op,request); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9ce4e1162..46975e732 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -795,8 +795,7 @@ static void ping_reply(SalOp *op){ } } -static bool_t fill_auth_info(SalOp*op, SalAuthInfo* sai) { - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); if (ai) { sai->userid=ai->userid?ai->userid:ai->username; @@ -808,14 +807,14 @@ static bool_t fill_auth_info(SalOp*op, SalAuthInfo* sai) { return FALSE; } } -static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - if (fill_auth_info(op,sai)) { +static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + if (fill_auth_info(lc,sai)) { return TRUE; } else { if (lc->vtable.auth_info_requested) { lc->vtable.auth_info_requested(lc,sai->realm,sai->username); - if (fill_auth_info(op,sai)) { + if (fill_auth_info(lc,sai)) { return TRUE; } } diff --git a/coreapi/friend.c b/coreapi/friend.c index 05a1baeec..d71dd25c6 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -198,8 +198,10 @@ 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){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 941b23516..543d7e9f2 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -236,7 +236,7 @@ typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); typedef void (*SalOnCallReleased)(SalOp *salop); typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); -typedef bool_t (*SalOnAuthRequested)(SalOp *salop,SalAuthInfo* info); +typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); diff --git a/tester/flexisip.conf b/tester/flexisip.conf old mode 100644 new mode 100755 index ffd6acf5f..5c1ee3ece --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -17,12 +17,12 @@ aliases=auth.example.org auth1.example.org auth2.example.org sip.example.org # The public ip address of the proxy. # Default value: guess -ip-address=guess +ip-address=auth.example.org # The local interface's ip address where to listen. The wildcard # (*) means all interfaces. # Default value: * -bind-address=sip.example.org +bind-address=auth.example.org # UDP/TCP port number to listen for sip messages. # Default value: 5060 @@ -45,7 +45,8 @@ port=5061 # The private key for TLS server must be in a agent.pem file within # this directory # Default value: /etc/flexisip/tls -certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip +#certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip +certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip ## @@ -249,7 +250,7 @@ routes= [module::MediaRelay] # Indicate whether the module is activated. # Default value: true -enabled=false +enabled=true # List of domain names in sip from allowed to enter the module. # Default value: * @@ -279,15 +280,15 @@ to-domains=* [module::Transcoder] # Indicate whether the module is activated. # Default value: false -enabled=true +enabled=false # List of domain names in sip from allowed to enter the module. # Default value: * -from-domains=freephonie.net +from-domains=* # List of domain names in sip to allowed to enter the module. # Default value: * -to-domains=freephonie.net +to-domains=* # Nominal size of RTP jitter buffer, in milliseconds. A value of # 0 means no jitter buffer (packet processing). @@ -330,4 +331,5 @@ to-domains=* # Default value: false rewrite-req-uri=false - +[dos-protection] +enabled=false diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 4f6ae1b16..4745dc4f0 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -55,58 +55,38 @@ static void linphone_address_test(void) { ms_free(create_linphone_address(NULL)); } -static int number_of_LinphoneRegistrationNone=0; -static int number_of_LinphoneRegistrationProgress =0; -static int number_of_LinphoneRegistrationOk =0; -static int number_of_LinphoneRegistrationCleared =0; -static int number_of_LinphoneRegistrationFailed =0; -static int number_of_auth_info_requested =0; +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 ; -static int number_of_LinphoneCallIncomingReceived=0; -static int number_of_LinphoneCallOutgoingInit=0; -static int number_of_LinphoneCallOutgoingProgress=0; -static int number_of_LinphoneCallOutgoingRinging=0; -static int number_of_LinphoneCallOutgoingEarlyMedia=0; -static int number_of_LinphoneCallConnected=0; -static int number_of_LinphoneCallStreamsRunning=0; -static int number_of_LinphoneCallPausing=0; -static int number_of_LinphoneCallPaused=0; -static int number_of_LinphoneCallResuming=0; -static int number_of_LinphoneCallRefered=0; -static int number_of_LinphoneCallError=0; -static int number_of_LinphoneCallEnd=0; -static int number_of_LinphoneCallPausedByRemote=0; -static int number_of_LinphoneCallUpdatedByRemote=0; -static int number_of_LinphoneCallIncomingEarlyMedia=0; -static int number_of_LinphoneCallUpdated=0; -static int number_of_LinphoneCallReleased=0; + 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_LinphoneCallUpdated; + int number_of_LinphoneCallReleased; +}stats; +static stats global_stat; -static void reset_counters() { - number_of_LinphoneRegistrationNone=0; - number_of_LinphoneRegistrationProgress =0; - number_of_LinphoneRegistrationOk =0; - number_of_LinphoneRegistrationCleared =0; - number_of_LinphoneRegistrationFailed =0; - number_of_auth_info_requested =0; - number_of_LinphoneCallIncomingReceived=0; - number_of_LinphoneCallOutgoingInit=0; - number_of_LinphoneCallOutgoingProgress=0; - number_of_LinphoneCallOutgoingRinging=0; - number_of_LinphoneCallOutgoingEarlyMedia=0; - number_of_LinphoneCallConnected=0; - number_of_LinphoneCallStreamsRunning=0; - number_of_LinphoneCallPausing=0; - number_of_LinphoneCallPaused=0; - number_of_LinphoneCallResuming=0; - number_of_LinphoneCallRefered=0; - number_of_LinphoneCallError=0; - number_of_LinphoneCallEnd=0; - number_of_LinphoneCallPausedByRemote=0; - number_of_LinphoneCallUpdatedByRemote=0; - number_of_LinphoneCallIncomingEarlyMedia=0; - number_of_LinphoneCallUpdated=0; - number_of_LinphoneCallReleased=0; +static void reset_counters( stats* counters) { + memset(counters,0,sizeof(stats)); } static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ @@ -114,12 +94,13 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo ,linphone_registration_state_to_string(cstate) ,linphone_proxy_config_get_identity(cfg) ,linphone_proxy_config_get_addr(cfg)); + stats* counters = (stats*)linphone_core_get_user_data(lc); switch (cstate) { - case LinphoneRegistrationNone:number_of_LinphoneRegistrationNone++;break; - case LinphoneRegistrationProgress:number_of_LinphoneRegistrationProgress++;break; - case LinphoneRegistrationOk:number_of_LinphoneRegistrationOk++;break; - case LinphoneRegistrationCleared:number_of_LinphoneRegistrationCleared++;break; - case LinphoneRegistrationFailed:number_of_LinphoneRegistrationFailed++;break; + case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; + case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; + case LinphoneRegistrationOk:counters->number_of_LinphoneRegistrationOk++;break; + case LinphoneRegistrationCleared:counters->number_of_LinphoneRegistrationCleared++;break; + case LinphoneRegistrationFailed:counters->number_of_LinphoneRegistrationFailed++;break; default: CU_FAIL("unexpected event");break; } @@ -129,17 +110,21 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo static LinphoneCore* create_lc() { LinphoneCoreVTable v_table; - + LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; - return linphone_core_new(&v_table,NULL,NULL,NULL); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + linphone_core_set_user_data(lc,&global_stat); + return lc; } + static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { int retry=0; LCSipTransports transport = {5070,5070,0,5071}; - reset_counters(); - CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + stats* counters = (stats*)linphone_core_get_user_data(lc); + reset_counters(counters); linphone_core_set_sip_transports(lc,&transport); LinphoneProxyConfig* proxy_cfg; @@ -163,100 +148,111 @@ static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* d linphone_core_add_proxy_config(lc,proxy_cfg); linphone_core_set_default_proxy(lc,proxy_cfg); - while (number_of_LinphoneRegistrationOk<1 && retry++ <20) { + while (counters->number_of_LinphoneRegistrationOk<1 && retry++ <20) { linphone_core_iterate(lc); ms_usleep(100000); } CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); if (refresh) { /*wait until refresh*/ - while (number_of_LinphoneRegistrationOk<2 && retry++ <310) { + while (counters->number_of_LinphoneRegistrationOk<2 && retry++ <310) { linphone_core_iterate(lc); ms_usleep(100000); } linphone_core_destroy(lc); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,2); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,2); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); } else { linphone_core_destroy(lc); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationProgress,1); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,1); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationCleared,1); - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); } } static void simple_register(){ - register_with_refresh(create_lc(),FALSE,NULL,NULL); - CU_ASSERT_EQUAL(number_of_auth_info_requested,0); + LinphoneCore* lc = create_lc(); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,FALSE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } static void simple_tcp_register(){ char route[256]; sprintf(route,"sip:%s;transport=tcp",test_domain); - register_with_refresh(create_lc(),FALSE,NULL,route); + LinphoneCore* lc = create_lc(); + register_with_refresh(lc,FALSE,NULL,route); } static void simple_tls_register(){ char route[256]; sprintf(route,"sip:%s;transport=tls",test_domain); - register_with_refresh(create_lc(),FALSE,NULL,route); + LinphoneCore* lc = create_lc(); + register_with_refresh(lc,FALSE,NULL,route); } static void simple_authenticated_register(){ LinphoneCore* lc = create_lc(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - + stats* counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh(lc,FALSE,auth_domain,NULL); - CU_ASSERT_EQUAL(number_of_auth_info_requested,0); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - number_of_auth_info_requested++; + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_auth_info_requested++; LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } static void authenticated_register_with_no_initial_credentials(){ - number_of_auth_info_requested=0; LinphoneCoreVTable v_table; LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; v_table.auth_info_requested=auth_info_requested; lc = linphone_core_new(&v_table,NULL,NULL,NULL); - + linphone_core_set_user_data(lc,&global_stat); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_auth_info_requested=0; register_with_refresh(lc,FALSE,auth_domain,NULL); - CU_ASSERT_EQUAL(number_of_auth_info_requested,1); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); } -static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { - +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count) { LinphoneCore* lc; int retry=0; + lc = linphone_core_new(v_table,NULL,file,NULL); + linphone_core_set_user_data(lc,&global_stat); + stats* counters = (stats*)linphone_core_get_user_data(lc); + linphone_core_set_ring(lc,"./share/rings/oldphone.wav"); + linphone_core_set_ringback(lc,"./share/ringback.wav"); - reset_counters(); - lc = linphone_core_new(v_table,NULL,"./multi_account_lrc",NULL); + reset_counters(counters); + CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count); - CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),3); - - while (number_of_LinphoneRegistrationOk<3 && retry++ <20) { + while (counters->number_of_LinphoneRegistrationOk<3 && retry++ <20) { linphone_core_iterate(lc); ms_usleep(100000); } - CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,3); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,proxy_count); return lc; } +static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { + return configure_lc_from(v_table,"./tester/multi_account_lrc",3); +} static void multiple_proxy(){ LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -266,28 +262,32 @@ static void multiple_proxy(){ linphone_core_destroy(lc); } static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ - char* to=linphone_call_get_remote_address_as_string(call); - ms_message("call from [??] to [%s], new state is [%s]",to,linphone_call_state_to_string(cstate)); + 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("call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(cstate)); ms_free(to); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); switch (cstate) { - case LinphoneCallIncomingReceived:number_of_LinphoneCallIncomingReceived++;break; - case LinphoneCallOutgoingInit :number_of_LinphoneCallOutgoingInit++;break; - case LinphoneCallOutgoingProgress :number_of_LinphoneCallOutgoingProgress++;break; - case LinphoneCallOutgoingRinging :number_of_LinphoneCallOutgoingRinging++;break; - case LinphoneCallOutgoingEarlyMedia :number_of_LinphoneCallOutgoingEarlyMedia++;break; - case LinphoneCallConnected :number_of_LinphoneCallConnected++;break; - case LinphoneCallStreamsRunning :number_of_LinphoneCallStreamsRunning++;break; - case LinphoneCallPausing :number_of_LinphoneCallPausing++;break; - case LinphoneCallPaused :number_of_LinphoneCallPaused++;break; - case LinphoneCallResuming :number_of_LinphoneCallResuming++;break; - case LinphoneCallRefered :number_of_LinphoneCallRefered++;break; - case LinphoneCallError :number_of_LinphoneCallError++;break; - case LinphoneCallEnd :number_of_LinphoneCallEnd++;break; - case LinphoneCallPausedByRemote :number_of_LinphoneCallPausedByRemote++;break; - case LinphoneCallUpdatedByRemote :number_of_LinphoneCallUpdatedByRemote++;break; - case LinphoneCallIncomingEarlyMedia :number_of_LinphoneCallIncomingEarlyMedia++;break; - case LinphoneCallUpdated :number_of_LinphoneCallUpdated++;break; - case LinphoneCallReleased :number_of_LinphoneCallReleased++;break; + 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 LinphoneCallUpdated :counters->number_of_LinphoneCallUpdated++;break; + case LinphoneCallReleased :counters->number_of_LinphoneCallReleased++;break; default: CU_FAIL("unexpected event");break; } @@ -301,25 +301,100 @@ static void simple_call_declined() { v_table.registration_state_changed=registration_state_changed; v_table.call_state_changed=call_state_changed; lc=configure_lc(&v_table); + stats* counters = (stats*)linphone_core_get_user_data(lc); linphone_core_invite(lc,"marie"); - while (number_of_LinphoneCallIncomingReceived<1 && retry++ <20) { + while (counters->number_of_LinphoneCallIncomingReceived<1 && retry++ <20) { linphone_core_iterate(lc); ms_usleep(100000); } - CU_ASSERT_EQUAL(number_of_LinphoneCallIncomingReceived,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneCallIncomingReceived,1); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc)); - linphone_core_terminate_call(lc,linphone_core_get_current_call(lc)); - CU_ASSERT_EQUAL(number_of_LinphoneCallReleased,1); + /*linphone_core_terminate_call(lc,linphone_core_get_current_call(lc));*/ + CU_ASSERT_EQUAL(counters->number_of_LinphoneCallReleased,1); linphone_core_destroy(lc); } +static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + int retry=0; + while (*counternext) { + linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); + } + PayloadType* pt; + if((pt = linphone_core_find_payload_type(lc,type,rate))) { + linphone_core_enable_payload_type(lc,pt, 1); + } +} +static void simple_call() { + LinphoneCoreVTable v_table_marie; + LinphoneCore* lc_marie; + LinphoneCoreVTable v_table_pauline; + LinphoneCore* lc_pauline; + stats stat_marie; + stats stat_pauline; + reset_counters(&stat_marie); + reset_counters(&stat_pauline); + + + + memset (&v_table_marie,0,sizeof(LinphoneCoreVTable)); + v_table_marie.registration_state_changed=registration_state_changed; + v_table_marie.call_state_changed=call_state_changed; + + lc_marie=configure_lc_from(&v_table_marie,"./tester/marie_rc",1); + enable_codec(lc_marie,"PCMU",8000); + linphone_core_set_user_data(lc_marie,&stat_marie); + + memset (&v_table_pauline,0,sizeof(LinphoneCoreVTable)); + v_table_pauline.registration_state_changed=registration_state_changed; + v_table_pauline.call_state_changed=call_state_changed; + + lc_pauline=configure_lc_from(&v_table_pauline,"./tester/pauline_rc",1); + linphone_core_set_user_data(lc_pauline,&stat_pauline); + + linphone_core_invite(lc_marie,"pauline"); + + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); + CU_ASSERT_EQUAL(stat_marie.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallOutgoingRinging,1)); + + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(lc_marie,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + + CU_ASSERT_STRING_EQUAL(linphone_proxy_config_get_identity(proxy),linphone_core_get_current_call_remote_address(lc_pauline)) + + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,1)); + /*just to sleep*/ + wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallEnd,1)); + + linphone_core_destroy(lc_marie); + linphone_core_destroy(lc_pauline); +} int init_test_suite () { -CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); +CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); + - if (NULL == CU_add_test(pSuite, "simple call declined", simple_call_declined)) { - return CU_get_error(); - } if (NULL == CU_add_test(pSuite, "linphone address tester", linphone_address_test)) { return CU_get_error(); } @@ -344,12 +419,19 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "simple_call_declined", simple_call_declined)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { int i; + char *test_name=NULL; + char *suite_name=NULL; for(i=1;i Date: Thu, 18 Oct 2012 16:47:36 +0200 Subject: [PATCH 010/909] implement call cancel/call reject --- .cproject | 26 +- coreapi/bellesip_sal/sal_impl.c | 28 +- coreapi/bellesip_sal/sal_impl.h | 2 + coreapi/bellesip_sal/sal_op_call.c | 111 +++++++- coreapi/bellesip_sal/sal_op_impl.c | 7 +- coreapi/linphonecore.c | 6 + tester/flexisip.conf | 415 ++++++++++++++++++++++------- tester/liblinphone_tester.c | 167 ++++++++---- 8 files changed, 576 insertions(+), 186 deletions(-) diff --git a/.cproject b/.cproject index 539e03aa9..beb21f7cb 100644 --- a/.cproject +++ b/.cproject @@ -81,6 +81,8 @@ + + @@ -133,6 +135,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -200,5 +225,4 @@ - diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 110a1b04f..f981afaa2 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -45,8 +45,14 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { } } -static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ - ms_error("process_dialog_terminated not implemented yet"); +static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ + belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_get_dialog(event); + SalOp* op = belle_sip_dialog_get_application_data(dialog); + if (op->callbacks.process_dialog_terminated) { + op->callbacks.process_dialog_terminated(op,event); + } else { + ms_error("sal process_dialog_terminated not implemented yet"); + } } static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); @@ -119,7 +125,10 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_request_t* old_request=NULL;; belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); - + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); } @@ -204,8 +213,13 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } case 401: case 407:{ - sal_process_authentication(op,response); - return; + if (op->state == SalOpStateTerminating) { + belle_sip_message("Op is in state terminating, nothing else to do"); + return; + } else { + sal_process_authentication(op,response); + return; + } } } op->callbacks.process_response_event(op,event); @@ -245,6 +259,7 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event } Sal * sal_init(){ char stack_string[64]; + belle_sip_listener_t* listener; Sal * sal=ms_new0(Sal,1); snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); @@ -260,7 +275,8 @@ Sal * sal_init(){ sal->listener_callbacks.process_timeout=process_timeout; sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; sal->listener_callbacks.process_auth_requested=process_auth_requested; - belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + belle_sip_provider_add_sip_listener(sal->prov,listener=belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + belle_sip_object_unref(listener); return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 309e779ba..695799d09 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -38,6 +38,7 @@ struct Sal{ typedef enum SalOpSate { SalOpStateEarly=0 ,SalOpStateActive + ,SalOpStateTerminating /*this state is used to wait until a procedding state, so we can send the cancel*/ ,SalOpStateTerminated }SalOpSate_t; @@ -52,6 +53,7 @@ struct SalOp{ belle_sip_request_t* request; belle_sip_response_t* response; belle_sip_server_transaction_t* pending_server_trans; + belle_sip_client_transaction_t* pending_inv_client_trans; SalAuthInfo auth_info; unsigned long int registration_refresh_timer; bool_t sdp_offering; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index d5a65b44c..94c9b4d94 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -83,6 +83,9 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } +static void process_dialog_terminated(void *op, const belle_sip_dialog_terminated_event_t *event) { + if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL; +} static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { @@ -91,6 +94,13 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { if (op->base.local_media) sdp_process(op); } } +static void cancelling_invite(SalOp* op ){ + belle_sip_request_t* cancel; + ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); + cancel = belle_sip_client_transaction_create_cancel(op->pending_inv_client_trans); + sal_op_send_request(op,cancel); + op->state=SalOpStateTerminated; +} static void call_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; @@ -154,9 +164,19 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } return; } + /*check if op is terminating*/ + dialog_state=belle_sip_dialog_get_state(op->dialog); + + if (op->state == SalOpStateTerminating + && (dialog_state==BELLE_SIP_DIALOG_NULL + || dialog_state==BELLE_SIP_DIALOG_EARLY)) { + cancelling_invite(op); + + return; + } /*else dialog*/ - dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { @@ -211,6 +231,21 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { ms_error("process_transaction_terminated not implemented yet"); } +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=belle_sip_response_create_from_request(request,status_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->state=SalOpStateTerminated; + return; +} +static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { + belle_sip_response_t* resp; + resp=belle_sip_response_create_from_request(request,500); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; +} + static void process_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)); @@ -223,7 +258,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_dialog_state_t dialog_state; belle_sdp_session_description_t* sdp; belle_sip_header_t* call_info; - belle_sip_response_t* resp; + if (!op->dialog) { op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_dialog_set_application_data(op->dialog,op); @@ -258,6 +293,30 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t break; } + case BELLE_SIP_DIALOG_EARLY: { + //hmm probably a cancel + if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) { + if(belle_sip_request_event_get_server_transaction(event)) { + /*first answer 200 ok to cancel*/ + belle_sip_server_transaction_send_response(server_transaction + ,belle_sip_response_create_from_request(req,200)); + /*terminate invite request*/ + call_terminated(op + ,belle_sip_request_event_get_server_transaction(event) + ,belle_sip_request_event_get_request(event),487); + + + } else { + /*call leg does not exist*/ + belle_sip_server_transaction_send_response(server_transaction + ,belle_sip_response_create_from_request(req,481)); + } + } else { + belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); + unsupported_method(server_transaction,belle_sip_request_event_get_request(event)); + } + break; + } case BELLE_SIP_DIALOG_CONFIRMED: /*great ACK received*/ if (strcmp("ACK",belle_sip_request_get_method(req))==0) { @@ -277,9 +336,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }*/ op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { - op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); - resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); - belle_sip_server_transaction_send_response(server_transaction,resp); + call_terminated(op,server_transaction,belle_sip_request_event_get_request(event),200); } else { ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); } @@ -305,9 +362,9 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* req; belle_sip_header_allow_t* header_allow; - belle_sip_client_transaction_t* client_transaction; +/* belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_header_route_t* route_header; + belle_sip_header_route_t* route_header;*/ op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); @@ -325,16 +382,17 @@ int sal_call(SalOp *op, const char *from, const char *to){ set_sdp_from_desc(BELLE_SIP_MESSAGE(req),op->base.local_media); }else op->sdp_offering=FALSE; - if (sal_op_get_route_address(op)) { +/* if (sal_op_get_route_address(op)) { route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); - } + }*/ sal_op_call_fill_cbs(op); - client_transaction = belle_sip_provider_create_client_transaction(prov,req); + sal_op_send_request(op,req); + /*op->pending_inv_client_trans = client_transaction = belle_sip_provider_create_client_transaction(prov,req); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_client_transaction_send_request(client_transaction); - + */ return 0; } void sal_op_call_fill_cbs(SalOp*op) { @@ -343,6 +401,7 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_timeout=call_process_timeout; op->callbacks.process_transaction_terminated=call_process_transaction_terminated; op->callbacks.process_request_event=process_request_event; + op->callbacks.process_dialog_terminated=process_dialog_terminated; } int sal_call_notify_ringing(SalOp *op, bool_t early_media){ belle_sip_response_t* ringing_response; @@ -414,6 +473,9 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti case SalReasonMedia: status=415; break; + case SalReasonDeclined: + status=603; + break; case SalReasonRedirect: if(redirection!=NULL) { if (strstr(redirection,"sip:")!=0) status=302; @@ -483,12 +545,35 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ } int sal_call_terminate(SalOp *op){ belle_sip_dialog_state_t dialog_state=belle_sip_dialog_get_state(op->dialog); - + op->state=SalOpStateTerminating; switch(dialog_state) { case BELLE_SIP_DIALOG_CONFIRMED: { sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + op->state=SalOpStateTerminated; + break; + } + case BELLE_SIP_DIALOG_NULL: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else if (op->pending_inv_client_trans + && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_inv_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ + cancelling_invite(op); + break; + } else { + ms_error("Don't know how to termination NUL dialog [%p]",op->dialog); + } + break; + } + case BELLE_SIP_DIALOG_EARLY: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else { + cancelling_invite(op); + } + break; } - break; default: { ms_fatal("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); return -1; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 2de7d8388..f61ff5ab7 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -159,12 +159,11 @@ void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); /*in case DIALOG is in state NULL create a new dialog*/ - if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL) { - belle_sip_dialog_delete(op->dialog); + if (!op->dialog && strcmp("INVITE",belle_sip_request_get_method(request))==0) { op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); + op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_dialog_set_application_data(op->dialog,op); - } else - if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) + } else 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); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f64edcb83..41e666f47 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3548,6 +3548,9 @@ const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc){ **/ void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){ lc->video_conf.show_local=val; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc)); + } } /** @@ -3570,6 +3573,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); } diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 5c1ee3ece..61d55fb2f 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -10,44 +10,39 @@ # Default value: false debug=false +# 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=auth.example.org auth1.example.org auth2.example.org sip.example.org +aliases=localhost -# The public ip address of the proxy. -# Default value: guess -ip-address=auth.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:* sips:* -# The local interface's ip address where to listen. The wildcard -# (*) means all interfaces. -# Default value: * -bind-address=auth.example.org - -# UDP/TCP port number to listen for sip messages. -# Default value: 5060 -port=5060 - - -## -## TLS specific parameters. -## -[tls] -# Enable SIP/TLS (sips) -# Default value: true -enabled=true - -# The port used for SIP/TLS -# Default value: 5061 -port=5061 - -# An absolute path of a directory where TLS certificate can be found. -# The private key for TLS server must be in a agent.pem file within -# this directory +# 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 -#certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip -certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip - +#tls-certificates-dir=/etc/flexisip/tls +tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip ## ## STUN server parameters. @@ -57,10 +52,43 @@ certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip # Default value: true enabled=true +# Local ip address where to bind the socket. +# Default value: 0.0.0.0 +bind-address=0.0.0.0 + # STUN server port number. # Default value: 3478 port=3478 +## +## DOS protection parameters. +## +[dos-protection] +# Enable or disable DOS protection using IPTables firewall. +# Default value: false +enabled=false + +# List of whitelist IPs which won't be affected by DOS protection. +# Default value: 127.0.0.1 +authorized-ip=127.0.0.1 + +# Local ports to protect. +# Default value: 5060 +port=5060 + +# Time (in seconds) while an IP have to not send any packet in order +# to leave the blacklist. +# Default value: 60 +ban-duration=60 + +# Number of packets authorized in 1sec before considering them as +# DOS attack. +# Default value: 20 +packets-limit=20 + +# Maximal amount of simultaneous connections to accept. +# Default value: 1000 +maximum-connections=1000 ## ## The NatHelper module executes small tasks to make SIP work smoothly @@ -72,16 +100,19 @@ port=3478 [module::NatHelper] # Indicate whether the module is activated. # Default value: true -enabled=false +enabled=true -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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 @@ -92,18 +123,17 @@ to-domains=* # Default value: false enabled=true -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=auth.example.org auth1.example.org auth2.example.org - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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 whitespace separated domain names to challenge. Others # are denied. # Default value: -auth-domains=auth.example.org auth1.example.org auth2.example.org +auth-domains= auth.example.org # List of whitespace separated IP which will not be challenged. # Default value: @@ -114,14 +144,16 @@ trusted-hosts= 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=localhost;DATABASE=dbname;USER=username;PASSWORD=passname;OPTION=3; +# 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=./userdb.conf -# Odbc SQL request to execute to obtain the password. Named parameters -# are :id, :domain and :authid.' +# 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 @@ -160,12 +192,52 @@ cache-expire=1800 # Default value: true immediate-retrieve-password=true -# True if the passwords retrieved from the database are already -# SIP hashed (HA1=MD5(A1)=MD5(username:realm:password)). +# True if retrieved passwords from the database are hashed. HA1=MD5(A1) +# = MD5(username:realm:pass). # Default value: false hashed-passwords=false +# When receiving a proxy authenticate challenge, generate a new +# challenge for this proxy. +# Default value: false +new-auth-on-407=false +## +## ... +## +[module::GatewayAdapter] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# A gateway uri where to send all requests, as a SIP url (eg 'sip:gateway.example.net') +# Default value: +gateway= + +# Modify the from and to domains of incoming register +# Default value: +gateway-domain= + +# The gateway will be added to the incoming register contacts. +# Default value: true +fork-to-gateway=true + +# Send a REGISTER to the gateway using this server as a contact +# in order to be notified on incoming calls by the gateway. +# Default value: true +register-on-gateway=true + +# Parameter name hosting the incoming domain that will be sent in +# the register to the gateway. +# Default value: routing-domain +routing-param=routing-domain ## ## The Registrar module accepts REGISTERs for domains it manages, @@ -177,19 +249,135 @@ hashed-passwords=false # Default value: true enabled=true -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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=auth.example.org auth1.example.org auth2.example.org sip.example.org +reg-domains=localhost auth.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: line +unique-id-parameters=line + +# Maximum expire time for a REGISTER, in seconds. +# Default value: 86400 +max-expires=86400 + +# Minimum expire time for a REGISTER, in seconds. +# Default value: 60 +min-expires=60 + +# 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 + +# Store and retrieve contacts without using the domain. +# Default value: false +use-global-domain=false + +# Fork messages to all registered devices +# Default value: true +fork=true + +# Force forking and thus the creation of an outgoing transaction +# even when only one contact found +# Default value: true +stateful=true + +# Fork invites to late registers +# Default value: false +fork-late=false + +# Only forward one response of forked invite to the caller +# Default value: true +fork-one-response=true + +# All the forked have to decline in order to decline the caller +# invite +# Default value: false +fork-no-global-decline=false + +# Maximum duration for delivering a message (text) +# Default value: 3600 +message-delivery-timeout=3600 + +# Generate a contact from the TO header and route it to the above +# destination. [sip:host:port] +# Default value: +generated-contact-route= + +# Require presence of authorization header for specified realm. +# [Realm] +# Default value: +generated-contact-expected-realm= + +## +## This module performs push notifications +## +[module::PushNotification] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Number of second to wait before sending a push notification to +# device(if <=0 then disabled) +# Default value: 5 +timeout=5 + +# Maximum number of notifications queued for each client +# Default value: 10 +max-queue-size=10 + +# Enable push notification for apple devices +# Default value: true +apple=true + +# Path to directory where to find Apple Push Notification service +# certificates. They should bear the appid of the application, suffixed +# by the release mode and .pem extension. For example: org.linphone.dev.pem +# org.linphone.prod.pem com.somephone.dev.pem etc... The files should +# be .pem format, and made of certificate followed by private key. +# Default value: /etc/flexisip/apn +apple-certificate-dir=/etc/flexisip/apn + +# Enable push notification for android devices +# Default value: true +google=true + +# List of couple projectId:ApiKey for each android project which +# support push notifications +# Default value: +google-projects-api-keys= ## ## The purpose of the ContactRouteInserter module is to masquerade @@ -204,19 +392,17 @@ reg-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org # Default value: true enabled=false -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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. @@ -226,20 +412,18 @@ masquerade-contacts-for-invites=false # Default value: false enabled=false -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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 @@ -250,16 +434,41 @@ routes= [module::MediaRelay] # Indicate whether the module is activated. # Default value: true -enabled=true +enabled=false -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* +# 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 domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# SDP attribute set by the first proxy to forbid subsequent proxies +# to provide relay. +# Default value: nortpproxy +nortpproxy=nortpproxy +# Set the RTP direction during early media state (duplex, forward) +# Default value: duplex +early-media-rtp-dir=duplex + +# The minimal value of SDP port range +# Default value: 1024 +sdp-port-range-min=1024 + +# The maximal value of SDP port range +# Default value: 65535 +sdp-port-range-max=65535 + +# Enable I-frame only filtering for video H264 for clients annoucing +# a total bandwith below this value expressed in kbit/s. Use 0 to +# disable the feature +# Default value: 0 +h264-filtering-bandwidth=0 + +# When above option is activated, keep one I frame over this number. +# Default value: 1 +h264-iframe-decim=1 ## ## The purpose of the Transcoder module is to transparently transcode @@ -282,13 +491,12 @@ to-domains=* # Default value: false enabled=false -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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). @@ -302,9 +510,13 @@ 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 telephone-event/8000 -audio-codecs=amr/8000 pcmu/8000 pcma/8000 telephone-event/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 @@ -315,21 +527,18 @@ audio-codecs=amr/8000 pcmu/8000 pcma/8000 telephone-event/8000 # Default value: true enabled=true -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* - -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# 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= +route= # Rewrite request-uri's host and port according to above route # Default value: false rewrite-req-uri=false -[dos-protection] -enabled=false diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 4745dc4f0..417319d24 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -292,28 +292,7 @@ static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCal CU_FAIL("unexpected event");break; } } -static void simple_call_declined() { - LinphoneCoreVTable v_table; - LinphoneCore* lc; - int retry=0; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - v_table.call_state_changed=call_state_changed; - lc=configure_lc(&v_table); - stats* counters = (stats*)linphone_core_get_user_data(lc); - linphone_core_invite(lc,"marie"); - - while (counters->number_of_LinphoneCallIncomingReceived<1 && retry++ <20) { - linphone_core_iterate(lc); - ms_usleep(100000); - } - CU_ASSERT_EQUAL(counters->number_of_LinphoneCallIncomingReceived,1); - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc)); - /*linphone_core_terminate_call(lc,linphone_core_get_current_call(lc));*/ - CU_ASSERT_EQUAL(counters->number_of_LinphoneCallReleased,1); - linphone_core_destroy(lc); -} static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counterv_table.registration_state_changed=registration_state_changed; + mgr->v_table.call_state_changed=call_state_changed; + + mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); + enable_codec(mgr->lc,"PCMU",8000); + linphone_core_set_user_data(mgr->lc,&mgr->stat); + return mgr; +} +static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { + linphone_core_destroy(mgr->lc); + free(mgr); +} static void simple_call() { - LinphoneCoreVTable v_table_marie; - LinphoneCore* lc_marie; - LinphoneCoreVTable v_table_pauline; - LinphoneCore* lc_pauline; - stats stat_marie; - stats stat_pauline; - reset_counters(&stat_marie); - reset_counters(&stat_pauline); + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; - memset (&v_table_marie,0,sizeof(LinphoneCoreVTable)); - v_table_marie.registration_state_changed=registration_state_changed; - v_table_marie.call_state_changed=call_state_changed; - - lc_marie=configure_lc_from(&v_table_marie,"./tester/marie_rc",1); - enable_codec(lc_marie,"PCMU",8000); - linphone_core_set_user_data(lc_marie,&stat_marie); - - memset (&v_table_pauline,0,sizeof(LinphoneCoreVTable)); - v_table_pauline.registration_state_changed=registration_state_changed; - v_table_pauline.call_state_changed=call_state_changed; - - lc_pauline=configure_lc_from(&v_table_pauline,"./tester/pauline_rc",1); - linphone_core_set_user_data(lc_pauline,&stat_pauline); - linphone_core_invite(lc_marie,"pauline"); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie.number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallOutgoingRinging,1)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(lc_marie,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - - CU_ASSERT_STRING_EQUAL(linphone_proxy_config_get_identity(proxy),linphone_core_get_current_call_remote_address(lc_pauline)) + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallStreamsRunning,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); /*just to sleep*/ - wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,3); + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); - linphone_core_destroy(lc_marie); - linphone_core_destroy(lc_pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_ringing_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_early_declined() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + LinphoneCall* in_call=linphone_core_get_current_call(marie->lc); + linphone_call_ref(in_call); + + linphone_core_terminate_call(marie->lc,in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(in_call); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); } int init_test_suite () { @@ -419,7 +459,13 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } - if (NULL == CU_add_test(pSuite, "simple_call_declined", simple_call_declined)) { + if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { return CU_get_error(); } if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { @@ -441,6 +487,9 @@ int main (int argc, char *argv[]) { }else if (strcmp(argv[i],"--domain")==0){ i++; test_domain=argv[i]; + } else if (strcmp(argv[i],"--auth-domain")==0){ + i++; + auth_domain=argv[i]; }else if (strcmp(argv[i],"--test")==0){ i++; test_name=argv[i]; From 38898c611392050c14c8be0856b7c5a1d3eb74d2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 25 Oct 2012 11:12:26 +0200 Subject: [PATCH 011/909] implements re-invite on belle-sip --- .cproject | 11 ++- coreapi/bellesip_sal/sal_impl.c | 2 +- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call.c | 87 ++++++++++++++--------- coreapi/bellesip_sal/sal_op_impl.c | 4 +- coreapi/bellesip_sal/sal_sdp.c | 18 +++++ tester/flexisip.conf | 10 +-- tester/liblinphone_tester.c | 108 ++++++++++++++++++++++++++++- tester/marie_rc | 8 +-- tester/pauline_rc | 8 +-- 10 files changed, 203 insertions(+), 55 deletions(-) diff --git a/.cproject b/.cproject index beb21f7cb..da5a8e1df 100644 --- a/.cproject +++ b/.cproject @@ -56,7 +56,7 @@ - + @@ -77,8 +77,13 @@ - - + + + + + + + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f981afaa2..cb22d53f9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -276,7 +276,7 @@ Sal * sal_init(){ sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; sal->listener_callbacks.process_auth_requested=process_auth_requested; belle_sip_provider_add_sip_listener(sal->prov,listener=belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); - belle_sip_object_unref(listener); + /* belle_sip_callbacks_t is unowned, why ?belle_sip_object_unref(listener);*/ return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 695799d09..069b3934a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -76,7 +76,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method); void sal_op_call_fill_cbs(SalOp*op); void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); -void sal_op_send_request(SalOp* op, belle_sip_request_t* request); +int sal_op_send_request(SalOp* op, belle_sip_request_t* request); void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 94c9b4d94..91006ae0d 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -194,8 +194,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { - case SalOpStateEarly: - handle_sdp_from_response(op,response); + case SalOpStateEarly:/*invite case*/ + case SalOpStateActive: /*re-invite case*/ + 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."); @@ -207,9 +208,10 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); + op->state=SalOpStateActive; op->base.root->callbacks.call_accepted(op); break; - case SalOpStateActive: + case SalOpStateTerminated: default: ms_error("op [%p] receive answer [%i] not implemented",op,code); @@ -246,17 +248,27 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio return; } +static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { + belle_sdp_session_description_t* sdp; + if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) { + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + belle_sip_object_unref(sdp); + }else + op->sdp_offering=TRUE; +} static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); 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; - + belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_header_t* replace_header; belle_sip_dialog_state_t dialog_state; - belle_sdp_session_description_t* sdp; + belle_sip_header_t* call_info; if (!op->dialog) { @@ -274,13 +286,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else if(op->replaces) { ms_warning("replace header already set"); } - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))) { - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - belle_sip_object_unref(sdp); - }else - op->sdp_offering=TRUE; + + process_sdp_for_invite(op,req); if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { @@ -337,6 +344,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { call_terminated(op,server_transaction,belle_sip_request_event_get_request(event),200); + } else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) { + /*re-invite*/ + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=NULL; + } + if (op->result){ + sal_media_description_unref(op->result); + op->result=NULL; + } + process_sdp_for_invite(op,req); + + op->base.root->callbacks.call_updating(op); } else { ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); } @@ -359,9 +379,24 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ op->base.local_media=desc; return 0; } +static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { + belle_sip_header_allow_t* header_allow; + header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(header_allow)); + + if (op->base.root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); + } + if (op->base.local_media){ + op->sdp_offering=TRUE; + set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media); + }else op->sdp_offering=FALSE; + return; +} int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* req; - belle_sip_header_allow_t* header_allow; + /* belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header;*/ @@ -370,22 +405,9 @@ int sal_call(SalOp *op, const char *from, const char *to){ sal_op_set_to(op,to); req=sal_op_build_request(op,"INVITE"); - header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(header_allow)); - if (op->base.root->session_expires!=0){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Session-expires", "200")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Supported", "timer")); - } - if (op->base.local_media){ - op->sdp_offering=TRUE; - set_sdp_from_desc(BELLE_SIP_MESSAGE(req),op->base.local_media); - }else op->sdp_offering=FALSE; + sal_op_fill_invite(op,req); -/* if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); - }*/ sal_op_call_fill_cbs(op); sal_op_send_request(op,req); /*op->pending_inv_client_trans = client_transaction = belle_sip_provider_create_client_transaction(prov,req); @@ -499,13 +521,14 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti return 0; } -int sal_call_update(SalOp *h, const char *subject){ - ms_fatal("sal_call_update not implemented yet"); - return -1; +int sal_call_update(SalOp *op, const char *subject){ + belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); + sal_op_fill_invite(op, reinvite); + return sal_op_send_request(op,reinvite); } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - ms_fatal("sal_call_get_remote_media_description not implemented yet"); - return NULL; + return h->base.remote_media;; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index f61ff5ab7..a178ade97 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -145,7 +145,7 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,request); } -void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { +int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; @@ -168,6 +168,6 @@ void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL); } - belle_sip_client_transaction_send_request(client_transaction); + return belle_sip_client_transaction_send_request(client_transaction); } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 7a2f918f1..482bab472 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -29,6 +29,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip MSList* pt_it; PayloadType* pt; char buffer[1024]; + char* dir; if (strchr(desc->addr,':')!=NULL){ inet6=1; @@ -114,6 +115,23 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip } } + switch(desc->streams[i].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)); + belle_sdp_session_description_add_media_description(session_desc,media_desc); } diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 61d55fb2f..b9d5b94a0 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -18,7 +18,7 @@ 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 +aliases=localhost sipopen.example.org sip.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' @@ -36,7 +36,7 @@ aliases=localhost # '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:* sips:* +transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 # An absolute path of a directory where TLS server certificate and # private key can be found, concatenated inside an 'agent.pem' file. @@ -128,12 +128,12 @@ enabled=true # in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') # && (user-agent == 'Linphone v2') # Default value: -filter= +filter= from.uri.domain contains 'sip.example.org' # List of whitespace separated domain names to challenge. Others # are denied. # Default value: -auth-domains= auth.example.org +auth-domains= sip.example.org # List of whitespace separated IP which will not be challenged. # Default value: @@ -259,7 +259,7 @@ filter= # List of whitelist separated domain names to be managed by the # registrar. # Default value: localhost -reg-domains=localhost auth.example.org +reg-domains=localhost sip.example.org sipopen.example.org # Maximum number of registered contacts of an address of record. # Default value: 15 diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 417319d24..def062827 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -19,8 +19,8 @@ #include "CUnit/Basic.h" #include "linphonecore.h" -const char *test_domain="sip.example.org"; -const char *auth_domain="auth.example.org"; +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"; @@ -335,6 +335,39 @@ static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); free(mgr); } + +static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(callee_mgr->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* dest_identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(dest_identity); + + CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,dest_identity)); + linphone_address_destroy(dest_identity); + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallOutgoingRinging,1)); + + linphone_core_get_default_proxy(caller_mgr->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + linphone_address_destroy(identity); + + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); + /*just to sleep*/ + return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,1) + && + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,1); + +} static void simple_call() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -430,6 +463,67 @@ static void call_early_declined() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void call_terminated_by_caller() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_paused_resumed() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(pauline->lc); + + linphone_core_pause_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + + linphone_core_resume_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_srtp() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); @@ -471,7 +565,15 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/marie_rc b/tester/marie_rc index 2a808a7cd..b0cb5c761 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -9,13 +9,13 @@ ping_with_options=0 username=marie userid=marie passwd=secret -realm="auth.example.org" +realm="sip.example.org" [proxy_0] -reg_proxy=auth.example.org;transport=tcp -reg_route=auth.example.org;transport=tcp;lr -reg_identity=sip:marie@auth.example.org +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 diff --git a/tester/pauline_rc b/tester/pauline_rc index 455683cc6..cba6b564f 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -9,13 +9,13 @@ ping_with_options=0 username=pauline userid=pauline passwd=secret -realm="auth.example.org" +realm="sip.example.org" [proxy_0] -reg_proxy=auth.example.org;transport=tls -reg_route=auth.example.org;transport=tls;lr -reg_identity=sip:pauline@auth.example.org +reg_proxy=sip.example.org;transport=tls +reg_route=sip.example.org;transport=tls;lr +reg_identity=sip:pauline@sip.example.org reg_expires=3600 reg_sendregister=1 publish=0 From 2cf1e6d964537e2a0543082af7d3036f1caf9874 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sun, 4 Nov 2012 20:16:35 +0100 Subject: [PATCH 012/909] implement text messaging --- .cproject | 6 +++++ coreapi/Makefile.am | 3 ++- coreapi/bellesip_sal/sal_impl.c | 30 ++++++++++++++++++--- coreapi/bellesip_sal/sal_op_impl.c | 6 +---- tester/flexisip.conf | 6 +++-- tester/liblinphone_tester.c | 42 +++++++++++++++++++++++++----- tester/marie_rc | 1 + tester/pauline_rc | 1 + 8 files changed, 77 insertions(+), 18 deletions(-) diff --git a/.cproject b/.cproject index da5a8e1df..c44aac2bb 100644 --- a/.cproject +++ b/.cproject @@ -34,6 +34,9 @@ + + + @@ -69,6 +72,9 @@ + + + diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 028db827c..61ee670a0 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -45,7 +45,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_impl.c \ bellesip_sal/sal_op_call.c \ bellesip_sal/sal_op_registration.c \ - bellesip_sal/sal_sdp.c + bellesip_sal/sal_sdp.c \ + bellesip_sal/sal_op_message.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index cb22d53f9..855596610 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -63,8 +63,12 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); belle_sip_header_address_t* origin_address; belle_sip_header_address_t* address; - belle_sip_header_from_t* from; + belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; + belle_sip_header_content_type_t* content_type; + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + + char* from; if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); @@ -72,18 +76,36 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); + } else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) { + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + if (content_type + && strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0) { + 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)); + ((Sal*)sal)->callbacks.text_received((Sal*)sal,from,belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))); + belle_sip_object_unref(address); + belle_sip_free(from); + return; + } else { + ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) + ,belle_sip_header_content_type_get_subtype(content_type)); + return; + } } else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); return; } if (!op->base.from_address) { - from=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); sal_op_set_from_address(op,(SalAddress*)address); belle_sip_object_unref(address); } + + if (!op->base.to_address) { to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a178ade97..5cce9bb1a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -87,11 +87,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { } -/*Messaging */ -int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ - ms_fatal("sal_text_send not implemented yet"); - return -1; -} + /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ diff --git a/tester/flexisip.conf b/tester/flexisip.conf index b9d5b94a0..22acf0937 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -36,13 +36,15 @@ aliases=localhost sipopen.example.org sip.example.org # 'sip.linphone.org' used in SIP messages. Bind address won't appear: # transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 # Default value: sip:* -transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 +#transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 +transports=sip:127.0.0.1:5060 sips:127.0.0.1:5061 # 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 -tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip +#tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip +tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip ## ## STUN server parameters. diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index def062827..23c50f88b 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -82,6 +82,8 @@ typedef struct _stats { int number_of_LinphoneCallIncomingEarlyMedia; int number_of_LinphoneCallUpdated; int number_of_LinphoneCallReleased; + + int number_of_LinphoneMessageReceived; }stats; static stats global_stat; @@ -243,7 +245,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* reset_counters(counters); CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count); - while (counters->number_of_LinphoneRegistrationOk<3 && retry++ <20) { + while (counters->number_of_LinphoneRegistrationOknumber_of_LinphoneMessageReceived++; +} + static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counterv_table.registration_state_changed=registration_state_changed; mgr->v_table.call_state_changed=call_state_changed; - + mgr->v_table.text_received=text_message_received; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); + linphone_core_get_default_proxy(mgr->lc,&proxy); + mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(mgr->identity); return mgr; } static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); + linphone_address_destroy(mgr->identity); free(mgr); } @@ -340,11 +357,10 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - LinphoneAddress* dest_identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - linphone_address_clean(dest_identity); - CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,dest_identity)); - linphone_address_destroy(dest_identity); + + CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); @@ -523,6 +539,17 @@ static void call_srtp() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void text_message() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} int init_test_suite () { @@ -574,6 +601,9 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "text_message", text_message)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/marie_rc b/tester/marie_rc index b0cb5c761..95c30a0e1 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -4,6 +4,7 @@ sip_tcp_port=5082 sip_tls_port=5083 default_proxy=0 ping_with_options=0 +register_only_when_network_is_up=0 [auth_info_0] username=marie diff --git a/tester/pauline_rc b/tester/pauline_rc index cba6b564f..07e0efa25 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -4,6 +4,7 @@ sip_tcp_port=5072 sip_tls_port=5073 default_proxy=0 ping_with_options=0 +register_only_when_network_is_up=0 [auth_info_0] username=pauline From 6c323ddc08f92344d00a8cfd358da846b6f7c471 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sun, 4 Nov 2012 20:25:52 +0100 Subject: [PATCH 013/909] add missing file --- coreapi/bellesip_sal/sal_op_message.c | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 coreapi/bellesip_sal/sal_op_message.c diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c new file mode 100644 index 000000000..f1c22de73 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -0,0 +1,39 @@ +/* +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 message_response_event(void *op_base, const belle_sip_response_event_t *event){ + /*nop for futur use*/ +} + +int sal_text_send(SalOp *op, const char *from, const char *to, const char *text){ + belle_sip_request_t* req; + size_t content_length = strlen(text); + if (!op->callbacks.process_response_event) + op->callbacks.process_response_event=message_response_event; + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + req=sal_op_build_request(op,"MESSAGE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_create("text","plain"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),text,content_length); + return sal_op_send_request(op,req); +} From 510f3b7200039ced8023d37e9802ebe9c45d7556 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 13 Dec 2012 18:05:16 +0100 Subject: [PATCH 014/909] implement presence --- .cproject | 2 +- coreapi/Makefile.am | 3 +- coreapi/bellesip_sal/sal_impl.c | 28 +- coreapi/bellesip_sal/sal_impl.h | 6 + coreapi/bellesip_sal/sal_op_impl.c | 103 ++-- coreapi/bellesip_sal/sal_op_presence.c | 628 +++++++++++++++++++++ coreapi/bellesip_sal/sal_op_registration.c | 8 +- coreapi/friend.c | 3 +- coreapi/sal.c | 15 + coreapi/sal.h | 2 + tester/liblinphone_tester.c | 58 +- tester/marie_rc | 5 + tester/pauline_rc | 5 + 13 files changed, 817 insertions(+), 49 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_presence.c diff --git a/.cproject b/.cproject index c44aac2bb..83757a0eb 100644 --- a/.cproject +++ b/.cproject @@ -59,7 +59,7 @@ - + diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 61ee670a0..3e56f1b48 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -46,7 +46,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_call.c \ bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_sdp.c \ - bellesip_sal/sal_op_message.c + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 855596610..b9cdd0b61 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -35,12 +35,28 @@ static void sal_add_pending_auth(Sal *sal, SalOp *op){ } void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_AUTHORIZATION); - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_PROXY_AUTHORIZATION); - if (belle_sip_provider_add_authorization(op->base.root->prov,op->request,response)) { - sal_op_resend_request(op,op->request); + belle_sip_request_t* request; + bool_t is_within_dialog=FALSE; + if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { + request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)op->request); + is_within_dialog=TRUE; + } else { + request=op->request; + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); + + } + if (belle_sip_provider_add_authorization(op->base.root->prov,request,response)) { + if (is_within_dialog) { + sal_op_resend_request(op,request); + } else { + sal_op_send_request(op,request); + } }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); + if (is_within_dialog) { + belle_sip_object_unref(request); + } sal_add_pending_auth(op->base.root,op); } @@ -76,6 +92,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); + } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { + op=sal_op_new((Sal*)sal); + op->dir=SalOpDirIncoming; + sal_op_presence_fill_cbs(op); } else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) { content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); if (content_type diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 069b3934a..1b036cc92 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -66,6 +66,7 @@ struct SalOp{ bool_t supports_session_timers; SalOpSate_t state; SalOpDir_t dir; + belle_sip_refresher_t* refresher; }; belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); @@ -80,4 +81,9 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request); void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); +bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); + +/*presence*/ +void sal_op_presence_fill_cbs(SalOp*op); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 5cce9bb1a..a79d179ce 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -88,40 +88,6 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { - -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ - ms_fatal("sal_subscribe_presence not implemented yet"); - return -1; -} -int sal_unsubscribe(SalOp *op){ - ms_fatal("sal_unsubscribe not implemented yet"); - return -1; -} -int sal_subscribe_accept(SalOp *op){ - ms_fatal("sal_subscribe_accept not implemented yet"); - return -1; -} -int sal_subscribe_decline(SalOp *op){ - ms_fatal("sal_subscribe_decline not implemented yet"); - return -1; -} -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ - ms_fatal("sal_notify_presence not implemented yet"); - return -1; -} -int sal_notify_close(SalOp *op){ - ms_fatal("sal_notify_close not implemented yet"); - return -1; -} - -/*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ - ms_fatal("sal_publish not implemented yet"); - return -1; -} - - /*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to){ ms_fatal("sal_ping not implemented yet"); @@ -141,6 +107,11 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,request); } +static bool_t is_request_creating_dialog(belle_sip_request_t* request) { + return strcmp("INVITE",belle_sip_request_get_method(request))==0 + || + strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0; +} int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; @@ -155,7 +126,7 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); /*in case DIALOG is in state NULL create a new dialog*/ - if (!op->dialog && strcmp("INVITE",belle_sip_request_get_method(request))==0) { + if (!op->dialog && is_request_creating_dialog(request)) { op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_dialog_set_application_data(op->dialog,op); @@ -167,3 +138,65 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { return belle_sip_client_transaction_send_request(client_transaction); } +/*return TRUE if error code*/ +bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { + int code = belle_sip_response_get_status_code(response); + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + *sal_err=SalErrorUnknown; + *sal_reason = SalReasonUnknown; + + if (reason_header){ + snprintf(reason + ,reason_size + ,"%s %s" + ,belle_sip_response_get_reason_phrase(response) + ,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); + } else { + strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); + } + if (code >=400) { + switch(code) { + case 400: + *sal_err=SalErrorUnknown; + break; + case 404: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNotFound; + break; + case 415: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonMedia; + break; + case 422: + ms_error ("422 not implemented yet");; + break; + case 480: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonTemporarilyUnavailable; + break; + case 486: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonBusy; + break; + case 487: + break; + case 600: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDoNotDisturb; + break; + case 603: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDeclined; + break; + default: + if (code>0){ + *sal_err=SalErrorFailure; + *sal_reason=SalReasonUnknown; + }else *sal_err=SalErrorNoResponse; + /* no break */ + } + return TRUE; + } else { + return FALSE; + } +} diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c new file mode 100644 index 000000000..6cb1762b6 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -0,0 +1,628 @@ +/* +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" + +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; + +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_info(belle_sip_message_t *notify, SalPresenceStatus online_status) { + char buf[1000]; + char *contact_info; + size_t content_length; + + 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))); + mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); + + + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application",presence_style?"xpidf+xml":"pidf+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(buf)))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),buf,content_length); + ms_free(contact_info); +} + +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 *op, const belle_sip_dialog_terminated_event_t *event) { + if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL; +} + +static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + belle_sip_dialog_state_t dialog_state; + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_response_t* response=belle_sip_response_event_get_response(event); + belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + int code = belle_sip_response_get_status_code(response); + char reason[256]={0}; + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + belle_sip_header_expires_t* expires; + if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { + ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); + op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); + 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("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); + } + if (expires>0){ + op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); + } + } + 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("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_error("presence_process_timeout not implemented yet"); +} +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_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);; + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + SalPresenceStatus estatus=SalPresenceOffline; + SalSubscribeState sub_state; + belle_sip_response_t* resp; + 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) { + 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); + ms_message("new incoming subscription 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: { + op->base.root->callbacks.subscribe_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 ",belle_sip_request_get_method(req),op->dialog); + break; + + case BELLE_SIP_DIALOG_CONFIRMED: + if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + if (body==NULL){ + ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); + return; + } + if (strstr(body,"pending")!=NULL){ + estatus=SalPresenceOffline; + }else if (strstr(body,"busy")!=NULL){ + estatus=SalPresenceBusy; + }else if (strstr(body,"berightback")!=NULL + || strstr(body,"in-transit")!=NULL ){ + estatus=SalPresenceBerightback; + }else if (strstr(body,"away")!=NULL + || strstr(body,"idle")){ + estatus=SalPresenceAway; + }else if (strstr(body,"onthephone")!=NULL + || strstr(body,"on-the-phone")!=NULL){ + estatus=SalPresenceOnthephone; + }else if (strstr(body,"outtolunch")!=NULL + || strstr(body,"meal")!=NULL){ + estatus=SalPresenceOuttolunch; + }else if (strstr(body,"closed")!=NULL){ + estatus=SalPresenceOffline; + }else if ((strstr(body,"online")!=NULL) || (strstr(body,"open")!=NULL)) { + estatus=SalPresenceOnline; + }else{ + estatus=SalPresenceOffline; + } + ms_message("We are notified that [%s] has online status %i",sal_op_get_from(op),estatus); + 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("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + } else + sub_state=SalSubscribeActive; + + op->base.root->callbacks.notify_presence(op,sub_state, estatus,NULL); + resp=belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { + /*either a refresh of an unsubscribe*/ + if (expires && belle_sip_header_expires_get_expires(expires)>0) { + op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op)); + } else if(expires) { + ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); + resp=belle_sip_response_create_from_request(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)); + } + /* no break */ + } + + +} +void sal_op_presence_fill_cbs(SalOp*op) { + op->callbacks.process_io_error=presence_process_io_error; + op->callbacks.process_response_event=presence_response_event; + op->callbacks.process_timeout=presence_process_timeout; + op->callbacks.process_transaction_terminated=presence_process_transaction_terminated; + op->callbacks.process_request_event=presence_process_request_event; + op->callbacks.process_dialog_terminated=presence_process_dialog_terminated; +} + +/*presence publish */ +int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ + ms_fatal("sal_publish not implemented yet"); + return -1; +} +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ + 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); + + /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ + req=sal_op_build_request(op,"SUBSCRIBE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); + + return sal_op_send_request(op,req); +} +int sal_unsubscribe(SalOp *op){ + belle_sip_request_t* req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); + return sal_op_send_request(op,req); +} +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 = belle_sip_response_create_from_request(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){ + belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),403); + belle_sip_server_transaction_send_response(op->pending_server_trans,resp); + return 0; +} +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); +/* belle_sip_header_address_t* identity=sal_op_get_contact_address(op); + if (identity==NULL) identity=sal_op_get_to_address(op); + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,identity);*/ + add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*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_close(SalOp *op){ + belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*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_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index ae7a6e116..7ad1c404e 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -30,11 +30,7 @@ static void register_refresh(SalOp* op) { belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,op->request); } -static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) { - if (!a | !b) return FALSE; - return !belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b))); -} + static void register_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); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); @@ -52,7 +48,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)is_contact_equal, (const void*)sal_op_get_contact_address(op)); + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)sal_op_get_contact_address(op)); if (!contact_header_list) { ms_error("no matching contact for [%s]", sal_op_get_contact(op)); } else { diff --git a/coreapi/friend.c b/coreapi/friend.c index d71dd25c6..7c89991ba 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -338,8 +338,8 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ ms_warning("No sip url defined."); return; } - fr->lc=lc; + linphone_core_write_friends_config(lc); if (fr->inc_subscribe_pending){ @@ -390,6 +390,7 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) return ; } lc->friends=ms_list_append(lc->friends,lf); + lf->lc=lc; if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc); else lf->commit=TRUE; return ; diff --git a/coreapi/sal.c b/coreapi/sal.c index 90fa26fab..461f54dfa 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -414,3 +414,18 @@ const char* sal_stream_dir_to_string(SalStreamDir type) { } } + +const char* sal_reason_to_string(const SalReason reason) { + switch (reason) { + case SalReasonDeclined : return "SalReasonDeclined"; + case SalReasonBusy: return "SalReasonBusy"; + case SalReasonRedirect: return "SalReasonRedirect"; + case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable"; + case SalReasonNotFound: return "SalReasonNotFound"; + case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb"; + case SalReasonMedia: return "SalReasonMedia"; + case SalReasonForbidden: return "SalReasonForbidden"; + case SalReasonUnknown: return "SalReasonUnknown"; + default: return "Unkown reason"; + } +} diff --git a/coreapi/sal.h b/coreapi/sal.h index 543d7e9f2..8e38c39f6 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -201,6 +201,8 @@ typedef enum SalReason{ SalReasonUnknown }SalReason; +const char* sal_reason_to_string(const SalReason reason); + typedef enum SalPresenceStatus{ SalPresenceOffline, SalPresenceOnline, diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 23c50f88b..736c1f380 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -84,6 +84,9 @@ typedef struct _stats { int number_of_LinphoneCallReleased; int number_of_LinphoneMessageReceived; + + int number_of_NewSubscriptionRequest; + int number_of_NotifyReceived; }stats; static stats global_stat; @@ -296,7 +299,6 @@ static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCal } static void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { - char* from=linphone_address_as_string(from_address); ms_message("Message from [%s] is [%s]",from,message); ms_free(from); @@ -304,6 +306,21 @@ static void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, cons counters->number_of_LinphoneMessageReceived++; } +void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("New subscription request from [%s] url [%s]",from,url); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_NewSubscriptionRequest++; + +} +static void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("New Notify request from [%s] ",from); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_NotifyReceived++; +} static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counterv_table.registration_state_changed=registration_state_changed; mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; + mgr->v_table.new_subscription_request=new_subscribtion_request; + mgr->v_table.notify_presence_recv=notify_presence_received; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); @@ -551,6 +570,37 @@ static void text_message() { linphone_core_manager_destroy(pauline); } +static void simple_publish() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + linphone_core_iterate(marie->lc); + linphone_core_manager_destroy(marie); +} + + +static void simple_subscribe() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); + LinphoneFriend* friend = (LinphoneFriend*) marie_friends->data; + linphone_friend_edit(friend); + linphone_friend_enable_subscribes(friend,TRUE); + linphone_friend_done(friend); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1)); + + linphone_core_manager_destroy(marie); + CU_ASSERT_TRUE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*wait for unsubscribe*/ + + linphone_core_manager_destroy(pauline); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); @@ -604,6 +654,12 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "text_message", text_message)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/marie_rc b/tester/marie_rc index 95c30a0e1..26cb42992 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -22,6 +22,11 @@ reg_sendregister=1 publish=0 dial_escape_plus=0 +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + [rtp] audio_rtp_port=8070 diff --git a/tester/pauline_rc b/tester/pauline_rc index 07e0efa25..f2da8991c 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -22,6 +22,11 @@ reg_sendregister=1 publish=0 dial_escape_plus=0 +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + [rtp] audio_rtp_port=8090 video_rtp_port=8092 From ee1b3d05a8c5338d9723941f1fa278ed75d972e8 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 14 Dec 2012 08:48:27 +0100 Subject: [PATCH 015/909] fix presence --- tester/liblinphone_tester.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 736c1f380..8521bc6e0 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -312,6 +312,7 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * ms_free(from); stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NewSubscriptionRequest++; + linphone_core_add_friend(lc,lf); /*accept subscription*/ } static void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { @@ -596,7 +597,7 @@ static void simple_subscribe() { CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1)); linphone_core_manager_destroy(marie); - CU_ASSERT_TRUE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*wait for unsubscribe*/ + CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ linphone_core_manager_destroy(pauline); } From e38184c551c6a8c9c637e2de5a6a3bfb999a954d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 18 Dec 2012 11:11:40 +0100 Subject: [PATCH 016/909] test with pstn gateways --- coreapi/bellesip_sal/sal_impl.c | 60 ++++++++-------- coreapi/bellesip_sal/sal_op_call.c | 79 ++++++++++++---------- coreapi/bellesip_sal/sal_op_impl.c | 5 +- coreapi/bellesip_sal/sal_op_registration.c | 19 ++++-- tester/liblinphone_tester.c | 33 ++++++++- 5 files changed, 125 insertions(+), 71 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b9cdd0b61..2d6311502 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -82,6 +82,7 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); char* from; @@ -115,6 +116,9 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev } } 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,500); + belle_sip_provider_send_response(((Sal*)sal)->prov,resp); + return; } @@ -190,7 +194,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); } if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); } contact_updated=TRUE; @@ -199,42 +203,41 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (received!=NULL || rport>0) { if (sal_op_get_contact(op)){ contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } + } + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) + /*try to fix transport if needed (very unlikely)*/ + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + if (!belle_sip_uri_get_transport_param(contact_uri) ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; - } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); - } + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); } } - } - if (contact_updated) { + if (contact_updated) { new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); sal_op_set_contact(op,new_contact); belle_sip_free(new_contact); } - if (contact_address)belle_sip_object_unref(contact_address); - + if (contact_address)belle_sip_object_unref(contact_address); + } /*update request/response * maybe only the transaction should be kept*/ old_request=op->request; @@ -265,6 +268,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } } op->callbacks.process_response_event(op,event); + } else { ms_error("Unhandled event response [%p]",event); } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 91006ae0d..94920b7b2 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -196,20 +196,23 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t switch (op->state) { case SalOpStateEarly:/*invite case*/ case SalOpStateActive: /*re-invite case*/ - 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."); + if (code >=200) { + 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(response),op->sdp_answer); - op->sdp_answer=NULL; - } - belle_sip_dialog_send_ack(op->dialog,ack); - op->state=SalOpStateActive; - op->base.root->callbacks.call_accepted(op); + return ; + } + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); + op->sdp_answer=NULL; + } + belle_sip_dialog_send_ack(op->dialog,ack); + /*if (op->state != SalOpStateActive)*/ + op->base.root->callbacks.call_accepted(op); + op->state=SalOpStateActive; + } break; case SalOpStateTerminated: @@ -425,16 +428,29 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_request_event=process_request_event; op->callbacks.process_dialog_terminated=process_dialog_terminated; } -int sal_call_notify_ringing(SalOp *op, bool_t early_media){ - belle_sip_response_t* ringing_response; - - /*if early media send also 180 and 183 */ - if (early_media){ - ms_fatal("not implemented yet"); +static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) { + if (op->base.local_media){ + /*this is the case where we received an invite without SDP*/ + if (op->sdp_offering) { + set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); + }else{ + if (op->sdp_answer==NULL) sdp_process(op); + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); + op->sdp_answer=NULL; + } + } }else{ - ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),180); - belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); + 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_response_t* ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status_code); + if (early_media){ + handle_offer_answer_response(op,ringing_response); + } + belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); return 0; } @@ -461,20 +477,8 @@ int sal_call_accept(SalOp*h){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); } - if (h->base.local_media){ - /*this is the case where we received an invite without SDP*/ - if (h->sdp_offering) { - set_sdp_from_desc(BELLE_SIP_MESSAGE(response),h->base.local_media); - }else{ - if (h->sdp_answer==NULL) sdp_process(h); - if (h->sdp_answer){ - set_sdp(BELLE_SIP_MESSAGE(response),h->sdp_answer); - h->sdp_answer=NULL; - } - } - }else{ - ms_error("You are accepting a call but not defined any media capabilities !"); - } + handle_offer_answer_response(h,response); + belle_sip_server_transaction_send_response(h->pending_server_trans,response); return 0; } @@ -523,8 +527,13 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti } int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); + /*belle_sdp_session_description_t* session_desc;*/ + belle_sip_header_contact_t* contact=belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); + /*need to add contact header for re-invite*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),BELLE_SIP_HEADER(contact)); sal_op_fill_invite(op, reinvite); + return sal_op_send_request(op,reinvite); } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a79d179ce..94419e79d 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -90,8 +90,9 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { /*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to){ - ms_fatal("sal_ping not implemented yet"); - return -1; + sal_op_set_from(op,from); + sal_op_set_to(op,to); + return sal_op_send_request(op,sal_op_build_request(op,"OPTION")); } void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 7ad1c404e..b11b2f839 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -36,10 +36,12 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_response_t* response = belle_sip_response_event_get_response(event); belle_sip_header_expires_t* expires_header; - + belle_sip_request_t* original_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_header_contact_t* original_contact=belle_sip_message_get_header_by_type(original_request,belle_sip_header_contact_t); const belle_sip_list_t* contact_header_list; int response_code = belle_sip_response_get_status_code(response); int expires=-1; + char* tmp_string; if (response_code<200) return;/*nothing to do*/ @@ -48,9 +50,14 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)sal_op_get_contact_address(op)); + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)original_contact); if (!contact_header_list) { - ms_error("no matching contact for [%s]", sal_op_get_contact(op)); + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)sal_op_get_contact_address(op)); + } + if (!contact_header_list) { + tmp_string=belle_sip_object_to_string(BELLE_SIP_OBJECT(original_contact)); + ms_error("no matching contact neither for [%s] nor [%s]", tmp_string, sal_op_get_contact(op)); + belle_sip_free(tmp_string); } else { expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header_list->data)); } @@ -63,8 +70,10 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve } } if (expires<0) { - ms_message("Neither Expires header nor corresponding Contact header found"); - expires=0; + if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(original_request),BELLE_SIP_EXPIRES))) { + expires = belle_sip_header_expires_get_expires(expires_header); + ms_message("Neither Expires header nor corresponding Contact header found, using expires value [%i] from request",expires); + } } op->base.root->callbacks.register_success(op,expires>0); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 8521bc6e0..7cce3c791 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -376,6 +376,7 @@ static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); + int retry=0; CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); @@ -386,7 +387,16 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallOutgoingRinging,1)); + + while ((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging<1 + || caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia<1) && retry++ <20) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(100000); + } + + + CU_ASSERT_TRUE_FATAL(caller_mgr->stat.number_of_LinphoneCallOutgoingRinging|caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia); linphone_core_get_default_proxy(caller_mgr->lc,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); @@ -602,6 +612,24 @@ static void simple_subscribe() { linphone_core_manager_destroy(pauline); } +static void call_early_media() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); @@ -643,6 +671,9 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "call_early_media", call_early_media)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { return CU_get_error(); } From a7618e45c17e0dcbfb224a6da4afcb25748e17d3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 19 Dec 2012 12:55:16 +0100 Subject: [PATCH 017/909] partial fix for multiple dialog --- coreapi/bellesip_sal/sal_op_call.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 838e841db..88455a2f6 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -165,6 +165,14 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } return; } + /*check if dialog has changed*/ + if (belle_sip_response_event_get_dialog(event) != op->dialog) { + ms_message("Dialog as changed from [%p] to [%p] for op [%p], updating",op->dialog,belle_sip_response_event_get_dialog(event),op); + /*fixme, shouldn't we cancel previous dialog*/ + belle_sip_object_unref(op->dialog); + op->dialog=belle_sip_response_event_get_dialog(event); + belle_sip_object_ref(op->dialog); + } /*check if op is terminating*/ dialog_state=belle_sip_dialog_get_state(op->dialog); From 6a89a97fcfebf660852eeb82660329e2b59af483 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 20 Dec 2012 18:58:53 +0100 Subject: [PATCH 018/909] add unsubscribe test --- coreapi/bellesip_sal/sal_impl.c | 1 + coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call.c | 7 +++++-- coreapi/bellesip_sal/sal_op_presence.c | 4 ++++ tester/liblinphone_tester.c | 14 ++++++++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 1a67506df..ccb8f7f52 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -183,6 +183,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_request_t* old_request=NULL;; belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); + if (op->state == SalOpStateTerminated) { belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); return; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1b036cc92..aca82a252 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -38,7 +38,7 @@ struct Sal{ typedef enum SalOpSate { SalOpStateEarly=0 ,SalOpStateActive - ,SalOpStateTerminating /*this state is used to wait until a procedding state, so we can send the cancel*/ + ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ ,SalOpStateTerminated }SalOpSate_t; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 88455a2f6..5c672860c 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -84,8 +84,11 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } -static void process_dialog_terminated(void *op, const belle_sip_dialog_terminated_event_t *event) { - if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL; +static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalOp* op=(SalOp*)ctx; + if (op->dialog) { + op->dialog=NULL; + } } static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 742f48e02..84db5b0a2 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -591,6 +591,10 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ } int sal_unsubscribe(SalOp *op){ belle_sip_request_t* req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); + if (!req) { + ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); + return -1; + } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); return sal_op_send_request(op,req); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a012d8035..bdd78c750 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -611,6 +611,17 @@ static void simple_subscribe() { linphone_core_manager_destroy(pauline); } +static void unsubscribe_while_subscribing() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ + linphone_friend_edit(friend); + linphone_friend_enable_subscribes(friend,TRUE); + linphone_friend_done(friend); + linphone_core_add_friend(marie->lc,friend); + linphone_core_iterate(marie->lc); + linphone_core_manager_destroy(marie); + +} static void call_early_media() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_early_rc"); @@ -692,6 +703,9 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "unsubscribe_while_subscribing", unsubscribe_while_subscribing)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { From 730d2cac7d65527738b653ef72ebb5b6220134af Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 8 Jan 2013 16:04:10 +0100 Subject: [PATCH 019/909] no longuer create dialog for outgoing calls --- coreapi/bellesip_sal/sal_impl.c | 4 +- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_call.c | 55 +++++++++++++------------- coreapi/bellesip_sal/sal_op_impl.c | 29 ++++++++------ coreapi/bellesip_sal/sal_op_presence.c | 14 ++++--- tester/liblinphone_tester.c | 10 ++++- 6 files changed, 67 insertions(+), 46 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ccb8f7f52..79d7c0fb4 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -64,10 +64,10 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_get_dialog(event); SalOp* op = belle_sip_dialog_get_application_data(dialog); - if (op->callbacks.process_dialog_terminated) { + if (op && op->callbacks.process_dialog_terminated) { op->callbacks.process_dialog_terminated(op,event); } else { - ms_error("sal process_dialog_terminated not implemented yet"); + 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){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index aca82a252..d98e85b42 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -75,6 +75,7 @@ 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, const belle_sip_response_event_t* event); 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); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 5c672860c..f2456d997 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -87,6 +87,9 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op=(SalOp*)ctx; if (op->dialog) { + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + op->state=SalOpStateTerminated; + belle_sip_object_unref(op->dialog); op->dialog=NULL; } } @@ -168,31 +171,30 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } return; } - /*check if dialog has changed*/ - if (belle_sip_response_event_get_dialog(event) != op->dialog) { - ms_message("Dialog as changed from [%p] to [%p] for op [%p], updating",op->dialog,belle_sip_response_event_get_dialog(event),op); - /*fixme, shouldn't we cancel previous dialog*/ - belle_sip_object_unref(op->dialog); - op->dialog=belle_sip_response_event_get_dialog(event); - belle_sip_object_ref(op->dialog); - } + set_or_update_dialog(op,event); + /*check if op is terminating*/ - dialog_state=belle_sip_dialog_get_state(op->dialog); + if (op->state == SalOpStateTerminating - && (dialog_state==BELLE_SIP_DIALOG_NULL - || dialog_state==BELLE_SIP_DIALOG_EARLY)) { + && (!op->dialog + || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL + || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_EARLY)) { cancelling_invite(op); return; } - /*else dialog*/ + if (!op->dialog) { + ms_message("call 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: { - ms_error("op [%p] receive an unexpected answer [%i]",op,code); + ms_error("call op [%p] receive an unexpected answer [%i]",op,code); break; } case BELLE_SIP_DIALOG_EARLY: { @@ -200,7 +202,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t handle_sdp_from_response(op,response); op->base.root->callbacks.call_ringing(op); } else { - ms_error("op [%p] receive an unexpected answer [%i]",op,code); + ms_error("call op [%p] receive an unexpected answer [%i]",op,code); } break; } @@ -229,13 +231,13 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t case SalOpStateTerminated: default: - ms_error("op [%p] receive answer [%i] not implemented",op,code); + ms_error("call op [%p] receive answer [%i] not implemented",op,code); } break; } case BELLE_SIP_DIALOG_TERMINATED: default: { - ms_error("op [%p] receive answer [%i] not implemented",op,code); + ms_error("call op [%p] receive answer [%i] not implemented",op,code); } /* no break */ } @@ -253,7 +255,7 @@ static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_tra op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); resp=belle_sip_response_create_from_request(request,status_code); belle_sip_server_transaction_send_response(server_transaction,resp); - op->state=SalOpStateTerminated; + return; } static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { @@ -283,7 +285,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_header_t* replace_header; belle_sip_dialog_state_t dialog_state; - + belle_sip_response_t* resp; belle_sip_header_t* call_info; if (!op->dialog) { @@ -335,7 +337,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } } else { belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); - unsupported_method(server_transaction,belle_sip_request_event_get_request(event)); + unsupported_method(server_transaction,req); } break; } @@ -358,7 +360,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }*/ op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { - call_terminated(op,server_transaction,belle_sip_request_event_get_request(event),200); + resp=belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + /*call end is notified by dialog deletion*/ } else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) { /*re-invite*/ if (op->base.remote_media){ @@ -374,6 +378,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->base.root->callbacks.call_updating(op); } else { ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); + unsupported_method(server_transaction,req); } break; default: { @@ -425,11 +430,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ sal_op_call_fill_cbs(op); sal_op_send_request(op,req); - /*op->pending_inv_client_trans = client_transaction = belle_sip_provider_create_client_transaction(prov,req); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_client_transaction_send_request(client_transaction); - */ + return 0; } void sal_op_call_fill_cbs(SalOp*op) { @@ -588,7 +589,7 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ return -1; } int sal_call_terminate(SalOp *op){ - belle_sip_dialog_state_t dialog_state=belle_sip_dialog_get_state(op->dialog); + 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*/ op->state=SalOpStateTerminating; switch(dialog_state) { case BELLE_SIP_DIALOG_CONFIRMED: { @@ -605,7 +606,7 @@ int sal_call_terminate(SalOp *op){ cancelling_invite(op); break; } else { - ms_error("Don't know how to termination NUL dialog [%p]",op->dialog); + ms_error("Don't know how to termination NUlL dialog for op [%p]",op); } break; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 94419e79d..5d1946cc7 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -108,30 +108,26 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,request); } -static bool_t is_request_creating_dialog(belle_sip_request_t* request) { - return strcmp("INVITE",belle_sip_request_get_method(request))==0 - || - strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0; -} + int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; - if (!op->dialog || belle_sip_dialog_get_state(op->dialog)!=BELLE_SIP_DIALOG_CONFIRMED) { + if (!op->dialog) { /*don't put route header if dialog is in confirmed state*/ if (sal_op_get_route_address(op)) { route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); } } + client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); - /*in case DIALOG is in state NULL create a new dialog*/ - if (!op->dialog && is_request_creating_dialog(request)) { - op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); + if ( strcmp("INVITE",belle_sip_request_get_method(request))==0) { op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ - belle_sip_dialog_set_application_data(op->dialog,op); - } else if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) + } + + 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); @@ -201,3 +197,14 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S return FALSE; } } +void set_or_update_dialog(SalOp* op, const belle_sip_response_event_t* event) { + /*check if dialog has changed*/ + if (belle_sip_response_event_get_dialog(event) != op->dialog) { + ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,belle_sip_response_event_get_dialog(event),op); + /*fixme, shouldn't we cancel previous dialog*/ + if (op->dialog)belle_sip_object_unref(op->dialog); + op->dialog=belle_sip_response_event_get_dialog(event); + belle_sip_dialog_set_application_data(op->dialog,op); + belle_sip_object_ref(op->dialog); + } +} diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 84db5b0a2..a4d8900fd 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -424,7 +424,11 @@ static void presence_response_event(void *op_base, const belle_sip_response_even op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); return; } - + set_or_update_dialog(op_base,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); @@ -432,7 +436,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { - ms_error("op [%p] receive an unexpected answer [%i]",op,code); + ms_error("presence op [%p] receive an unexpected answer [%i]",op,code); break; } case BELLE_SIP_DIALOG_CONFIRMED: { @@ -456,7 +460,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } break; default: { - ms_error("op [%p] receive answer [%i] not implemented",op,code); + ms_error("presence op [%p] receive answer [%i] not implemented",op,code); } /* no break */ } @@ -569,7 +573,7 @@ void sal_op_presence_fill_cbs(SalOp*op) { /*presence publish */ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ - ms_fatal("sal_publish not implemented yet"); + ms_error("sal_publish not implemented yet"); return -1; } /*presence Subscribe/notify*/ @@ -590,7 +594,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ return sal_op_send_request(op,req); } int sal_unsubscribe(SalOp *op){ - belle_sip_request_t* req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); + belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ if (!req) { ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); return -1; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index bdd78c750..5c9f9106d 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -643,7 +643,7 @@ static void call_early_media() { int init_test_suite () { -CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); +CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); if (NULL == CU_add_test(pSuite, "linphone address tester", linphone_address_test)) { @@ -652,6 +652,8 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "linphone core init/uninit tester", core_init_test)) { return CU_get_error(); } + + pSuite = CU_add_suite("Register", init, uninit); if (NULL == CU_add_test(pSuite, "simple register tester", simple_register)) { return CU_get_error(); } @@ -670,6 +672,8 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } + + pSuite = CU_add_suite("Call", init, uninit); if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { return CU_get_error(); } @@ -694,9 +698,13 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { return CU_get_error(); } + + pSuite = CU_add_suite("Message", init, uninit); if (NULL == CU_add_test(pSuite, "text_message", text_message)) { return CU_get_error(); } + + pSuite = CU_add_suite("Presence", init, uninit); if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) { return CU_get_error(); } From e9df76394989085968347992efbeb0fa1cad91a6 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 9 Jan 2013 18:32:13 +0100 Subject: [PATCH 020/909] update sal op contact with contact generated by the sip stack for the request --- coreapi/bellesip_sal/sal_impl.c | 44 ++++++++++++++++------ coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 7 ++-- coreapi/bellesip_sal/sal_op_registration.c | 7 ++-- coreapi/linphonecore.c | 2 +- coreapi/private.h | 1 + 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 79d7c0fb4..fd063b64f 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -37,6 +37,8 @@ static void sal_add_pending_auth(Sal *sal, SalOp *op){ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { belle_sip_request_t* request; bool_t is_within_dialog=FALSE; + belle_sip_list_t* auth_list=NULL; + belle_sip_auth_event_t* auth_event; if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)op->request); is_within_dialog=TRUE; @@ -46,7 +48,7 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); } - if (belle_sip_provider_add_authorization(op->base.root->prov,request,response)) { + if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) { if (is_within_dialog) { sal_op_resend_request(op,request); } else { @@ -57,6 +59,12 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { if (is_within_dialog) { belle_sip_object_unref(request); } + if (op->auth_info) sal_auth_info_delete(op->auth_info); + auth_event=(belle_sip_auth_event_t*)(auth_list->data); + op->auth_info=sal_auth_info_new(); + op->auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(auth_event)) ; + op->auth_info->username = ms_strdup(belle_sip_auth_event_get_username(auth_event)) ; + belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); sal_add_pending_auth(op->base.root,op); } @@ -172,6 +180,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); 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)); + belle_sip_header_contact_t* original_contact; belle_sip_header_address_t* contact_address=NULL; belle_sip_header_via_t* via_header; belle_sip_uri_t* contact_uri; @@ -198,19 +208,29 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even received = belle_sip_header_via_get_received(via_header); rport = belle_sip_header_via_get_rport(via_header); if (!sal_op_get_contact(op)) { - /*hmm update contact from via*/ - contact_address=belle_sip_header_address_new(); - contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); - belle_sip_header_address_set_uri(contact_address,contact_uri); + /*check if contqct set in reauest*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { + /*no contact set yet, try to see if sip tack has an updated one*/ + contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_object_unref(contact_address); + } else { + + /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ + contact_address=belle_sip_header_address_new(); + contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); + belle_sip_header_address_set_uri(contact_address,contact_uri); + + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + } + if (belle_sip_header_via_get_listening_port(via_header) + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + } + contact_updated=TRUE; } - if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { - belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); - } - contact_updated=TRUE; } if (received!=NULL || rport>0) { diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index d98e85b42..8619bf856 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -54,7 +54,7 @@ struct SalOp{ belle_sip_response_t* response; belle_sip_server_transaction_t* pending_server_trans; belle_sip_client_transaction_t* pending_inv_client_trans; - SalAuthInfo auth_info; + SalAuthInfo* auth_info; unsigned long int registration_refresh_timer; bool_t sdp_offering; belle_sip_dialog_t* dialog; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 5d1946cc7..8ed860a05 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -31,6 +31,7 @@ void sal_op_release(SalOp *op){ if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } + if (op->auth_info) sal_auth_info_delete(op->auth_info); __sal_op_free(op); return ; } @@ -46,8 +47,8 @@ void sal_op_cancel_authentication(SalOp *h){ } int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ - *realm=op->auth_info.realm; - *username=op->auth_info.username; + *realm=op->auth_info?op->auth_info->realm:NULL; + *username=op->auth_info?op->auth_info->username:NULL; return 0; } @@ -130,7 +131,7 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { 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); + belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL); } return belle_sip_client_transaction_send_request(client_transaction); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index b11b2f839..8f708f6ad 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -50,9 +50,11 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)original_contact); + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)original_contact); if (!contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)sal_op_get_contact_address(op)); + /*reset header list*/ + contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); + contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)sal_op_get_contact_address(op)); } if (!contact_header_list) { tmp_string=belle_sip_object_to_string(BELLE_SIP_OBJECT(original_contact)); @@ -119,7 +121,6 @@ static void send_register_request_with_expires(SalOp* op, belle_sip_request_t* r int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; - sal_op_set_from(op,from); sal_op_set_to(op,from); sal_op_set_route(op,proxy); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0a76f4b4f..26e0ba572 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4749,7 +4749,7 @@ void sip_config_uninit(LinphoneCore *lc) ms_list_free(config->proxies); config->proxies=NULL; - linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */ + /*no longuer need to write proxy config if not changedlinphone_proxy_config_write_to_config_file(lc->config,NULL,i);*/ /*mark the end */ ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); ms_list_free(lc->auth_info); diff --git a/coreapi/private.h b/coreapi/private.h index c171fac88..bc2b65cfb 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -186,6 +186,7 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); +void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); From 48b1a8be8da983920b4cee2df3ceefc3bd742306 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 10 Jan 2013 18:07:54 +0100 Subject: [PATCH 021/909] add service route support (rfc3608) --- coreapi/bellesip_sal/sal_op_registration.c | 21 +++++++++++++++++++++ coreapi/linphonecore.c | 13 ++++++++++--- coreapi/private.h | 6 ++++++ coreapi/proxy.c | 4 +++- coreapi/sal.c | 12 ++++++++++++ coreapi/sal.h | 4 ++++ 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 8f708f6ad..e94407598 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -39,6 +39,9 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve belle_sip_request_t* original_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_header_contact_t* original_contact=belle_sip_message_get_header_by_type(original_request,belle_sip_header_contact_t); const belle_sip_list_t* contact_header_list; + belle_sip_header_service_route_t* service_route; + belle_sip_header_address_t* service_route_address=NULL; + int response_code = belle_sip_response_get_status_code(response); int expires=-1; char* tmp_string; @@ -77,6 +80,12 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve ms_message("Neither Expires header nor corresponding Contact header found, using expires value [%i] from request",expires); } } + /*check service route rfc3608*/ + 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); op->base.root->callbacks.register_success(op,expires>0); /*always cancel pending refresh if any*/ @@ -92,6 +101,18 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve } default:{ + + /* 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); + ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); op->base.root->callbacks.register_failure(op,SalErrorFailure,SalReasonUnknown,belle_sip_response_get_reason_phrase(response)); break; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 26e0ba572..763f59058 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2421,7 +2421,6 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr **/ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { - const char *route=NULL; const char *from=NULL; LinphoneProxyConfig *proxy=NULL,*dest_proxy=NULL; LinphoneAddress *parsed_url2=NULL; @@ -2437,7 +2436,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const return NULL; } linphone_core_get_default_proxy(lc,&proxy); - route=linphone_core_get_route(lc); + real_url=linphone_address_as_string(addr); dest_proxy=linphone_core_lookup_known_proxy(lc,addr); @@ -2459,7 +2458,15 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const 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); + + if (linphone_core_get_route(lc)) { + sal_op_set_route(call->op,linphone_core_get_route(lc)); + } else if (proxy && linphone_proxy_config_get_service_route(proxy)) { + /*set service route*/ + sal_op_set_route_address(call->op,linphone_proxy_config_get_service_route(proxy)); + } /*else, no route*/ + + if(linphone_core_add_call(lc,call)!= 0) { diff --git a/coreapi/private.h b/coreapi/private.h index bc2b65cfb..70a659679 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -187,6 +187,12 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); +/* + * returns service route as defined in as defined by rfc3608, might be a list instead of just one. + * Can be NULL + * */ +const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); + int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index cd8a03f1b..fe5a724e8 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1254,4 +1254,6 @@ void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason err cfg->error = error; } - +const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { + return cfg->op?(const LinphoneAddress*) sal_op_get_service_route(cfg->op):NULL; +} diff --git a/coreapi/sal.c b/coreapi/sal.c index f995ee712..5809b2617 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -395,6 +395,9 @@ void __sal_op_free(SalOp *op){ sal_media_description_unref(b->remote_media); if (b->call_id) ms_free((void*)b->call_id); + if (b->service_route) { + sal_address_destroy(b->service_route); + } ms_free(op); } @@ -461,3 +464,12 @@ const char* sal_reason_to_string(const SalReason reason) { 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; +} diff --git a/coreapi/sal.h b/coreapi/sal.h index 016e6cbd3..281397143 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -229,6 +229,7 @@ typedef struct SalOpBase{ SalMediaDescription *remote_media; void *user_pointer; const char* call_id; + SalAddress* service_route; /*as defined by rfc3608, might be a list*/ } SalOpBase; @@ -416,6 +417,9 @@ const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); const char* sal_op_get_call_id(const SalOp *op); +const SalAddress* sal_op_get_service_route(const SalOp *op); +void sal_op_set_service_route(SalOp *op,const SalAddress* service_route); + /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); From ca59e093f52af74234306af4f38d64548fcce584 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 14 Jan 2013 18:24:38 +0100 Subject: [PATCH 022/909] adapt code to new object ref management --- coreapi/bellesip_sal/sal_address_impl.c | 7 ++++--- coreapi/bellesip_sal/sal_impl.c | 1 - coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call.c | 10 +++++----- coreapi/bellesip_sal/sal_op_impl.c | 9 +++++---- coreapi/bellesip_sal/sal_op_presence.c | 2 +- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index e2bb58daf..86415ad0f 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -22,15 +22,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SalAddress * sal_address_new(const char *uri){ belle_sip_header_address_t* result; if (uri) { - return (SalAddress *)belle_sip_header_address_parse (uri); + result=belle_sip_header_address_parse (uri); } else { result = belle_sip_header_address_new(); belle_sip_header_address_set_uri(result,belle_sip_uri_new()); - return (SalAddress *)result; } + belle_sip_object_ref(result); + return (SalAddress *)result; } SalAddress * sal_address_clone(const SalAddress *addr){ - return (SalAddress *) belle_sip_object_clone(BELLE_SIP_OBJECT(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); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index fd063b64f..08b9d2450 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -425,7 +425,6 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,addr,port,sal_transport_to_string(tr)); if (lp) { result = belle_sip_provider_add_listening_point(ctx->prov,lp); - belle_sip_object_unref(lp); } else { return -1; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 8619bf856..c71a84417 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -75,7 +75,7 @@ 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, const belle_sip_response_event_t* event); +void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog); 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); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f2456d997..857818d87 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -33,7 +33,7 @@ static void sdp_process(SalOp *h){ belle_sip_object_unref(h->sdp_answer); } offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result); + 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); @@ -171,7 +171,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } return; } - set_or_update_dialog(op,event); + set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); /*check if op is terminating*/ @@ -180,6 +180,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t && (!op->dialog || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_EARLY)) { + /*FIXME if DIALOG_CONFIRM then ACK+BYE*/ cancelling_invite(op); return; @@ -278,7 +279,7 @@ static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { 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 = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); - belle_sip_object_ref(server_transaction); + if (server_transaction) belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=server_transaction; belle_sdp_session_description_t* sdp; @@ -289,8 +290,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_header_t* call_info; if (!op->dialog) { - op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)); - belle_sip_dialog_set_application_data(op->dialog,op); + 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); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 8ed860a05..4b12a653f 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -32,6 +32,7 @@ void sal_op_release(SalOp *op){ belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } if (op->auth_info) sal_auth_info_delete(op->auth_info); + if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); __sal_op_free(op); return ; } @@ -198,13 +199,13 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S return FALSE; } } -void set_or_update_dialog(SalOp* op, const belle_sip_response_event_t* event) { +void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { /*check if dialog has changed*/ - if (belle_sip_response_event_get_dialog(event) != op->dialog) { - ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,belle_sip_response_event_get_dialog(event),op); + if (dialog != op->dialog) { + ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op); /*fixme, shouldn't we cancel previous dialog*/ if (op->dialog)belle_sip_object_unref(op->dialog); - op->dialog=belle_sip_response_event_get_dialog(event); + op->dialog=dialog; belle_sip_dialog_set_application_data(op->dialog,op); belle_sip_object_ref(op->dialog); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index a4d8900fd..9da9e1080 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -424,7 +424,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); return; } - set_or_update_dialog(op_base,event); + 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; From 7d9be6acc9620e89f1fa545aa7ce2410d196f75d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 15 Jan 2013 19:25:44 +0100 Subject: [PATCH 023/909] fix service route implementation, now op route address is a list --- coreapi/bellesip_sal/sal_op_impl.c | 5 +++-- coreapi/linphonecore.c | 20 ++++++++++++++++++-- coreapi/sal.c | 24 +++++++++++++++++++++--- coreapi/sal.h | 5 +++-- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 4b12a653f..84957f36a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -115,10 +115,11 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; + MSList* iterator; if (!op->dialog) { /*don't put route header if dialog is in confirmed state*/ - if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + for(iterator=(MSList*)sal_op_get_route_addresses(op);iterator!=NULL;iterator=iterator->next) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(iterator->data)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 763f59058..4b3d1ea50 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2461,9 +2461,25 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (linphone_core_get_route(lc)) { sal_op_set_route(call->op,linphone_core_get_route(lc)); - } else if (proxy && linphone_proxy_config_get_service_route(proxy)) { + } +/* +* 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. +*/ + if (proxy && linphone_proxy_config_get_service_route(proxy)) { /*set service route*/ - sal_op_set_route_address(call->op,linphone_proxy_config_get_service_route(proxy)); + sal_op_add_route_address(call->op,linphone_proxy_config_get_service_route(proxy)); } /*else, no route*/ diff --git a/coreapi/sal.c b/coreapi/sal.c index 5809b2617..3a9806a9d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -273,16 +273,34 @@ void sal_op_set_contact(SalOp *op, const char *contact){ } void sal_op_set_route(SalOp *op, const char *route){ - SET_PARAM(op,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) ortp_free(route_string); } -const SalAddress* sal_op_get_route_address(const SalOp *op) { - return ((SalOpBase*)op)->route_address; +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*)address); + } +} void sal_op_set_from(SalOp *op, const char *from){ SET_PARAM(op,from); } diff --git a/coreapi/sal.h b/coreapi/sal.h index 281397143..2918dbe92 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -215,7 +215,7 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ - SalAddress* route_address; + MSList* route_addresses; /*list of SalAddress* */ char *contact; SalAddress* contact_address; char *from; @@ -391,6 +391,7 @@ void sal_op_set_contact(SalOp *op, const char *contact); void sal_op_set_contact_address(SalOp *op, const SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_route_address(SalOp *op, const SalAddress* address); +void sal_op_add_route_address(SalOp *op, const SalAddress* address); void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_from_address(SalOp *op, const SalAddress *from); void sal_op_set_to(SalOp *op, const char *to); @@ -407,7 +408,7 @@ const SalAddress *sal_op_get_to_address(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); -const SalAddress* sal_op_get_route_address(const SalOp *op); +const MSList* sal_op_get_route_addresses(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); From d0a0b86cfbc69db35e88449fbb4ce578095a1354 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 23 Jan 2013 14:06:51 +0100 Subject: [PATCH 024/909] Add missing sal_use_tcp_tls_keepalive and sal_verify_server_cn --- coreapi/bellesip_sal/sal_impl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 08b9d2450..95e630d3c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -495,6 +495,15 @@ void sal_verify_server_certificates(Sal *ctx, bool_t verify){ ms_error("sal_verify_server_certificates not implemented yet"); return ; } +void sal_verify_server_cn(Sal *ctx, bool_t verify){ + ms_error("sal_verify_server_cn not implemented yet"); + return ; +} + +void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { + ms_error("sal_use_tcp_tls_keepalive not implemented yet"); + return ; +} int sal_iterate(Sal *sal){ /*FIXME should be zero*/ From fa4a074f21c3161ed745003b4f2e3f6ddd0a9d94 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 23 Jan 2013 14:07:21 +0100 Subject: [PATCH 025/909] Modify Android makefile for belle-sip --- build/android/common.mk | 24 ++--- build/android/config.h | 232 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 build/android/config.h diff --git a/build/android/common.mk b/build/android/common.mk index d629b54af..aed755d59 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -35,10 +35,15 @@ LOCAL_SRC_FILES := \ siplogin.c \ address.c \ linphonecore_jni.cc \ + bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_sdp.c \ sal.c \ - sal_eXosip2.c \ - sal_eXosip2_presence.c \ - sal_eXosip2_sdp.c \ offeranswer.c \ callbacks.c \ linphonecall.c \ @@ -54,14 +59,10 @@ LOCAL_CFLAGS += \ -D_BYTE_ORDER=_LITTLE_ENDIAN \ -DORTP_INET6 \ -DINET6 \ - -DOSIP_MT \ - -DHAVE_EXOSIP_GET_VERSION \ - -DHAVE_EXOSIP_RESET_TRANSPORTS \ -DENABLE_TRACE \ + -DHAVE_CONFIG_H \ -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -DHAVE_EXOSIP_TRYLOCK=1 \ - -DHAVE_EXOSIP_TLS_VERIFY_CERTIFICATE=1 LOCAL_CFLAGS += -DIN_LINPHONE @@ -79,10 +80,10 @@ 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)/../../belle-sip/include \ $(LOCAL_PATH)/../../../gen LOCAL_LDLIBS += -llog -ldl @@ -93,8 +94,7 @@ LOCAL_STATIC_LIBRARIES := \ cpufeatures \ libmediastreamer2 \ libortp \ - libeXosip2 \ - libosip2 \ + libbellesip \ libgsm ifeq ($(BUILD_TUNNEL),1) diff --git a/build/android/config.h b/build/android/config.h new file mode 100644 index 000000000..0842116ab --- /dev/null +++ b/build/android/config.h @@ -0,0 +1,232 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define if tools enabled */ +/* #undef BUILD_TOOLS */ + +/* 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 */ + +/* The name of the gettext package name */ +/* #undef GETTEXT_PACKAGE */ + +/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +/* #undef HAVE_CFLOCALECOPYCURRENT */ + +/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +/* #undef HAVE_DCGETTEXT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define if exosip dscp available */ +/* #def HAVE_EXOSIP_DSCP */ + +/* Defined when eXosip_get_version is available */ +/* #undef HAVE_EXOSIP_GET_VERSION */ + +/* Defined when eXosip_reset_transports is available */ +/* #undef HAVE_EXOSIP_RESET_TRANSPORTS */ + +/* Defined when eXosip_tls_verify_certificate is available */ +/* #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 */ +/* #undef HAVE_EXOSIP_TRYLOCK */ + +/* If present, the getenv function allows fim to read environment variables. + */ +#define HAVE_GETENV 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +/* #undef HAVE_GETIFADDRS */ + +/* Tells wheter localisation is possible */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have the `get_current_dir_name' function. */ +#define HAVE_GET_CURRENT_DIR_NAME 1 + +/* Defined when gtk osx is used */ +/* #undef HAVE_GTK_OSX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_HISTORY_H */ + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `eXosip2' library (-leXosip2). */ +/* #define HAVE_LIBEXOSIP2 */ + +/* Define to 1 if you have the `osip2' library (-losip2). */ +/* #undef HAVE_LIBOSIP2 */ + +/* Define to 1 if you have the `osipparser2' library (-losipparser2). */ +/* #undef HAVE_LIBOSIPPARSER2 */ + +/* Define to 1 if you have the `udev' library (-ludev). */ +/* #undef HAVE_LIBUDEV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBUDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* NOTIFY1 support */ +/* #undef HAVE_NOTIFY1 */ + +/* NOTIFY4 support */ +/* #undef HAVE_NOTIFY4 */ + +/* defined when compiling with readline support */ +/* #undef HAVE_READLINE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_HISTORY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_READLINE_H */ + +/* Define if sighandler_t available */ +/* #undef HAVE_SIGHANDLER_T */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `stpcpy' function. */ +#define HAVE_STPCPY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_X11_XLIB_H 1 + +/* All supported languages */ +/* #undef LINPHONE_ALL_LANGS */ + +/* Windows appdata subdir where linphonerc can be found */ +/* #undef LINPHONE_CONFIG_DIR */ + +/* path of liblinphone plugins, not mediastreamer2 plugins */ +/* #undef LINPHONE_PLUGINS_DIR */ + +/* Linphone's version number */ +/* #undef LINPHONE_VERSION */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "linphone" + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Defines the place where data are found */ +/* #undef PACKAGE_DATA_DIR */ + +/* Defines the place where locales can be found */ +/* #undef PACKAGE_LOCALE_DIR */ + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "linphone" + +/* Defines the place where linphone sounds are found */ +/* #undef PACKAGE_SOUND_DIR */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the home page for this package. */ +/* #undef PACKAGE_URL */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Tell whether date_version.h must be used */ +/* #undef USE_BUILDDATE_VERSION */ + +/* Version number of package */ +/* #undef VERSION */ + +/* defined if video support is available */ +/* #undef VIDEO_ENABLED */ + +/* Tell whether RSVP support should be compiled. */ +/* #undef VINCENT_MAURY_RSVP */ + +/* 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 +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Defined if we are compiling for arm processor */ +/* #undef __ARM__ */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif From 488dadc448fd3edcf5284df5806dcbb5e9088536 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 24 Jan 2013 12:35:21 +0100 Subject: [PATCH 026/909] use belle-sip-refresher for registration --- .cproject | 5 + coreapi/bellesip_sal/sal_address_impl.c | 3 +- coreapi/bellesip_sal/sal_impl.c | 3 + coreapi/bellesip_sal/sal_impl.h | 4 +- coreapi/bellesip_sal/sal_op_impl.c | 56 ++++++---- coreapi/bellesip_sal/sal_op_registration.c | 63 ++++++----- coreapi/sal.c | 3 + coreapi/sal.h | 3 + tester/flexisip.conf | 6 +- tester/liblinphone_tester.c | 119 ++++++++++++++------- 10 files changed, 173 insertions(+), 92 deletions(-) diff --git a/.cproject b/.cproject index 070162890..02473afca 100644 --- a/.cproject +++ b/.cproject @@ -35,6 +35,10 @@
+ + + +
@@ -198,4 +202,5 @@ + diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 86415ad0f..5c210878c 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -23,11 +23,12 @@ 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()); } - belle_sip_object_ref(result); + if (result) belle_sip_object_ref(result); return (SalAddress *)result; } SalAddress * sal_address_clone(const SalAddress *addr){ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 95e630d3c..ab2700d05 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -534,3 +534,6 @@ int sal_reset_transports(Sal *ctx){ void sal_set_dscp(Sal *ctx, int dscp){ ms_warning("sal_set_dscp not implemented"); } +void sal_set_send_error(Sal *sal,int value) { + belle_sip_stack_set_send_error(sal->stack,value); +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index c71a84417..8a206be24 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -55,7 +55,7 @@ struct SalOp{ belle_sip_server_transaction_t* pending_server_trans; belle_sip_client_transaction_t* pending_inv_client_trans; SalAuthInfo* auth_info; - unsigned long int registration_refresh_timer; + belle_sip_refresher_t* registration_refresher; bool_t sdp_offering; belle_sip_dialog_t* dialog; belle_sip_header_address_t *replaces; @@ -83,7 +83,7 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); - +void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; /*presence*/ void sal_op_presence_fill_cbs(SalOp*op); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 84957f36a..bd5af0598 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -28,11 +28,12 @@ SalOp * sal_op_new(Sal *sal){ void sal_op_release(SalOp *op){ if (op->request) belle_sip_object_unref(op->request); - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - } if (op->auth_info) sal_auth_info_delete(op->auth_info); if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); + if (op->registration_refresher) { + belle_sip_refresher_stop(op->registration_refresher); + belle_sip_object_unref(op->registration_refresher); + } __sal_op_free(op); return ; } @@ -115,12 +116,19 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; + belle_sip_uri_t* outbound_proxy=NULL; MSList* iterator; if (!op->dialog) { /*don't put route header if dialog is in confirmed state*/ for(iterator=(MSList*)sal_op_get_route_addresses(op);iterator!=NULL;iterator=iterator->next) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(iterator->data)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + if(!outbound_proxy) { + /*first toute is outbound proxy*/ + outbound_proxy=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(iterator->data)); + } else { + /*next are Route headers*/ + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(iterator->data)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } } } @@ -135,26 +143,11 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL); } - return belle_sip_client_transaction_send_request(client_transaction); + return belle_sip_client_transaction_send_request_to(client_transaction,outbound_proxy/*might be null*/); } -/*return TRUE if error code*/ -bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { - int code = belle_sip_response_get_status_code(response); - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); - *sal_err=SalErrorUnknown; - *sal_reason = SalReasonUnknown; - if (reason_header){ - snprintf(reason - ,reason_size - ,"%s %s" - ,belle_sip_response_get_reason_phrase(response) - ,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); - } else { - strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); - } - if (code >=400) { +void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { switch(code) { case 400: *sal_err=SalErrorUnknown; @@ -195,6 +188,25 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S }else *sal_err=SalErrorNoResponse; /* no break */ } +} +/*return TRUE if error code*/ +bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { + int code = belle_sip_response_get_status_code(response); + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + *sal_err=SalErrorUnknown; + *sal_reason = SalReasonUnknown; + + if (reason_header){ + snprintf(reason + ,reason_size + ,"%s %s" + ,belle_sip_response_get_reason_phrase(response) + ,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); + } else { + strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); + } + if (code>400) { + sal_compute_sal_errors_from_code(code,sal_err,sal_reason); return TRUE; } else { return FALSE; diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index e94407598..d4c6c37eb 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -24,38 +24,51 @@ static void register_process_io_error(void *user_ctx, const belle_sip_io_error_e ms_error("process_io_error not implemented yet"); } -static void register_refresh(SalOp* op) { - op->registration_refresh_timer=0; - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->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,op->request); +static void register_refresher_listener ( const belle_sip_refresher_t* refresher + ,void* user_pointer + ,unsigned int status_code + ,const char* reason_phrase) { + SalOp* op = (SalOp*)user_pointer; + SalError sal_err; + SalReason sal_reason; + ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); + if(status_code ==200) { + op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->registration_refresher)>0); + } else if (status_code>=400) { + sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); + op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); + } else { + ms_warning("Register refresher know what to do with this status code"); + } } static void register_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); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_response_t* response = belle_sip_response_event_get_response(event); +/* belle_sip_request_t* original_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_header_expires_t* expires_header; - belle_sip_request_t* original_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_header_contact_t* original_contact=belle_sip_message_get_header_by_type(original_request,belle_sip_header_contact_t); const belle_sip_list_t* contact_header_list; + char* tmp_string;*/ + + belle_sip_header_service_route_t* service_route; belle_sip_header_address_t* service_route_address=NULL; int response_code = belle_sip_response_get_status_code(response); - int expires=-1; - char* tmp_string; + /*int expires=-1;*/ if (response_code<200) return;/*nothing to do*/ switch (response_code) { case 200: { - contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); +/* contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)original_contact); if (!contact_header_list) { - /*reset header list*/ + reset header list contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)sal_op_get_contact_address(op)); } @@ -69,7 +82,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve } if (expires<0 ) { - /*no contact with expire, looking for Expires header*/ + no contact with expire, looking for Expires header if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { expires = belle_sip_header_expires_get_expires(expires_header); } @@ -79,7 +92,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve expires = belle_sip_header_expires_get_expires(expires_header); ms_message("Neither Expires header nor corresponding Contact header found, using expires value [%i] from request",expires); } - } + }*/ /*check service route rfc3608*/ 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))); @@ -87,14 +100,11 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve sal_op_set_service_route(op,(const SalAddress*)service_route_address); if (service_route_address) belle_sip_object_unref(service_route_address); - op->base.root->callbacks.register_success(op,expires>0); - /*always cancel pending refresh if any*/ - if (op->registration_refresh_timer>0) { - belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); - op->registration_refresh_timer=0; - } - if (expires>0) { - op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); + op->base.root->callbacks.register_success(op,TRUE); + + if (/*expires>0 &&*/ !op->registration_refresher) { + op->registration_refresher = belle_sip_client_transaction_create_refresher(client_transaction); + belle_sip_refresher_set_listener(op->registration_refresher,register_refresher_listener,op); } break; @@ -159,16 +169,13 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ } int sal_register_refresh(SalOp *op, int expires){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->request,expires); - return 0; + if (op->registration_refresher) + return belle_sip_refresher_refresh(op->registration_refresher,expires); + else + return -1; } int sal_unregister(SalOp *op){ - belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_CSEQ); - belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); - send_register_request_with_expires(op,op->request,0); - return 0; + return sal_register_refresh(op,0); } diff --git a/coreapi/sal.c b/coreapi/sal.c index f7f1f5f63..69c4cc04c 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -346,6 +346,9 @@ const char *sal_op_get_contact(const SalOp *op){ } 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; } diff --git a/coreapi/sal.h b/coreapi/sal.h index 0beb66277..1084ebce6 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -488,4 +488,7 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin); void __sal_op_free(SalOp *b); +/*test api*/ +/*0 for no error*/ +void sal_set_send_error(Sal *sal,int value); #endif diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 22acf0937..c59ed0a5e 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -278,7 +278,7 @@ max-expires=86400 # Minimum expire time for a REGISTER, in seconds. # Default value: 60 -min-expires=60 +min-expires=1 # File containing the static records to add to database at startup. # Format: one 'sip_uri contact_header' by line. Example: @@ -466,11 +466,11 @@ sdp-port-range-max=65535 # a total bandwith below this value expressed in kbit/s. Use 0 to # disable the feature # Default value: 0 -h264-filtering-bandwidth=0 +#h264-filtering-bandwidth=0 # When above option is activated, keep one I frame over this number. # Default value: 1 -h264-iframe-decim=1 +#h264-iframe-decim=1 ## ## The purpose of the Transcoder module is to transparently transcode diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 5c9f9106d..b99b0871e 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -18,6 +18,8 @@ #include #include "CUnit/Basic.h" #include "linphonecore.h" +#include "private.h" + const char *test_domain="sipopen.example.org"; const char *auth_domain="sip.example.org"; @@ -111,19 +113,33 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo } } +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_auth_info_requested++; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ +} -static LinphoneCore* create_lc() { +static LinphoneCore* create_lc_with_auth(unsigned int with_auth) { LinphoneCoreVTable v_table; LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; + if (with_auth) { + v_table.auth_info_requested=auth_info_requested; + } lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&global_stat); return lc; } - -static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { +static LinphoneCore* create_lc() { + return create_lc_with_auth(0); +} +static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { int retry=0; LCSipTransports transport = {5070,5070,0,5071}; @@ -141,7 +157,7 @@ static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* d const char* server_addr = linphone_address_get_domain(from); linphone_proxy_config_enable_register(proxy_cfg,TRUE); - linphone_proxy_config_expires(proxy_cfg,30); + linphone_proxy_config_expires(proxy_cfg,1); if (route) { linphone_proxy_config_set_route(proxy_cfg,route); linphone_proxy_config_set_server_addr(proxy_cfg,route); @@ -153,41 +169,70 @@ static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* d linphone_core_add_proxy_config(lc,proxy_cfg); linphone_core_set_default_proxy(lc,proxy_cfg); - while (counters->number_of_LinphoneRegistrationOk<1 && retry++ <20) { + while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { linphone_core_iterate(lc); ms_usleep(100000); } - CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); - if (refresh) { - /*wait until refresh*/ - while (counters->number_of_LinphoneRegistrationOk<2 && retry++ <310) { - linphone_core_iterate(lc); - ms_usleep(100000); - } - linphone_core_destroy(lc); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,2); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); - } else { - linphone_core_destroy(lc); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); - } + CU_ASSERT_TRUE_FATAL(linphone_proxy_config_is_registered(proxy_cfg)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + +} +static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh_base(lc,refresh,domain,route); + linphone_core_destroy(lc); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); } +static void register_with_refresh_with_send_error(void) { + int retry=0; + LinphoneCore* lc = create_lc_with_auth(1); + stats* counters = (stats*)linphone_core_get_user_data(lc); + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base(lc,TRUE,auth_domain,NULL); + /*simultate a network error*/ + sal_set_send_error(lc->sal, -1); + while (counters->number_of_LinphoneRegistrationFailed<1 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); + linphone_core_destroy(lc); + + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + +} static void simple_register(){ LinphoneCore* lc = create_lc(); stats* counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh(lc,FALSE,NULL,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } + + +/*take care of min expires configuration from server*/ +static void simple_register_with_refresh() { + LinphoneCore* lc = create_lc(); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,TRUE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + +static void simple_auth_register_with_refresh() { + LinphoneCore* lc = create_lc_with_auth(1); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,TRUE,auth_domain,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); +} + static void simple_tcp_register(){ char route[256]; sprintf(route,"sip:%s;transport=tcp",test_domain); @@ -210,16 +255,7 @@ static void simple_authenticated_register(){ CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } -static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { - ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); - stats* counters = (stats*)linphone_core_get_user_data(lc); - counters->number_of_auth_info_requested++; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ -} static void authenticated_register_with_no_initial_credentials(){ LinphoneCoreVTable v_table; @@ -654,7 +690,7 @@ CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); } pSuite = CU_add_suite("Register", init, uninit); - if (NULL == CU_add_test(pSuite, "simple register tester", simple_register)) { + if (NULL == CU_add_test(pSuite, "simple_register_tester", simple_register)) { return CU_get_error(); } if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { @@ -669,6 +705,17 @@ CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple_register_with_refresh", simple_register_with_refresh)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_auth_register_with_refresh", simple_auth_register_with_refresh)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "register_with_refresh_with_send_error", register_with_refresh_with_send_error)) { + return CU_get_error(); + } + + if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } From f03502ec00194698db4e6df3670e3d0d3908f131 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 24 Jan 2013 13:57:27 +0100 Subject: [PATCH 027/909] Add log callback to bellesip --- coreapi/bellesip_sal/sal_impl.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ab2700d05..07442977e 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -20,6 +20,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif + + +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: + ortp_level=ORTP_DEBUG; + break; + } + if (ortp_log_level_enabled(ortp_level)){ + ortp_logv(ortp_level,fmt,args); + } +} + void sal_enable_logs(){ belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); } @@ -345,6 +371,7 @@ Sal * sal_init(){ belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); belle_sip_header_user_agent_add_product(sal->user_agent,stack_string); belle_sip_object_ref(sal->user_agent); + belle_sip_set_log_handler(_belle_sip_log); sal->stack = belle_sip_stack_new(NULL); sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; From 54c81a8c280234e4003f26681811a2ebf7ef0364 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 24 Jan 2013 15:42:56 +0100 Subject: [PATCH 028/909] fix compilation warning --- coreapi/bellesip_sal/sal_impl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 07442977e..7c347d88e 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -40,6 +40,8 @@ void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { case BELLE_SIP_LOG_DEBUG: ortp_level=ORTP_DEBUG; break; + default: + break; } if (ortp_log_level_enabled(ortp_level)){ ortp_logv(ortp_level,fmt,args); From 5ac4b44a7f44ea52ce2720ed21fc2fceaad7f6c1 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 25 Jan 2013 10:04:38 +0100 Subject: [PATCH 029/909] Add missing liblinphone_gitversio.h file --- build/android/liblinphone_gitversion.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/android/liblinphone_gitversion.h diff --git a/build/android/liblinphone_gitversion.h b/build/android/liblinphone_gitversion.h new file mode 100644 index 000000000..50e8a106e --- /dev/null +++ b/build/android/liblinphone_gitversion.h @@ -0,0 +1 @@ +#define LIBLINPHONE_GIT_VERSION "unknown" From fce34adbe9958e2534069dfccd0256019452aa08 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 29 Jan 2013 14:24:20 +0100 Subject: [PATCH 030/909] split liblinphone_tester --- coreapi/bellesip_sal/sal_op_call.c | 6 + tester/Makefile.am | 4 +- tester/call_tester.c | 277 ++++++++++++++ tester/liblinphone_tester.c | 566 +---------------------------- tester/liblinphone_tester.h | 89 +++++ tester/message_tester.c | 43 +++ tester/presence_tester.c | 79 ++++ tester/register_tester.c | 226 ++++++++++++ 8 files changed, 742 insertions(+), 548 deletions(-) create mode 100644 tester/call_tester.c create mode 100644 tester/liblinphone_tester.h create mode 100644 tester/message_tester.c create mode 100644 tester/presence_tester.c create mode 100644 tester/register_tester.c diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 857818d87..74db3bba1 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -473,6 +473,12 @@ int sal_call_accept(SalOp*h){ belle_sip_response_t *response; belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(h); belle_sip_header_contact_t* contact_header; + + if (!h->pending_server_trans) { + ms_error("No transaction to accept for op [%p]",h); + return -1; + } + /* sends a 200 OK */ response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200); diff --git a/tester/Makefile.am b/tester/Makefile.am index 375b22912..e1d2c692f 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -4,7 +4,7 @@ if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester TESTS=$(noinst_PROGRAMS) -liblinphone_tester_SOURCES= liblinphone_tester.c +liblinphone_tester_SOURCES= liblinphone_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) @@ -12,7 +12,7 @@ liblinphone_tester_SOURCES= liblinphone_tester.c #liblinphone_tester_LDFLAGS=$(CUNIT_LIBS) -INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi +AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi LDADD=$(top_builddir)/coreapi/liblinphone.la diff --git a/tester/call_tester.c b/tester/call_tester.c new file mode 100644 index 000000000..b15004264 --- /dev/null +++ b/tester/call_tester.c @@ -0,0 +1,277 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + +static int init(void) { + return 0; +} +static int uninit(void) { + return 0; +} + + +static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(callee_mgr->lc,&proxy); + int retry=0; + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + + + CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); + + while ((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging<1 + || caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia<1) && retry++ <20) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(100000); + } + + + CU_ASSERT_TRUE_FATAL(caller_mgr->stat.number_of_LinphoneCallOutgoingRinging|caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia); + + linphone_core_get_default_proxy(caller_mgr->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + linphone_address_destroy(identity); + + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); + /*just to sleep*/ + return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,1) + && + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,1); + +} +static void simple_call() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; + + + + linphone_core_invite(lc_marie,"pauline"); + + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); + + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(lc_marie,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); + + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); + /*just to sleep*/ + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_ringing_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_early_declined() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + LinphoneCall* in_call=linphone_core_get_current_call(marie->lc); + linphone_call_ref(in_call); + + linphone_core_terminate_call(marie->lc,in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(in_call); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_terminated_by_caller() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_paused_resumed() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(pauline->lc); + + linphone_core_pause_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + + linphone_core_resume_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_srtp() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_early_media() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +int call_test_suite () { + CU_pSuite pSuite = CU_add_suite("Call", init, uninit); + if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_early_media", call_early_media)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { + return CU_get_error(); + } + + + return 0; +} diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index b99b0871e..adf1526c8 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -19,10 +19,11 @@ #include "CUnit/Basic.h" #include "linphonecore.h" #include "private.h" +#include "liblinphone_tester.h" -const char *test_domain="sipopen.example.org"; -const char *auth_domain="sip.example.org"; +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"; @@ -40,7 +41,7 @@ static void core_init_test(void) { linphone_core_destroy(lc); } -static LinphoneAddress * create_linphone_address(const char * domain) { +LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(addr); linphone_address_set_username(addr,test_username); @@ -54,66 +55,14 @@ static LinphoneAddress * create_linphone_address(const char * domain) { return addr; } static void linphone_address_test(void) { - ms_free(create_linphone_address(NULL)); + linphone_address_destroy(create_linphone_address(NULL)); } -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_LinphoneMessageReceived; - - int number_of_NewSubscriptionRequest; - int number_of_NotifyReceived; -}stats; static stats global_stat; -static void reset_counters( stats* counters) { - memset(counters,0,sizeof(stats)); -} -static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ - 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)); - stats* counters = (stats*)linphone_core_get_user_data(lc); - switch (cstate) { - case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; - case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; - case LinphoneRegistrationOk:counters->number_of_LinphoneRegistrationOk++;break; - case LinphoneRegistrationCleared:counters->number_of_LinphoneRegistrationCleared++;break; - case LinphoneRegistrationFailed:counters->number_of_LinphoneRegistrationFailed++;break; - default: - CU_FAIL("unexpected event");break; - } - -} -static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { +void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); @@ -124,7 +73,7 @@ static void auth_info_requested(LinphoneCore *lc, const char *realm, const char } -static LinphoneCore* create_lc_with_auth(unsigned int with_auth) { +LinphoneCore* create_lc_with_auth(unsigned int with_auth) { LinphoneCoreVTable v_table; LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); @@ -136,143 +85,12 @@ static LinphoneCore* create_lc_with_auth(unsigned int with_auth) { linphone_core_set_user_data(lc,&global_stat); return lc; } -static LinphoneCore* create_lc() { - return create_lc_with_auth(0); -} -static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - int retry=0; - LCSipTransports transport = {5070,5070,0,5071}; - - CU_ASSERT_PTR_NOT_NULL_FATAL(lc); - stats* counters = (stats*)linphone_core_get_user_data(lc); - reset_counters(counters); - linphone_core_set_sip_transports(lc,&transport); - LinphoneProxyConfig* proxy_cfg; - - proxy_cfg = linphone_proxy_config_new(); - - LinphoneAddress *from = create_linphone_address(domain); - - linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); - const char* server_addr = linphone_address_get_domain(from); - - linphone_proxy_config_enable_register(proxy_cfg,TRUE); - linphone_proxy_config_expires(proxy_cfg,1); - if (route) { - linphone_proxy_config_set_route(proxy_cfg,route); - linphone_proxy_config_set_server_addr(proxy_cfg,route); - } else { - linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); - } - linphone_address_destroy(from); - - linphone_core_add_proxy_config(lc,proxy_cfg); - linphone_core_set_default_proxy(lc,proxy_cfg); - - while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { - linphone_core_iterate(lc); - ms_usleep(100000); - } - CU_ASSERT_TRUE_FATAL(linphone_proxy_config_is_registered(proxy_cfg)); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1+(refresh!=0)); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); - -} -static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - stats* counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh_base(lc,refresh,domain,route); - linphone_core_destroy(lc); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); - +void reset_counters( stats* counters) { + memset(counters,0,sizeof(stats)); } -static void register_with_refresh_with_send_error(void) { - int retry=0; - LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = (stats*)linphone_core_get_user_data(lc); - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - - register_with_refresh_base(lc,TRUE,auth_domain,NULL); - /*simultate a network error*/ - sal_set_send_error(lc->sal, -1); - while (counters->number_of_LinphoneRegistrationFailed<1 && retry++ <20) { - linphone_core_iterate(lc); - ms_usleep(100000); - } - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); - linphone_core_destroy(lc); - - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); - -} -static void simple_register(){ - LinphoneCore* lc = create_lc(); - stats* counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh(lc,FALSE,NULL,NULL); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); -} - - -/*take care of min expires configuration from server*/ -static void simple_register_with_refresh() { - LinphoneCore* lc = create_lc(); - stats* counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh(lc,TRUE,NULL,NULL); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); -} - -static void simple_auth_register_with_refresh() { - LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh(lc,TRUE,auth_domain,NULL); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); -} - -static void simple_tcp_register(){ - char route[256]; - sprintf(route,"sip:%s;transport=tcp",test_domain); - LinphoneCore* lc = create_lc(); - register_with_refresh(lc,FALSE,NULL,route); -} -static void simple_tls_register(){ - char route[256]; - sprintf(route,"sip:%s;transport=tls",test_domain); - LinphoneCore* lc = create_lc(); - register_with_refresh(lc,FALSE,NULL,route); -} - -static void simple_authenticated_register(){ - LinphoneCore* lc = create_lc(); - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - stats* counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh(lc,FALSE,auth_domain,NULL); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); -} - - - -static void authenticated_register_with_no_initial_credentials(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - memset (&v_table,0,sizeof(v_table)); - v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested; - lc = linphone_core_new(&v_table,NULL,NULL,NULL); - linphone_core_set_user_data(lc,&global_stat); - stats* counters = (stats*)linphone_core_get_user_data(lc); - counters->number_of_auth_info_requested=0; - register_with_refresh(lc,FALSE,auth_domain,NULL); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); -} - - -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count) { +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count) { LinphoneCore* lc; int retry=0; lc = linphone_core_new(v_table,NULL,file,NULL); @@ -291,17 +109,8 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,proxy_count); return lc; } -static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { - return configure_lc_from(v_table,"./tester/multi_account_lrc",3); -} -static void multiple_proxy(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); - linphone_core_destroy(lc); -} + + static 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); @@ -358,7 +167,7 @@ static void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NotifyReceived++; } -static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counteridentity); return mgr; } -static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { +void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); linphone_address_destroy(mgr->identity); free(mgr); } -static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { - LinphoneProxyConfig* proxy; - linphone_core_get_default_proxy(callee_mgr->lc,&proxy); - int retry=0; - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); - - /*linphone_core_invite(caller_mgr->lc,"pauline");*/ - - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); - CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); - - while ((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging<1 - || caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia<1) && retry++ <20) { - linphone_core_iterate(caller_mgr->lc); - linphone_core_iterate(callee_mgr->lc); - ms_usleep(100000); - } - - - CU_ASSERT_TRUE_FATAL(caller_mgr->stat.number_of_LinphoneCallOutgoingRinging|caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia); - - linphone_core_get_default_proxy(caller_mgr->lc,&proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); - linphone_address_destroy(identity); - - linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); - - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); - /*just to sleep*/ - return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,1) - && - wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,1); - -} -static void simple_call() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - LinphoneCore* lc_marie=marie->lc; - LinphoneCore* lc_pauline=pauline->lc; - stats* stat_marie=&marie->stat; - stats* stat_pauline=&pauline->stat; - - - - linphone_core_invite(lc_marie,"pauline"); - - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); - - LinphoneProxyConfig* proxy; - linphone_core_get_default_proxy(lc_marie,&proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); - linphone_address_destroy(identity); - - linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); - /*just to sleep*/ - wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); - linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -static void call_canceled() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); - linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); - - linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); - linphone_call_unref(out_call); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -static void call_ringing_canceled() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); - linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); - - linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); - //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); - linphone_call_unref(out_call); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void call_early_declined() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); - linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); - LinphoneCall* in_call=linphone_core_get_current_call(marie->lc); - linphone_call_ref(in_call); - - linphone_core_terminate_call(marie->lc,in_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); - CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); - linphone_call_unref(in_call); - linphone_call_unref(out_call); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void call_terminated_by_caller() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - CU_ASSERT_TRUE(call(pauline,marie)); - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void call_paused_resumed() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - LinphoneCall* call_obj; - - CU_ASSERT_TRUE(call(pauline,marie)); - call_obj = linphone_core_get_current_call(pauline->lc); - - linphone_core_pause_call(pauline->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); - - linphone_core_resume_call(pauline->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void call_srtp() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); - linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); - - CU_ASSERT_TRUE(call(pauline,marie)); - - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); - - /*just to sleep*/ - linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -static void text_message() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); - linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void simple_publish() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneProxyConfig* proxy; - linphone_core_get_default_proxy(marie->lc,&proxy); - linphone_proxy_config_edit(proxy); - linphone_proxy_config_enable_publish(proxy,TRUE); - linphone_proxy_config_done(proxy); - linphone_core_iterate(marie->lc); - linphone_core_manager_destroy(marie); -} - - -static void simple_subscribe() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); - CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); - LinphoneFriend* friend = (LinphoneFriend*) marie_friends->data; - linphone_friend_edit(friend); - linphone_friend_enable_subscribes(friend,TRUE); - linphone_friend_done(friend); - - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1)); - - linphone_core_manager_destroy(marie); - CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ - - linphone_core_manager_destroy(pauline); -} -static void unsubscribe_while_subscribing() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); - LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ - linphone_friend_edit(friend); - linphone_friend_enable_subscribes(friend,TRUE); - linphone_friend_done(friend); - linphone_core_add_friend(marie->lc,friend); - linphone_core_iterate(marie->lc); - linphone_core_manager_destroy(marie); - -} - -static void call_early_media() { - LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_early_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - - - CU_ASSERT_TRUE(call(pauline,marie)); - - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); - /*just to sleep*/ - linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - int init_test_suite () { CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); @@ -689,78 +227,14 @@ CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); return CU_get_error(); } - pSuite = CU_add_suite("Register", init, uninit); - if (NULL == CU_add_test(pSuite, "simple_register_tester", simple_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "tls register tester", simple_tls_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_register_with_refresh", simple_register_with_refresh)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_auth_register_with_refresh", simple_auth_register_with_refresh)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "register_with_refresh_with_send_error", register_with_refresh_with_send_error)) { - return CU_get_error(); - } + register_test_suite(); + call_test_suite(); - if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { - return CU_get_error(); - } + message_test_suite(); - pSuite = CU_add_suite("Call", init, uninit); - if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_early_media", call_early_media)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { - return CU_get_error(); - } + presence_test_suite(); - pSuite = CU_add_suite("Message", init, uninit); - if (NULL == CU_add_test(pSuite, "text_message", text_message)) { - return CU_get_error(); - } - - pSuite = CU_add_suite("Presence", init, uninit); - if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "unsubscribe_while_subscribing", unsubscribe_while_subscribing)) { - return CU_get_error(); - } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h new file mode 100644 index 000000000..152893ec7 --- /dev/null +++ b/tester/liblinphone_tester.h @@ -0,0 +1,89 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef LIBLINPHONE_TESTER_H_ +#define LIBLINPHONE_TESTER_H_ + + + +const char* test_domain; +const char* auth_domain; +const char* test_username; +const char* test_password; + + + +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_LinphoneMessageReceived; + + int number_of_NewSubscriptionRequest; + int number_of_NotifyReceived; +}stats; +typedef struct _LinphoneCoreManager { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + LinphoneAddress* identity; +} LinphoneCoreManager; + + +LinphoneCoreManager* linphone_core_manager_new(const char* rc_file); +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 auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; +LinphoneAddress * create_linphone_address(const char * domain); +LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count); +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); + +int call_test_suite (); +int register_test_suite (); +int message_test_suite (); +int presence_test_suite (); + +#endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/message_tester.c b/tester/message_tester.c new file mode 100644 index 000000000..2658834d9 --- /dev/null +++ b/tester/message_tester.c @@ -0,0 +1,43 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + +static void text_message() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +int message_test_suite () { + CU_pSuite pSuite = CU_add_suite("Message", NULL, NULL); + if (NULL == CU_add_test(pSuite, "text_message", text_message)) { + return CU_get_error(); + } + return 0; +} diff --git a/tester/presence_tester.c b/tester/presence_tester.c new file mode 100644 index 000000000..7df079b0c --- /dev/null +++ b/tester/presence_tester.c @@ -0,0 +1,79 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + +static void simple_publish() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + linphone_core_iterate(marie->lc); + linphone_core_manager_destroy(marie); +} + + +static void simple_subscribe() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); + LinphoneFriend* friend = (LinphoneFriend*) marie_friends->data; + linphone_friend_edit(friend); + linphone_friend_enable_subscribes(friend,TRUE); + linphone_friend_done(friend); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1)); + + linphone_core_manager_destroy(marie); + CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(pauline); +} +static void unsubscribe_while_subscribing() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneFriend* friend = linphone_friend_new_with_addr("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); + +} + +int presence_test_suite () { + CU_pSuite pSuite = CU_add_suite("Presence", NULL, NULL); + if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "unsubscribe_while_subscribing", unsubscribe_while_subscribing)) { + return CU_get_error(); + } + return 0; +} diff --git a/tester/register_tester.c b/tester/register_tester.c new file mode 100644 index 000000000..80da637c5 --- /dev/null +++ b/tester/register_tester.c @@ -0,0 +1,226 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + + +static LinphoneCore* create_lc() { + return create_lc_with_auth(0); +} + + +void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + 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)); + stats* counters = (stats*)linphone_core_get_user_data(lc); + switch (cstate) { + case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; + case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; + case LinphoneRegistrationOk:counters->number_of_LinphoneRegistrationOk++;break; + case LinphoneRegistrationCleared:counters->number_of_LinphoneRegistrationCleared++;break; + case LinphoneRegistrationFailed:counters->number_of_LinphoneRegistrationFailed++;break; + default: + CU_FAIL("unexpected event");break; + } + +} +static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + int retry=0; + LCSipTransports transport = {5070,5070,0,5071}; + + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + stats* counters = (stats*)linphone_core_get_user_data(lc); + reset_counters(counters); + linphone_core_set_sip_transports(lc,&transport); + LinphoneProxyConfig* proxy_cfg; + + proxy_cfg = linphone_proxy_config_new(); + + LinphoneAddress *from = create_linphone_address(domain); + + linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); + const char* server_addr = linphone_address_get_domain(from); + + linphone_proxy_config_enable_register(proxy_cfg,TRUE); + linphone_proxy_config_expires(proxy_cfg,1); + if (route) { + linphone_proxy_config_set_route(proxy_cfg,route); + linphone_proxy_config_set_server_addr(proxy_cfg,route); + } else { + linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); + } + linphone_address_destroy(from); + + linphone_core_add_proxy_config(lc,proxy_cfg); + linphone_core_set_default_proxy(lc,proxy_cfg); + + while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_TRUE_FATAL(linphone_proxy_config_is_registered(proxy_cfg)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + +} +static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh_base(lc,refresh,domain,route); + linphone_core_destroy(lc); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); + + +} + +static void register_with_refresh_with_send_error(void) { + int retry=0; + LinphoneCore* lc = create_lc_with_auth(1); + stats* counters = (stats*)linphone_core_get_user_data(lc); + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base(lc,TRUE,auth_domain,NULL); + /*simultate a network error*/ + sal_set_send_error(lc->sal, -1); + while (counters->number_of_LinphoneRegistrationFailed<1 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); + linphone_core_destroy(lc); + + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + +} +static void simple_register(){ + LinphoneCore* lc = create_lc(); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,FALSE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + + +/*take care of min expires configuration from server*/ +static void simple_register_with_refresh() { + LinphoneCore* lc = create_lc(); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,TRUE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + +static void simple_auth_register_with_refresh() { + LinphoneCore* lc = create_lc_with_auth(1); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,TRUE,auth_domain,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); +} + +static void simple_tcp_register(){ + char route[256]; + sprintf(route,"sip:%s;transport=tcp",test_domain); + LinphoneCore* lc = create_lc(); + register_with_refresh(lc,FALSE,NULL,route); +} +static void simple_tls_register(){ + char route[256]; + sprintf(route,"sip:%s;transport=tls",test_domain); + LinphoneCore* lc = create_lc(); + register_with_refresh(lc,FALSE,NULL,route); +} + +static void simple_authenticated_register(){ + LinphoneCore* lc = create_lc(); + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,FALSE,auth_domain,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + + + +static void authenticated_register_with_no_initial_credentials(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + v_table.auth_info_requested=auth_info_requested; + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + linphone_core_set_user_data(lc,&stat); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_auth_info_requested=0; + register_with_refresh(lc,FALSE,auth_domain,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); +} + +static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { + return configure_lc_from(v_table,"./tester/multi_account_lrc",3); +} + +static void multiple_proxy(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + memset (&v_table,0,sizeof(LinphoneCoreVTable)); + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); + linphone_core_destroy(lc); +} + +int register_test_suite () { + + CU_pSuite pSuite = CU_add_suite("Register", NULL, NULL); + if (NULL == CU_add_test(pSuite, "simple_register_tester", simple_register)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "tls register tester", simple_tls_register)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_register_with_refresh", simple_register_with_refresh)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "simple_auth_register_with_refresh", simple_auth_register_with_refresh)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "register_with_refresh_with_send_error", register_with_refresh_with_send_error)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { + return CU_get_error(); + } + + return 0; +} From 3459d96c4e7fdfcb689591634c7f138f36a44f4a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 30 Jan 2013 10:25:24 +0100 Subject: [PATCH 031/909] refactor unit test --- coreapi/bellesip_sal/sal_impl.c | 22 +++++++++--- tester/call_tester.c | 31 +++++++++++++++++ tester/flexisip.conf | 8 ++--- tester/liblinphone_tester.c | 55 ------------------------------ tester/liblinphone_tester.h | 5 +++ tester/message_tester.c | 8 +++++ tester/multi_account_lrc | 14 ++++---- tester/presence_tester.c | 17 ++++++++++ tester/register_tester.c | 59 ++++++++++++++++++++++++++++++--- tester/userdb.conf | 10 +++--- 10 files changed, 150 insertions(+), 79 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7c347d88e..33d44cec7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -449,9 +449,12 @@ void sal_uninit(Sal* sal){ return ; }; -int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ +int sal_add_listen_port(Sal *ctx, SalAddress* addr){ int result; - belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,addr,port,sal_transport_to_string(tr)); + belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack + ,sal_address_get_domain(addr) + ,sal_address_get_port_int(addr) + ,sal_transport_to_string(sal_address_get_transport(addr))); if (lp) { result = belle_sip_provider_add_listening_point(ctx->prov,lp); } else { @@ -459,6 +462,16 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i } return result; } +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure) { + SalAddress* sal_addr = sal_address_new(NULL); + int result; + sal_address_set_domain(sal_addr,addr); + sal_address_set_port_int(sal_addr,port); + sal_address_set_transport(sal_addr,tr); + result = sal_add_listen_port(ctx,sal_addr); + sal_address_destroy(sal_addr); + return result; +} static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { belle_sip_provider_remove_listening_point(prov,lp); } @@ -557,8 +570,9 @@ const char *sal_get_root_ca(Sal* ctx) { return NULL; } int sal_reset_transports(Sal *ctx){ - ms_warning("sal_reset_transports() not implemented in this version."); - return -1; + ms_message("reseting transport"); + belle_sip_provider_clean_channels(ctx->prov); + return 0; } void sal_set_dscp(Sal *ctx, int dscp){ ms_warning("sal_set_dscp not implemented"); diff --git a/tester/call_tester.c b/tester/call_tester.c index b15004264..a0e0923ee 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -29,6 +29,37 @@ static int uninit(void) { return 0; } +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); + + ms_message("call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(cstate)); + ms_free(to); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + switch (cstate) { + case LinphoneCallIncomingReceived:counters->number_of_LinphoneCallIncomingReceived++;break; + case LinphoneCallOutgoingInit :counters->number_of_LinphoneCallOutgoingInit++;break; + case LinphoneCallOutgoingProgress :counters->number_of_LinphoneCallOutgoingProgress++;break; + case LinphoneCallOutgoingRinging :counters->number_of_LinphoneCallOutgoingRinging++;break; + case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneCallOutgoingEarlyMedia++;break; + case LinphoneCallConnected :counters->number_of_LinphoneCallConnected++;break; + case LinphoneCallStreamsRunning :counters->number_of_LinphoneCallStreamsRunning++;break; + case LinphoneCallPausing :counters->number_of_LinphoneCallPausing++;break; + case LinphoneCallPaused :counters->number_of_LinphoneCallPaused++;break; + case LinphoneCallResuming :counters->number_of_LinphoneCallResuming++;break; + case LinphoneCallRefered :counters->number_of_LinphoneCallRefered++;break; + case LinphoneCallError :counters->number_of_LinphoneCallError++;break; + case LinphoneCallEnd :counters->number_of_LinphoneCallEnd++;break; + case LinphoneCallPausedByRemote :counters->number_of_LinphoneCallPausedByRemote++;break; + case LinphoneCallUpdatedByRemote :counters->number_of_LinphoneCallUpdatedByRemote++;break; + case LinphoneCallIncomingEarlyMedia :counters->number_of_LinphoneCallIncomingEarlyMedia++;break; + case LinphoneCallUpdating :counters->number_of_LinphoneCallUpdating++;break; + case LinphoneCallReleased :counters->number_of_LinphoneCallReleased++;break; + default: + CU_FAIL("unexpected event");break; + } +} static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; diff --git a/tester/flexisip.conf b/tester/flexisip.conf index c59ed0a5e..de5809da9 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -18,7 +18,7 @@ auto-respawn=true # List of white space separated host names pointing to this machine. # This is to prevent loops while routing SIP messages. # Default value: localhost -aliases=localhost sipopen.example.org sip.example.org +aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.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' @@ -130,12 +130,12 @@ enabled=true # 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' +filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' # List of whitespace separated domain names to challenge. Others # are denied. # Default value: -auth-domains= sip.example.org +auth-domains= sip.example.org auth.example.org auth1.example.org auth2.example.org # List of whitespace separated IP which will not be challenged. # Default value: @@ -261,7 +261,7 @@ 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 +reg-domains=localhost sip.example.org sipopen.example.org auth1.example.org # Maximum number of registered contacts of an address of record. # Default value: 15 diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index adf1526c8..8bfc5352b 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -111,62 +111,7 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in } -static 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); - ms_message("call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(cstate)); - ms_free(to); - ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); - switch (cstate) { - case LinphoneCallIncomingReceived:counters->number_of_LinphoneCallIncomingReceived++;break; - case LinphoneCallOutgoingInit :counters->number_of_LinphoneCallOutgoingInit++;break; - case LinphoneCallOutgoingProgress :counters->number_of_LinphoneCallOutgoingProgress++;break; - case LinphoneCallOutgoingRinging :counters->number_of_LinphoneCallOutgoingRinging++;break; - case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneCallOutgoingEarlyMedia++;break; - case LinphoneCallConnected :counters->number_of_LinphoneCallConnected++;break; - case LinphoneCallStreamsRunning :counters->number_of_LinphoneCallStreamsRunning++;break; - case LinphoneCallPausing :counters->number_of_LinphoneCallPausing++;break; - case LinphoneCallPaused :counters->number_of_LinphoneCallPaused++;break; - case LinphoneCallResuming :counters->number_of_LinphoneCallResuming++;break; - case LinphoneCallRefered :counters->number_of_LinphoneCallRefered++;break; - case LinphoneCallError :counters->number_of_LinphoneCallError++;break; - case LinphoneCallEnd :counters->number_of_LinphoneCallEnd++;break; - case LinphoneCallPausedByRemote :counters->number_of_LinphoneCallPausedByRemote++;break; - case LinphoneCallUpdatedByRemote :counters->number_of_LinphoneCallUpdatedByRemote++;break; - case LinphoneCallIncomingEarlyMedia :counters->number_of_LinphoneCallIncomingEarlyMedia++;break; - case LinphoneCallUpdating :counters->number_of_LinphoneCallUpdating++;break; - case LinphoneCallReleased :counters->number_of_LinphoneCallReleased++;break; - default: - CU_FAIL("unexpected event");break; - } -} - -static void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { - char* from=linphone_address_as_string(from_address); - ms_message("Message from [%s] is [%s]",from,message); - ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); - counters->number_of_LinphoneMessageReceived++; -} - -void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ - char* from=linphone_address_as_string(linphone_friend_get_address(lf)); - ms_message("New subscription request from [%s] url [%s]",from,url); - ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); - counters->number_of_NewSubscriptionRequest++; - linphone_core_add_friend(lc,lf); /*accept subscription*/ - -} -static void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { - char* from=linphone_address_as_string(linphone_friend_get_address(lf)); - ms_message("New Notify request from [%s] ",from); - ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); - counters->number_of_NotifyReceived++; -} bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counternumber_of_LinphoneMessageReceived++; +} + static void text_message() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc index 6f362c533..df91cf251 100644 --- a/tester/multi_account_lrc +++ b/tester/multi_account_lrc @@ -14,7 +14,7 @@ realm="auth.example.org" username=pauline userid=pauline passwd=secret -realm="auth.example.org" +realm="sip.example.org" [auth_info_2] username=liblinphone_tester @@ -26,26 +26,26 @@ realm="auth1.example.org" username=marie userid=marie passwd=secret -realm="auth.example.org" +realm="sip.example.org" [proxy_0] -reg_proxy=auth.example.org;transport=tls -reg_identity=sip:pauline@auth.example.org +reg_proxy=sip.example.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=auth.example.org;transport=tcp -reg_identity=sip:marie@auth.example.org +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=auth.example.org +reg_proxy=auth1.example.org reg_identity=sip:liblinphone_tester@auth1.example.org reg_expires=3600 reg_sendregister=1 diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 7df079b0c..eb4bb1b95 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -22,6 +22,23 @@ #include "liblinphone_tester.h" +void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("New subscription request from [%s] url [%s]",from,url); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_NewSubscriptionRequest++; + linphone_core_add_friend(lc,lf); /*accept subscription*/ + +} +void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("New Notify request from [%s] ",from); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_NotifyReceived++; +} + static void simple_publish() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneProxyConfig* proxy; diff --git a/tester/register_tester.c b/tester/register_tester.c index 80da637c5..826c3703d 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -45,7 +45,7 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } } -static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { +static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route,bool_t late_auth_info) { int retry=0; LCSipTransports transport = {5070,5070,0,5071}; @@ -77,16 +77,23 @@ static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const ch while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { linphone_core_iterate(lc); + if (counters->number_of_auth_info_requested>0 && late_auth_info) { + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + } ms_usleep(100000); } CU_ASSERT_TRUE_FATAL(linphone_proxy_config_is_registered(proxy_cfg)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); } +static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + register_with_refresh_base_2(lc,refresh,domain,route,FALSE); +} static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { stats* counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh_base(lc,refresh,domain,route); @@ -161,8 +168,6 @@ static void simple_authenticated_register(){ CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } - - static void authenticated_register_with_no_initial_credentials(){ LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -177,6 +182,27 @@ static void authenticated_register_with_no_initial_credentials(){ register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); } +static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username) { + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_auth_info_requested++; +} + +static void authenticated_register_with_late_credentials(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + v_table.auth_info_requested=auth_info_requested2; + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + linphone_core_set_user_data(lc,&stat); + stats* counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh_base_2(lc,FALSE,auth_domain,NULL,TRUE); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); +} static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { return configure_lc_from(v_table,"./tester/multi_account_lrc",3); @@ -191,6 +217,24 @@ static void multiple_proxy(){ linphone_core_destroy(lc); } +static void network_state_change(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int register_ok; + stats* counters ; + + memset (&v_table,0,sizeof(LinphoneCoreVTable)); + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); + counters = (stats*)linphone_core_get_user_data(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + linphone_core_set_network_reachable(lc,FALSE); + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); + linphone_core_set_network_reachable(lc,TRUE); + wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); + linphone_core_destroy(lc); +} + int register_test_suite () { CU_pSuite pSuite = CU_add_suite("Register", NULL, NULL); @@ -209,6 +253,9 @@ int register_test_suite () { if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "authenticated_register_with_late_credentials", authenticated_register_with_late_credentials)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "simple_register_with_refresh", simple_register_with_refresh)) { return CU_get_error(); } @@ -222,5 +269,9 @@ int register_test_suite () { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "network_state_change", network_state_change)) { + return CU_get_error(); + } + return 0; } diff --git a/tester/userdb.conf b/tester/userdb.conf index 4be5cd891..3326e1f48 100644 --- a/tester/userdb.conf +++ b/tester/userdb.conf @@ -1,8 +1,8 @@ +liblinphone_tester@sip.example.org secret liblinphone_tester@auth.example.org secret liblinphone_tester@auth1.example.org secret -liblinphone_tester@auth2.example.org secret - -pauline@auth.example.org secret -marie@auth.example.org secret -bellesip@auth.example.org secret +tester@sip.example.org secret +pauline@sip.example.org secret +marie@sip.example.org secret +bellesip@sip.example.org secret From 08281caa49a86a05511a93fb68ebe5db12aef772 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 31 Jan 2013 16:54:01 +0100 Subject: [PATCH 032/909] implement io error for register --- coreapi/bellesip_sal/sal_impl.c | 15 +++++++- coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 3 ++ coreapi/bellesip_sal/sal_op_registration.c | 43 +++------------------- coreapi/sal.h | 2 + tester/register_tester.c | 22 +++++++++++ 6 files changed, 47 insertions(+), 40 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 33d44cec7..b037bbf60 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -107,7 +107,17 @@ static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminat } } static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); + belle_sip_client_transaction_t*client_transaction; + SalOp* op; + if (belle_sip_object_is_instance_of(BELLE_SIP_OBJECT(belle_sip_io_error_event_get_source(event)),BELLE_SIP_TYPE_ID(belle_sip_client_transaction_t))) { + client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); + op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + if (op->callbacks.process_io_error) { + op->callbacks.process_io_error(op,event); + } + } else { + ms_error("process_io_error not implemented yet for non transaction"); + } } static void process_request_event(void *sal, const belle_sip_request_event_t *event) { SalOp* op=NULL; @@ -580,3 +590,6 @@ void sal_set_dscp(Sal *ctx, int 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); +} diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 74db3bba1..a39cc3dbb 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -82,7 +82,7 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription } static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); + ms_error("call_process_io_error not implemented yet"); } static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op=(SalOp*)ctx; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index bd5af0598..a22c5392a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -34,6 +34,7 @@ void sal_op_release(SalOp *op){ belle_sip_refresher_stop(op->registration_refresher); belle_sip_object_unref(op->registration_refresher); } + if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); __sal_op_free(op); return ; } @@ -135,7 +136,9 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); if ( strcmp("INVITE",belle_sip_request_get_method(request))==0) { + if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ + belle_sip_object_ref(op->pending_inv_client_trans); } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index d4c6c37eb..4f5036ae2 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -21,7 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("process_io_error not implemented yet"); + SalOp* op = (SalOp*)user_ctx; + ms_error("register_process_io_error io error reported for [%s]",sal_op_get_proxy(op)); + if (op->registration_refresher) { + op->base.root->callbacks.register_failure(op,SalErrorFailure,SalErrorFailure,"io error"); + } } static void register_refresher_listener ( const belle_sip_refresher_t* refresher @@ -46,53 +50,16 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_response_t* response = belle_sip_response_event_get_response(event); -/* belle_sip_request_t* original_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_header_expires_t* expires_header; - belle_sip_header_contact_t* original_contact=belle_sip_message_get_header_by_type(original_request,belle_sip_header_contact_t); - const belle_sip_list_t* contact_header_list; - char* tmp_string;*/ - - belle_sip_header_service_route_t* service_route; belle_sip_header_address_t* service_route_address=NULL; int response_code = belle_sip_response_get_status_code(response); - /*int expires=-1;*/ if (response_code<200) return;/*nothing to do*/ switch (response_code) { case 200: { -/* contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); - if (contact_header_list) { - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)original_contact); - if (!contact_header_list) { - reset header list - contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); - contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_not_equals, (const void*)sal_op_get_contact_address(op)); - } - if (!contact_header_list) { - tmp_string=belle_sip_object_to_string(BELLE_SIP_OBJECT(original_contact)); - ms_error("no matching contact neither for [%s] nor [%s]", tmp_string, sal_op_get_contact(op)); - belle_sip_free(tmp_string); - } else { - expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header_list->data)); - } - } - - if (expires<0 ) { - no contact with expire, looking for Expires header - if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { - expires = belle_sip_header_expires_get_expires(expires_header); - } - } - if (expires<0) { - if ((expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(original_request),BELLE_SIP_EXPIRES))) { - expires = belle_sip_header_expires_get_expires(expires_header); - ms_message("Neither Expires header nor corresponding Contact header found, using expires value [%i] from request",expires); - } - }*/ /*check service route rfc3608*/ 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))); diff --git a/coreapi/sal.h b/coreapi/sal.h index 1084ebce6..0f5c646b9 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -491,4 +491,6 @@ void __sal_op_free(SalOp *b); /*test api*/ /*0 for no error*/ void sal_set_send_error(Sal *sal,int value); +/*1 for no error*/ +void sal_set_recv_error(Sal *sal,int value); #endif diff --git a/tester/register_tester.c b/tester/register_tester.c index 826c3703d..a655a8c86 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -235,6 +235,25 @@ static void network_state_change(){ linphone_core_destroy(lc); } +static void io_recv_error(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int register_ok; + stats* counters ; + + memset (&v_table,0,sizeof(LinphoneCoreVTable)); + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); + counters = (stats*)linphone_core_get_user_data(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + sal_set_recv_error(lc->sal, 0); + + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-1 /*because 1 udp*/)); + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_destroy(lc); +} + int register_test_suite () { CU_pSuite pSuite = CU_add_suite("Register", NULL, NULL); @@ -272,6 +291,9 @@ int register_test_suite () { if (NULL == CU_add_test(pSuite, "network_state_change", network_state_change)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "io_recv_error_0", io_recv_error)) { + return CU_get_error(); + } return 0; } From eb26ab5c1c2a1f8b721725a7063b9862b2e3ee78 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 4 Feb 2013 17:58:02 +0100 Subject: [PATCH 033/909] use transport from proxyconfig if not set in request uri --- coreapi/bellesip_sal/sal_impl.c | 12 ++++++-- coreapi/bellesip_sal/sal_op_registration.c | 7 ++--- coreapi/linphonecore.c | 23 +++++++++++++++ coreapi/private.h | 2 +- coreapi/sal.c | 2 ++ tester/register_tester.c | 33 ++++++++++++++++++++-- 6 files changed, 69 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b037bbf60..49ce7f649 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -216,6 +216,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev 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); + if (!client_transaction) { + ms_error("Unexpected stateless response, trashing"); + return; + } SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); 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)); @@ -355,12 +359,14 @@ static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *eve } } 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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); + 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); + +/* SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); if (op->calbacks.process_transaction_terminated) { op->calbacks.process_transaction_terminated(op,event); } else */{ - ms_error("Unhandled transaction terminated [%p]",event); + ms_error("Unhandled transaction terminated [%p]",client_transaction!=NULL?(void*)client_transaction:(void*)server_transaction); } } static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 4f5036ae2..df137d614 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -106,14 +106,14 @@ static void register_process_transaction_terminated(void *user_ctx, const belle_ /*if expire = -1, does not change expires*/ -static void send_register_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { +static int send_register_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); - sal_op_send_request(op,request); + return sal_op_send_request(op,request); } @@ -131,8 +131,7 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_uri_t* req_uri = belle_sip_request_get_uri(req); belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ - send_register_request_with_expires(op,req,expires); - return 0; + return send_register_request_with_expires(op,req,expires); } int sal_register_refresh(SalOp *op, int expires){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 435e505e8..455f80e71 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2427,6 +2427,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const const char *from=NULL; LinphoneProxyConfig *proxy=NULL,*dest_proxy=NULL; LinphoneAddress *parsed_url2=NULL; + SalAddress *route=NULL; + SalAddress *proxy_addr=NULL; char *real_url=NULL; LinphoneCall *call; bool_t use_ice = FALSE; @@ -2465,6 +2467,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (linphone_core_get_route(lc)) { sal_op_set_route(call->op,linphone_core_get_route(lc)); } + /* * rfc3608 6.1. Procedures at the UA @@ -2485,7 +2488,27 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const sal_op_add_route_address(call->op,linphone_proxy_config_get_service_route(proxy)); } /*else, no route*/ + if (!sal_op_get_route(call->op)) { + /*still no route, so try to build a route from proxy transport + identity host*/ + route=sal_address_new(NULL); + /*first, get domain and port from requerst uri*/ + sal_address_set_domain(route,sal_address_get_domain((SalAddress*)addr)); + sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)addr)); + /*next get transport either from request uri or from proxy if any*/ + if (sal_address_get_transport((SalAddress*)addr)) { + sal_address_set_transport(route,sal_address_get_transport((SalAddress*)addr)); + } else { + if (dest_proxy) + proxy_addr=sal_address_new(linphone_proxy_config_get_addr(dest_proxy)); + else if (proxy) + proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy)); + if (proxy_addr && sal_address_get_transport(proxy_addr)) + sal_address_set_transport(route,sal_address_get_transport(proxy_addr)); + } + sal_op_add_route_address(call->op,route); + + } if(linphone_core_add_call(lc,call)!= 0) { diff --git a/coreapi/private.h b/coreapi/private.h index 9e00cee0e..1a0876cfc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -298,7 +298,7 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); -const char * linphone_core_get_route(LinphoneCore *lc); + void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); void linphone_core_stop_waiting(LinphoneCore *lc); diff --git a/coreapi/sal.c b/coreapi/sal.c index 69c4cc04c..c73f5a889 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -300,6 +300,8 @@ 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*)address); + } else { + sal_op_set_route_address(op,address); } } void sal_op_set_from(SalOp *op, const char *from){ diff --git a/tester/register_tester.c b/tester/register_tester.c index a655a8c86..1a6d7eaf8 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -202,6 +202,7 @@ static void authenticated_register_with_late_credentials(){ stats* counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh_base_2(lc,FALSE,auth_domain,NULL,TRUE); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_destroy(lc); } static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { @@ -235,6 +236,32 @@ static void network_state_change(){ linphone_core_destroy(lc); } +static void transport_change(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int register_ok; + stats* counters ; + LCSipTransports sip_tr; + LCSipTransports sip_tr_orig; + memset(&sip_tr,0,sizeof(sip_tr)); + + memset (&v_table,0,sizeof(LinphoneCoreVTable)); + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); + counters = (stats*)linphone_core_get_user_data(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + linphone_core_get_sip_transports(lc,&sip_tr_orig); + sip_tr.udp_port=sip_tr_orig.udp_port; + + /*keep only udp*/ + linphone_core_set_sip_transports(lc,&sip_tr); + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+1)); + + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+2)); + + linphone_core_destroy(lc); +} + static void io_recv_error(){ LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -248,7 +275,7 @@ static void io_recv_error(){ register_ok=counters->number_of_LinphoneRegistrationOk; sal_set_recv_error(lc->sal, 0); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-1 /*because 1 udp*/)); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-1 /*because 1 udp*/)); sal_set_recv_error(lc->sal, 1); /*reset*/ linphone_core_destroy(lc); @@ -287,7 +314,9 @@ int register_test_suite () { if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "transport_change", transport_change)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "network_state_change", network_state_change)) { return CU_get_error(); } From 3d1c5e7ce121d0b9f66aee607ba038339c65f026 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 5 Feb 2013 15:02:03 +0100 Subject: [PATCH 034/909] fix call error reporting when dialog is not established yet --- coreapi/bellesip_sal/sal_impl.c | 6 +-- coreapi/bellesip_sal/sal_op_call.c | 63 +++++++--------------- coreapi/bellesip_sal/sal_op_impl.c | 4 +- coreapi/bellesip_sal/sal_op_registration.c | 8 ++- 4 files changed, 31 insertions(+), 50 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 49ce7f649..a0f5fe947 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -350,11 +350,11 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { -/* belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); + 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->callbacks.process_timeout) { + if (op && op->callbacks.process_timeout) { op->callbacks.process_timeout(op,event); - } else*/ { + } else { ms_error("Unhandled event timeout [%p]",event); } } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index a39cc3dbb..9a2f90790 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -86,9 +86,16 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event } static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op=(SalOp*)ctx; + if (op->dialog) { - op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); - op->state=SalOpStateTerminated; + if (belle_sip_dialog_get_previous_state(op->dialog) == BELLE_SIP_DIALOG_CONFIRMED) { + /*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=SalOpStateTerminated; + } else { + /*let the process response handle this case*/ + } + belle_sip_object_unref(op->dialog); op->dialog=NULL; } @@ -124,48 +131,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); } if (code >=400) { - switch(code) { - case 400: - error=SalErrorUnknown; - break; - case 404: - error=SalErrorFailure; - sr=SalReasonNotFound; - break; - case 415: - error=SalErrorFailure; - sr=SalReasonMedia; - break; - case 422: - ms_error ("422 not implemented yet");; - break; - case 480: - error=SalErrorFailure; - sr=SalReasonTemporarilyUnavailable; - break; - case 486: - error=SalErrorFailure; - sr=SalReasonBusy; - break; - case 487: - break; - case 600: - error=SalErrorFailure; - sr=SalReasonDoNotDisturb; - break; - case 603: - error=SalErrorFailure; - sr=SalReasonDeclined; - break; - default: - if (code>0){ - error=SalErrorFailure; - sr=SalReasonUnknown; - }else error=SalErrorNoResponse; - /* no break */ - } - + sal_compute_sal_errors_from_code(code,&error,&sr); op->base.root->callbacks.call_failure(op,error,sr,reason,code); + op->state=SalOpStateTerminated; if (reason_header != NULL){ ms_free(reason); } @@ -246,7 +214,14 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - ms_error("process_timeout not implemented yet"); + SalOp* op=(SalOp*)user_ctx; + if (!op->dialog) { + /*call terminated very early*/ + op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); + op->state=SalOpStateTerminated; + } 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) { ms_error("process_transaction_terminated not implemented yet"); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a22c5392a..d779249f2 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -119,8 +119,8 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_route_t* route_header; belle_sip_uri_t* outbound_proxy=NULL; MSList* iterator; - if (!op->dialog) { - /*don't put route header if dialog is in confirmed state*/ + 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*/ for(iterator=(MSList*)sal_op_get_route_addresses(op);iterator!=NULL;iterator=iterator->next) { if(!outbound_proxy) { /*first toute is outbound proxy*/ diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index df137d614..a8ac7e874 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -97,7 +97,13 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve } } static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - ms_error("process_timeout not implemented yet"); + SalOp* op = (SalOp*)user_ctx; + ms_error("register_process_timeout timeout error reported for [%s]",sal_op_get_proxy(op)); + if (!op->registration_refresher) { + op->base.root->callbacks.register_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout"); + } else { + /*refresher will report error*/ + } } static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { ms_error("process_transaction_terminated not implemented yet"); From e597db563c905bf9f019f6f02a6129807aee9682 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 6 Feb 2013 12:44:05 +0100 Subject: [PATCH 035/909] add sal keep alive implementation --- coreapi/bellesip_sal/sal_impl.c | 10 +++++++--- coreapi/bellesip_sal/sal_impl.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index a0f5fe947..4aa6f5bf8 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -472,6 +472,7 @@ int sal_add_listen_port(Sal *ctx, SalAddress* addr){ ,sal_address_get_port_int(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); } else { return -1; @@ -511,7 +512,11 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){ } /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ - ms_error("sal_set_keepalive_period not implemented yet"); + const belle_sip_list_t* iterator; + ctx->keep_alive=value; + for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) { + belle_sip_listening_point_set_keep_alive((belle_sip_listening_point_t*)iterator->data,ctx->keep_alive); + } return ; } /** @@ -519,8 +524,7 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ * 0 desactiaved * */ unsigned int sal_get_keepalive_period(Sal *ctx){ - ms_fatal("sal_get_keepalive_period not implemented yet"); - return -1; + return ctx->keep_alive; } void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 8a206be24..f29fabd7c 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -33,6 +33,7 @@ struct Sal{ void *up; /*user pointer*/ int session_expires; bool_t one_matching_codec; + unsigned int keep_alive; }; typedef enum SalOpSate { From ee5c80b9c6cad47578a0234f22326bba2475008e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 7 Feb 2013 18:51:21 +0100 Subject: [PATCH 036/909] rework contact management for request implement tcp keep alive --- coreapi/bellesip_sal/sal_impl.c | 10 +++-- coreapi/bellesip_sal/sal_impl.h | 3 ++ coreapi/bellesip_sal/sal_op_call.c | 13 +----- coreapi/bellesip_sal/sal_op_impl.c | 50 ++++++++++++++-------- coreapi/bellesip_sal/sal_op_presence.c | 4 +- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/linphonecore.c | 4 +- tester/call_tester.c | 29 +++++++++++++ 8 files changed, 78 insertions(+), 37 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 4aa6f5bf8..c7705138f 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -513,9 +513,13 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){ /*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) { - belle_sip_listening_point_set_keep_alive((belle_sip_listening_point_t*)iterator->data,ctx->keep_alive); + lp=(belle_sip_listening_point_t*)iterator->data; + if (ctx->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { + belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); + } } return ; } @@ -563,12 +567,10 @@ void sal_verify_server_cn(Sal *ctx, bool_t verify){ } void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { - ms_error("sal_use_tcp_tls_keepalive not implemented yet"); - return ; + ctx->use_tcp_tls_keep_alive=enabled; } int sal_iterate(Sal *sal){ - /*FIXME should be zero*/ belle_sip_stack_sleep(sal->stack,0); return 0; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index f29fabd7c..46692786b 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -34,6 +34,7 @@ struct Sal{ int session_expires; bool_t one_matching_codec; unsigned int keep_alive; + bool_t use_tcp_tls_keep_alive; }; typedef enum SalOpSate { @@ -80,8 +81,10 @@ void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog); 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_contact(SalOp* op, belle_sip_request_t* request) ; void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2b48c2329..60272addd 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -389,10 +389,6 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { } int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* req; - -/* belle_sip_client_transaction_t* client_transaction; - belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_header_route_t* route_header;*/ op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); @@ -402,7 +398,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ sal_op_fill_invite(op,req); sal_op_call_fill_cbs(op); - sal_op_send_request(op,req); + sal_op_send_request_with_contact(op,req); return 0; } @@ -519,14 +515,9 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti } int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); - /*belle_sdp_session_description_t* session_desc;*/ - belle_sip_header_contact_t* contact=belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); - /*need to add contact header for re-invite*/ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),BELLE_SIP_HEADER(contact)); sal_op_fill_invite(op, reinvite); - - return sal_op_send_request(op,reinvite); + return sal_op_send_request_with_contact(op,reinvite); } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ return h->base.remote_media;; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index d779249f2..6d6b7a955 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -54,21 +54,9 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna *username=op->auth_info?op->auth_info->username:NULL; return 0; } - -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_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) { + belle_sip_uri_t* req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)from_header)); belle_sip_header_contact_t* contact_header; - char token[10]; - - from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) - ,belle_sip_random_token(token,sizeof(token))); - to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); - req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); - 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 { @@ -76,6 +64,22 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,belle_sip_uri_new()); belle_sip_uri_set_user(belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact_header),belle_sip_uri_get_user(req_uri)); } + belle_sip_object_unref(req_uri); + return contact_header; +} +belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + char token[10]; + + from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) + ,belle_sip_random_token(token,sizeof(token))); + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + req=belle_sip_request_create( req_uri, method, @@ -85,7 +89,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { to_header, belle_sip_header_via_new(), 70); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->base.root->user_agent)); return req; } @@ -113,11 +117,13 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { sal_op_send_request(op,request); } -int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { + +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_header_route_t* route_header; belle_sip_uri_t* outbound_proxy=NULL; + belle_sip_header_contact_t* contact; MSList* iterator; 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*/ @@ -140,7 +146,10 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_object_ref(op->pending_inv_client_trans); } - + if (add_contact) { + contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); + } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ @@ -150,6 +159,13 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { } +int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { + return _sal_op_send_request_with_contact(op, request,FALSE); +} +int sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request) { + return _sal_op_send_request_with_contact(op, request,TRUE); +} + void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { switch(code) { case 400: diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 9da9e1080..590a92a18 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -591,7 +591,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); - return sal_op_send_request(op,req); + return sal_op_send_request_with_contact(op,req); } int sal_unsubscribe(SalOp *op){ belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ @@ -601,7 +601,7 @@ int sal_unsubscribe(SalOp *op){ } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); - return sal_op_send_request(op,req); + return sal_op_send_request_with_contact(op,req); } int sal_subscribe_accept(SalOp *op){ belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index a8ac7e874..ea1eb6c82 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -119,7 +119,7 @@ static int send_register_request_with_expires(SalOp* op, belle_sip_request_t* re 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); + return sal_op_send_request_with_contact(op,request); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 81f9865fa..202d851dc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2106,7 +2106,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ - ms_message("incoming call ringing for %i seconds",elapsed); + if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); call->log->status=LinphoneCallMissed; @@ -5191,7 +5191,7 @@ static void linphone_core_uninit(LinphoneCore *lc) 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 diff --git a/tester/call_tester.c b/tester/call_tester.c index a0e0923ee..d0a083037 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -237,6 +237,32 @@ static void call_paused_resumed() { linphone_core_manager_destroy(pauline); } +static void call_paused_resumed_from_callee() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(marie->lc); + + linphone_core_pause_call(marie->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + + linphone_core_resume_call(marie->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + static void call_srtp() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -299,6 +325,9 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "call_paused_resumed_from_callee", call_paused_resumed_from_callee)) { + return CU_get_error(); + } if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { return CU_get_error(); } From a4c096e7a4c3d8228c2e34837b6dc21dbcd69642 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 8 Feb 2013 18:11:13 +0100 Subject: [PATCH 037/909] implement vfu request --- coreapi/bellesip_sal/sal_impl.c | 6 ++-- coreapi/bellesip_sal/sal_op_call.c | 52 ++++++++++++++++++++++++--- tester/call_tester.c | 57 +++++++++++++++++++++++++++++- tester/liblinphone_tester.h | 2 ++ 4 files changed, 109 insertions(+), 8 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c7705138f..c2238216b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -161,9 +161,11 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; salmsg.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - salmsg.url=NULL; /*not implemented yet*/ + salmsg.url=NULL; /*FIXME not implemented yet*/ salmsg.message_id=message_id; - ((Sal*)sal)->callbacks.text_received((Sal*)sal,&salmsg); + op=sal_op_new((Sal*)sal); + ((Sal*)sal)->callbacks.text_received(op,&salmsg); + sal_op_release(op); belle_sip_object_unref(address); belle_sip_free(from); return; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 60272addd..984881592 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -117,17 +117,22 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t 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_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 code = belle_sip_response_get_status_code(response); char* reason; SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + if (!client_transaction) { + ms_warning("Discarding state less response [%i] on op [%p]",code,op); + return; + } reason=(char*)belle_sip_response_get_reason_phrase(response); if (reason_header){ reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); } + /*FIXME should be limited to early/NULL dialog*/ if (code >=400) { sal_compute_sal_errors_from_code(code,&error,&sr); op->base.root->callbacks.call_failure(op,error,sr,reason,code); @@ -177,7 +182,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t switch (op->state) { case SalOpStateEarly:/*invite case*/ case SalOpStateActive: /*re-invite case*/ - if (code >=200) { + if (code >=200 + && code<300 + && strcmp("INVITE",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction))))==0) { handle_sdp_from_response(op,response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack==NULL) { @@ -193,6 +200,8 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t /*if (op->state != SalOpStateActive)*/ op->base.root->callbacks.call_accepted(op); op->state=SalOpStateActive; + } else { + /*nop*/ } break; @@ -349,7 +358,18 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t process_sdp_for_invite(op,req); op->base.root->callbacks.call_updating(op); - } else { + } else if (strcmp("INFO",belle_sip_request_get_method(req))==0 + && 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); + + } + resp=belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + }else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); } @@ -599,8 +619,30 @@ int sal_call_terminate(SalOp *op){ bool_t sal_call_autoanswer_asked(SalOp *op){ return op->auto_answer_asked; } -void sal_call_send_vfu_request(SalOp *h){ - ms_fatal("sal_call_send_vfu_request not implemented yet"); +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_request(op->dialog,"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); + sal_op_send_request(op,info); + } 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){ diff --git a/tester/call_tester.c b/tester/call_tester.c index d0a083037..bc9a75b98 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -61,6 +61,16 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState } } +static void linphone_call_cb(LinphoneCall *call,void * user_data) { + char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + LinphoneCore* lc=(LinphoneCore*)user_data; + ms_message("call from [%s] to [%s] receive iFrame",from,to); + ms_free(to); + ms_free(from); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_IframeDecoded++; +} static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); @@ -262,6 +272,49 @@ static void call_paused_resumed_from_callee() { linphone_core_manager_destroy(pauline); } +static void call_with_video_added() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCall* call_obj; + LinphoneVideoPolicy pauline_policy; + pauline_policy.automatically_accept=TRUE; + pauline_policy.automatically_initiate=TRUE; + LinphoneCallParams* marie_params; + + CU_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_enable_video(marie->lc,TRUE,TRUE); + linphone_core_enable_video(pauline->lc,TRUE,FALSE); + linphone_core_set_video_policy(pauline->lc,&pauline_policy); + + call_obj = linphone_core_get_current_call(marie->lc); + marie_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); + /*add video*/ + linphone_call_params_enable_video(marie_params,TRUE); + linphone_core_update_call(marie->lc,call_obj,marie_params); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); + + linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,marie->lc); + /*send vfu*/ + linphone_call_send_vfu_request(call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_srtp() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); @@ -331,7 +384,9 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "call_with_video_added", call_with_video_added)) { + return CU_get_error(); + } return 0; } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 03ab11b61..9f1bc97f2 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -60,6 +60,8 @@ typedef struct _stats { int number_of_NewSubscriptionRequest; int number_of_NotifyReceived; + + int number_of_IframeDecoded; }stats; typedef struct _LinphoneCoreManager { LinphoneCoreVTable v_table; From ba1318d8cb5506a848f18838d58b5f224e1666b1 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 11 Feb 2013 18:16:40 +0100 Subject: [PATCH 038/909] add conferencing test --- tester/call_tester.c | 98 +++++++++++++++++++++++++++++++++---- tester/laure_rc | 38 ++++++++++++++ tester/liblinphone_tester.c | 17 +++++-- tester/liblinphone_tester.h | 2 +- tester/userdb.conf | 1 + 5 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 tester/laure_rc diff --git a/tester/call_tester.c b/tester/call_tester.c index bc9a75b98..3dd9cb0ca 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -75,6 +75,9 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); int retry=0; + stats initial_caller=caller_mgr->stat; + stats initial_callee=callee_mgr->stat; + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); @@ -82,19 +85,25 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m /*linphone_core_invite(caller_mgr->lc,"pauline");*/ - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc + ,caller_mgr->lc + ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived + ,initial_callee.number_of_LinphoneCallIncomingReceived+1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); - CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1); - while ((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging<1 - || caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia<1) && retry++ <20) { + + while (caller_mgr->stat.number_of_LinphoneCallOutgoingRinging!=(initial_caller.number_of_LinphoneCallOutgoingRinging + 1) + && caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia!=(initial_caller.number_of_LinphoneCallOutgoingEarlyMedia +1) + && retry++ <20) { linphone_core_iterate(caller_mgr->lc); linphone_core_iterate(callee_mgr->lc); ms_usleep(100000); } - CU_ASSERT_TRUE_FATAL(caller_mgr->stat.number_of_LinphoneCallOutgoingRinging|caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia); + CU_ASSERT_TRUE_FATAL((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) + |(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); linphone_core_get_default_proxy(caller_mgr->lc,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); @@ -104,12 +113,12 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); /*just to sleep*/ - return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,1) + return 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,1); + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1); } static void simple_call() { @@ -247,6 +256,17 @@ static void call_paused_resumed() { linphone_core_manager_destroy(pauline); } +static bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,LinphoneCoreManager* mgr_2,LinphoneCall* call_2) { + stats initial_call_stat_1=mgr_1->stat; + stats initial_call_stat_2=mgr_2->stat; + linphone_core_pause_call(mgr_1->lc,call_1); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPausing,initial_call_stat_1.number_of_LinphoneCallPausing+1)); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPaused,initial_call_stat_1.number_of_LinphoneCallPaused+1)); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_2->stat.number_of_LinphoneCallPausedByRemote,initial_call_stat_2.number_of_LinphoneCallPausedByRemote+1)); + CU_ASSERT_EQUAL(linphone_call_get_state(call_1),LinphoneCallPaused); + CU_ASSERT_EQUAL(linphone_call_get_state(call_2),LinphoneCallPausedByRemote); + return linphone_call_get_state(call_1) == LinphoneCallPaused && linphone_call_get_state(call_2)==LinphoneCallPausedByRemote; +} static void call_paused_resumed_from_callee() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -314,6 +334,63 @@ static void call_with_video_added() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void simple_conference() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + stats initial_marie_stat; + stats initial_pauline_stat; + stats initial_laure_stat; + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; + LinphoneCall* marie_call_laure; + + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + CU_ASSERT_TRUE(call(marie,laure)); + initial_marie_stat=marie->stat; + initial_pauline_stat=pauline->stat; + initial_laure_stat=laure->stat; + + marie_call_laure=linphone_core_get_current_call(marie->lc); + + linphone_core_add_to_conference(marie->lc,marie_call_laure); + CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); + + + + linphone_core_add_to_conference(marie->lc,marie_call_pauline); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + + CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); + CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + + linphone_core_terminate_conference(marie->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} static void call_srtp() { @@ -387,6 +464,9 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "call_with_video_added", call_with_video_added)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple_conference", simple_conference)) { + return CU_get_error(); + } return 0; } diff --git a/tester/laure_rc b/tester/laure_rc new file mode 100644 index 000000000..b4480494c --- /dev/null +++ b/tester/laure_rc @@ -0,0 +1,38 @@ +[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 \ No newline at end of file diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 8bfc5352b..a20d72581 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -113,10 +113,21 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + MSList* lcs=NULL; + lcs=ms_list_append(lcs,lc_1); + bool_t result; + lcs=ms_list_append(lcs,lc_2); + result=wait_for_list(lcs,counter,value,2000); + ms_list_free(lcs); + return result; +} +bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; - while (*counternext) { + linphone_core_iterate((LinphoneCore*)(iterator->data)); + } ms_usleep(100000); } if(*counter Date: Tue, 12 Feb 2013 18:09:36 +0100 Subject: [PATCH 039/909] fix linux compilation issue --- coreapi/bellesip_sal/sal_impl.c | 3 +-- coreapi/bellesip_sal/sal_sdp.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c2238216b..ee75f3f2a 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -38,9 +38,8 @@ void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { ortp_level=ORTP_MESSAGE; break; case BELLE_SIP_LOG_DEBUG: - ortp_level=ORTP_DEBUG; - break; default: + ortp_level=ORTP_DEBUG; break; } if (ortp_log_level_enabled(ortp_level)){ diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 06a93d2e6..074ed25d8 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -29,7 +29,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip MSList* pt_it; PayloadType* pt; char buffer[1024]; - char* dir; + char* dir=NULL; if (strchr(desc->addr,':')!=NULL){ inet6=1; From a177101b5542ebe634465d13fb6bba19d8e9d318 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Feb 2013 16:11:33 +0100 Subject: [PATCH 040/909] fix cseq not incremented in case of 401/407 response --- coreapi/bellesip_sal/sal_impl.c | 299 ++++++++++++-------------- coreapi/bellesip_sal/sal_impl.h | 6 +- coreapi/bellesip_sal/sal_op_call.c | 63 +++++- coreapi/bellesip_sal/sal_op_message.c | 99 ++++++++- coreapi/callbacks.c | 12 +- tester/call_tester.c | 65 ++++++ tester/liblinphone_tester.c | 7 +- tester/liblinphone_tester.h | 10 + tester/message_tester.c | 90 +++++++- 9 files changed, 466 insertions(+), 185 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ee75f3f2a..f1336a491 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -77,9 +77,9 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { } if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) { if (is_within_dialog) { - sal_op_resend_request(op,request); - } else { sal_op_send_request(op,request); + } else { + sal_op_resend_request(op,request); } }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); @@ -115,7 +115,7 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e op->callbacks.process_io_error(op,event); } } else { - ms_error("process_io_error not implemented yet for non transaction"); + ms_error("sal process_io_error not implemented yet for non transaction"); } } static void process_request_event(void *sal, const belle_sip_request_event_t *event) { @@ -126,17 +126,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_header_address_t* address; belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; - belle_sip_header_content_type_t* content_type; belle_sip_response_t* resp; - belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); - belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); - SalMessage salmsg; - char message_id[256]={0}; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); - char* from; - if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); } else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { @@ -148,34 +141,13 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op->dir=SalOpDirIncoming; sal_op_presence_fill_cbs(op); } else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) { - content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); - if (content_type - && strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0) { - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); - snprintf(message_id,sizeof(message_id)-1,"%s%i" - ,belle_sip_header_call_id_get_call_id(call_id) - ,belle_sip_header_cseq_get_seq_number(cseq)); - salmsg.from=from; - salmsg.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - salmsg.url=NULL; /*FIXME not implemented yet*/ - salmsg.message_id=message_id; - op=sal_op_new((Sal*)sal); - ((Sal*)sal)->callbacks.text_received(op,&salmsg); - sal_op_release(op); - belle_sip_object_unref(address); - belle_sip_free(from); - return; - } else { - ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) - ,belle_sip_header_content_type_get_subtype(content_type)); - return; - } + op=sal_op_new((Sal*)sal); + op->dir=SalOpDirIncoming; + sal_op_message_fill_cbs(op); + } 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,500); + resp=belle_sip_response_create_from_request(req,501); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; @@ -217,136 +189,139 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev 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); - if (!client_transaction) { - ms_error("Unexpected stateless response, trashing"); - return; - } - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); 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)); - belle_sip_header_contact_t* original_contact; - belle_sip_header_address_t* contact_address=NULL; - belle_sip_header_via_t* via_header; - belle_sip_uri_t* contact_uri; - unsigned int contact_port; - const char* received; - int rport; - bool_t contact_updated=FALSE; - char* new_contact; - belle_sip_request_t* old_request=NULL;; - belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); - - if (op->state == SalOpStateTerminated) { - belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + if (!client_transaction) { + ms_warning("Discarding state less response [%i]",response_code); return; - } - if (!op->base.remote_ua) { - sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); - } - - if (op->callbacks.process_response_event) { - /*Fix contact if needed*/ - via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); - received = belle_sip_header_via_get_received(via_header); - rport = belle_sip_header_via_get_rport(via_header); - if (!sal_op_get_contact(op)) { - /*check if contqct set in reauest*/ - - if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { - /*no contact set yet, try to see if sip tack has an updated one*/ - contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_object_unref(contact_address); - } else { - - /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ - contact_address=belle_sip_header_address_new(); - contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); - belle_sip_header_address_set_uri(contact_address,contact_uri); - - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - } - if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { - belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); - } - contact_updated=TRUE; - } - } - - if (received!=NULL || rport>0) { - if (sal_op_get_contact(op)){ - contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - } - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } - - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) - ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; - } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); - } - } - if (contact_updated) { - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); - sal_op_set_contact(op,new_contact); - belle_sip_free(new_contact); - } - if (contact_address)belle_sip_object_unref(contact_address); - } - /*update request/response - * maybe only the transaction should be kept*/ - old_request=op->request; - op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_object_ref(op->request); - if (old_request) belle_sip_object_unref(old_request); - - old_response=op->response; - op->response=response; /*kept for use at authorization time*/ - belle_sip_object_ref(op->response); - if (old_response) belle_sip_object_unref(old_response); - - /*handle authozation*/ - switch (response_code) { - case 200: { - sal_remove_pending_auth(op->base.root,op);/*just in case*/ - break; - } - case 401: - case 407:{ - if (op->state == SalOpStateTerminating) { - belle_sip_message("Op is in state terminating, nothing else to do"); - return; - } else { - sal_process_authentication(op,response); - return; - } - } - } - op->callbacks.process_response_event(op,event); - } else { - ms_error("Unhandled event response [%p]",event); + 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* original_contact; + belle_sip_header_address_t* contact_address=NULL; + belle_sip_header_via_t* via_header; + belle_sip_uri_t* contact_uri; + unsigned int contact_port; + const char* received; + int rport; + bool_t contact_updated=FALSE; + char* new_contact; + belle_sip_request_t* old_request=NULL;; + belle_sip_response_t* old_response=NULL;; + + + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); + } + + if (op->callbacks.process_response_event) { + /*Fix contact if needed*/ + via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); + received = belle_sip_header_via_get_received(via_header); + rport = belle_sip_header_via_get_rport(via_header); + if (!sal_op_get_contact(op)) { + /*check if contqct set in reauest*/ + + if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { + /*no contact set yet, try to see if sip tack has an updated one*/ + contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_object_unref(contact_address); + } else { + + /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ + contact_address=belle_sip_header_address_new(); + contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); + belle_sip_header_address_set_uri(contact_address,contact_uri); + + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + } + if (belle_sip_header_via_get_listening_port(via_header) + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + } + contact_updated=TRUE; + } + } + + if (received!=NULL || rport>0) { + if (sal_op_get_contact(op)){ + contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); + } + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } + + /*try to fix transport if needed (very unlikely)*/ + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + if (!belle_sip_uri_get_transport_param(contact_uri) + ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); + } + } + if (contact_updated) { + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); + sal_op_set_contact(op,new_contact); + belle_sip_free(new_contact); + } + if (contact_address)belle_sip_object_unref(contact_address); + } + /*update request/response + * maybe only the transaction should be kept*/ + old_request=op->request; + op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_object_ref(op->request); + if (old_request) belle_sip_object_unref(old_request); + + old_response=op->response; + op->response=response; /*kept for use at authorization time*/ + belle_sip_object_ref(op->response); + if (old_response) belle_sip_object_unref(old_response); + + /*handle authozation*/ + switch (response_code) { + case 200: { + sal_remove_pending_auth(op->base.root,op);/*just in case*/ + break; + } + case 401: + case 407:{ + if (op->state == SalOpStateTerminating) { + belle_sip_message("Op is in state terminating, nothing else to do"); + return; + } else { + sal_process_authentication(op,response); + return; + } + } + } + + op->callbacks.process_response_event(op,event); + + } else { + ms_error("Unhandled event response [%p]",event); + } } } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 46692786b..2f7262c6f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -60,8 +60,8 @@ struct SalOp{ belle_sip_refresher_t* registration_refresher; bool_t sdp_offering; belle_sip_dialog_t* dialog; - belle_sip_header_address_t *replaces; - belle_sip_header_address_t *referred_by; + belle_sip_header_replaces_t *replaces; + belle_sip_header_t *referred_by; bool_t auto_answer_asked; SalMediaDescription *result; belle_sdp_session_description_t *sdp_answer; @@ -90,5 +90,7 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; /*presence*/ void sal_op_presence_fill_cbs(SalOp*op); +/*messaging*/ +void sal_op_message_fill_cbs(SalOp*op); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 984881592..2c6401d81 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -266,7 +266,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->pending_server_trans=server_transaction; belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_header_t* replace_header; belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; belle_sip_header_t* call_info; @@ -279,8 +278,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { - if (!op->replaces && (replace_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"replaces"))) { - op->replaces=belle_sip_header_address_parse(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(replace_header))); + 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"); @@ -550,9 +548,15 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ } return h->result; } -int sal_call_refer(SalOp *h, const char *refer_to){ - ms_fatal("sal_call_refer not implemented yet"); - return -1; +int sal_call_refer(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + 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) { + ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); + return sal_op_send_request(op,req); } int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ ms_fatal("sal_call_refer_with_replaces not implemented yet"); @@ -660,4 +664,49 @@ void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ void sal_use_dates(Sal *ctx, bool_t enabled){ ms_warning("sal_use_dates not implemented yet"); } - +/* +static void process_refer(SalOp *op, belle_sip_request_event_t *event){ + 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_uri_t* refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + ms_message("Receiving REFER request on op [%p]",op); + if (refer_to){ + char *tmp; + if (refer_to_uri){ + 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 (belle_sip_uri_get_header(refer_to_uri,"Replaces")) + 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"); + } +} +*/ diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 2fcbeb0bb..46492f63a 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -18,21 +18,103 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" -static void message_response_event(void *op_base, const belle_sip_response_event_t *event){ - /*nop for futur use*/ +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; + process_error(op); +} +static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalOp* op=(SalOp*)user_ctx; + 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; + 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_plain_text(belle_sip_header_content_type_t* content_type) { + return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; +} +static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { + return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; +} + +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; + belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); + belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); + SalMessage salmsg; + char message_id[256]={0}; + int response_code=501; + char* from; + bool_t plain_text=FALSE; + bool_t external_body=FALSE; + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + if (content_type && ((plain_text=is_plain_text(content_type)) + || (external_body=is_external_body(content_type)))) { + + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + snprintf(message_id,sizeof(message_id)-1,"%s%i" + ,belle_sip_header_call_id_get_call_id(call_id) + ,belle_sip_header_cseq_get_seq_number(cseq)); + salmsg.from=from; + salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.url=external_body?belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"):NULL; + salmsg.message_id=message_id; + op->base.root->callbacks.text_received(op,&salmsg); + belle_sip_object_unref(address); + belle_sip_free(from); + response_code=200; + } else { + ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) + ,belle_sip_header_content_type_get_subtype(content_type)); + response_code=501; /*not implemented sound appropriate*/ + } + resp = belle_sip_response_create_from_request(req,response_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); +} int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ belle_sip_request_t* req; char content_type_raw[256]; - size_t content_length = strlen(msg); - if (!op->callbacks.process_response_event) - op->callbacks.process_response_event=message_response_event; + size_t content_length = msg?strlen(msg):0; + 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"); 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))); @@ -44,3 +126,10 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { return sal_message_send(op,from,to,"text/plain",msg); } + +void sal_op_message_fill_cbs(SalOp*op) { + op->callbacks.process_io_error=process_io_error; + op->callbacks.process_response_event=process_response_event; + op->callbacks.process_timeout=process_timeout; + op->callbacks.process_request_event=process_request_event; +} diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 31e457486..23f586088 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -965,11 +965,13 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ ,chatStatusSal2Linphone(status) ,chat_msg->cb_ud); } - 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); + if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/ + linphone_chat_message_destroy(chat_msg); + + if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) { + /*op was only create for messaging purpose, destroying*/ + sal_op_release(op); + } } } diff --git a/tester/call_tester.c b/tester/call_tester.c index 3dd9cb0ca..3ca6ebe71 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -432,6 +432,67 @@ static void call_early_media() { linphone_core_manager_destroy(pauline); } +static void simple_call_transfer() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); +/* stats initial_marie_stat; + stats initial_pauline_stat; + stats initial_laure_stat;*/ + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + 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); + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; +/* LinphoneCall* marie_call_laure;*/ + + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + + + linphone_core_transfer_call(pauline->lc,pauline_called_by_marie,laure_identity); + +/* + 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); + + + linphone_core_transfer_call() + CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); + + + + linphone_core_add_to_conference(marie->lc,marie_call_pauline); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + + CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); + CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + + linphone_core_terminate_conference(marie->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + +*/ + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + int call_test_suite () { CU_pSuite pSuite = CU_add_suite("Call", init, uninit); if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { @@ -467,6 +528,10 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "simple_conference", simple_conference)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple_call_transfer", simple_call_transfer)) { + return CU_get_error(); + } + return 0; } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a20d72581..7a1c8f133 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -114,9 +114,11 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { MSList* lcs=NULL; - lcs=ms_list_append(lcs,lc_1); + if (lc_1) + lcs=ms_list_append(lcs,lc_1); bool_t result; - lcs=ms_list_append(lcs,lc_2); + if (lc_2) + lcs=ms_list_append(lcs,lc_2); result=wait_for_list(lcs,counter,value,2000); ms_list_free(lcs); return result; @@ -153,6 +155,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) { mgr->v_table.registration_state_changed=registration_state_changed; mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; + mgr->v_table.message_received=message_received; mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index cc662c2f0..85cc719dd 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -57,6 +57,13 @@ typedef struct _stats { int number_of_LinphoneCallReleased; int number_of_LinphoneMessageReceived; + int number_of_LinphoneMessageReceivedLegacy; + int number_of_LinphoneMessageExtBodyReceived; + int number_of_LinphoneMessageInProgress; + int number_of_LinphoneMessageDelivered; + int number_of_LinphoneMessageNotDelivered; + + int number_of_NewSubscriptionRequest; int number_of_NotifyReceived; @@ -80,9 +87,12 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg); 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 new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); + LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; LinphoneAddress * create_linphone_address(const char * domain); LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count); diff --git a/tester/message_tester.c b/tester/message_tester.c index a48e0dbe1..424a12b32 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -22,13 +22,40 @@ #include "liblinphone_tester.h" void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { - char* from=linphone_address_as_string(from_address); - ms_message("Message from [%s] is [%s]",from,message); + stats* counters = (stats*)linphone_core_get_user_data(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)); + ms_message("Message from [%s] is [%s] , external URL [%s]",from + ,linphone_chat_message_get_text(message) + ,linphone_chat_message_get_external_body_url(message)); ms_free(from); stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_LinphoneMessageReceived++; + if (linphone_chat_message_get_external_body_url(message)) + counters->number_of_LinphoneMessageExtBodyReceived++; } +void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + LinphoneCore* lc=(LinphoneCore*)ud; + stats* counters = (stats*)linphone_core_get_user_data(lc); + ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); + switch (state) { + case LinphoneChatMessageStateDelivered: + counters->number_of_LinphoneMessageDelivered++; + break; + case LinphoneChatMessageStateNotDelivered: + counters->number_of_LinphoneMessageNotDelivered++; + break; + case LinphoneChatMessageStateInProgress: + counters->number_of_LinphoneMessageInProgress++; + break; + default: + ms_error("Unexpected state [%s] for message [%p]",linphone_chat_message_state_to_string(state),msg); + } + +} static void text_message() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); @@ -37,7 +64,56 @@ static void text_message() { LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void text_message_with_ack() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void text_message_with_external_body() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_message_set_external_body_url(message,"http://www.linphone.org"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_send_error() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + /*simultate a network error*/ + sal_set_send_error(marie->lc->sal, -1); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,marie->lc); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + /*CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1);*/ + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); + + sal_set_send_error(marie->lc->sal, 0); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -47,5 +123,15 @@ int message_test_suite () { if (NULL == CU_add_test(pSuite, "text_message", text_message)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "text_message_with_ack", text_message_with_ack)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "text_message_with_send_error", text_message_with_send_error)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "text_message_with_external_body", text_message_with_external_body)) { + return CU_get_error(); + } + return 0; } From 7545582ab8286d1a533a23e8dbc2dca6f932c8c9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Feb 2013 16:28:20 +0100 Subject: [PATCH 041/909] only check upnp state if upnp is configured --- coreapi/proxy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 4f9bbb6ba..d57f32cae 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1087,7 +1087,9 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ linphone_proxy_config_activate_sip_setup(cfg); } if ((!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) && - (!lc->sip_conf.register_only_when_upnp_is_ok || linphone_core_get_upnp_state(lc) == LinphoneUpnpStateOk)) + (linphone_core_get_firewall_policy(lc)!=LinphonePolicyUseUpnp + || !lc->sip_conf.register_only_when_upnp_is_ok + || linphone_core_get_upnp_state(lc) == LinphoneUpnpStateOk)) linphone_proxy_config_register(cfg); if (cfg->publish && cfg->publish_op==NULL){ linphone_proxy_config_send_publish(cfg,lc->presence_mode); From 607af68f427102855763c2ed2f4fb2a52294927d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Feb 2013 16:53:54 +0100 Subject: [PATCH 042/909] add upnp status to configure.ac --- configure.ac | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index db0273616..311af74f4 100644 --- a/configure.ac +++ b/configure.ac @@ -826,12 +826,15 @@ printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp if test "$enable_tunnel" = "true" ; then - printf "* Tunnel support\t\ttrue\n" + printf "* Tunnel support\t\t\ttrue\n" fi if test $USE_BELLESIP_TRUE !='#' ; then - printf "* bellesip stack\t\ttrue\n" + printf "* bellesip stack\t\t\ttrue\n" else printf "* eXosip stack\t\ttrue\n" fi +if test "$build_upnp" = "true" ; then + printf "* upnp support\t\t\ttrue\n" +fi echo "Now type 'make' to compile, and then 'make install' as root to install it." From f6f2381a09736b507869840f0084c08a515e1d06 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 15 Feb 2013 11:30:22 +0100 Subject: [PATCH 043/909] start call transfert, fix upnp crash, imp[lement incoming OPTION --- coreapi/bellesip_sal/sal_impl.c | 7 +- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call.c | 188 ++++++++++++++++++----------- coreapi/bellesip_sal/sal_op_impl.c | 3 + coreapi/linphonecore.c | 15 ++- tester/call_tester.c | 15 ++- 6 files changed, 149 insertions(+), 81 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f1336a491..0cd5aa3a6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -145,11 +145,14 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op->dir=SalOpDirIncoming; sal_op_message_fill_cbs(op); - } else { + } else if (strcmp("OPTION",belle_sip_request_get_method(req))==0) { + resp=belle_sip_response_create_from_request(req,200); + belle_sip_provider_send_response(((Sal*)sal)->prov,resp); + return; + }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,501); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); - return; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 2f7262c6f..1e3962221 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -61,7 +61,7 @@ struct SalOp{ bool_t sdp_offering; belle_sip_dialog_t* dialog; belle_sip_header_replaces_t *replaces; - belle_sip_header_t *referred_by; + belle_sip_header_referred_by_t *referred_by; bool_t auto_answer_asked; SalMediaDescription *result; belle_sdp_session_description_t *sdp_answer; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2c6401d81..f0acc8112 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" +static void process_refer(SalOp *op, const belle_sip_request_event_t *event); + static void sdp_process(SalOp *h){ ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); if (h->result){ @@ -367,7 +369,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } resp=belle_sip_response_create_from_request(req,200); belle_sip_server_transaction_send_response(server_transaction,resp); - }else{ + }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { + process_refer(op,event); + } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); } @@ -381,6 +385,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } + /*Call API*/ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ if (desc) @@ -548,36 +553,6 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ } return h->result; } -int sal_call_refer(SalOp *op, const char *refer_to){ - belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); - 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) { - ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); - return sal_op_send_request(op,req); -} -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; -} -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){ - ms_fatal("sal_call_set_referer not implemented yet"); - return -1; -} -/* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - ms_fatal("sal_call_get_replaces not implemented yet"); - } - return NULL; -} int sal_call_send_dtmf(SalOp *h, char dtmf){ ms_fatal("sal_call_send_dtmf not implemented yet"); return -1; @@ -653,10 +628,91 @@ int sal_call_is_offerer(const SalOp *h){ return h->sdp_offering; } -int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){ - ms_fatal("sal_call_notify_refer_state not implemented yet"); + +/*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(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + 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) { + ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); + return sal_op_send_request(op,req); +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); return -1; } +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 *h){ + if (h!=NULL && h->replaces!=NULL){ + ms_fatal("sal_call_get_replaces not implemented yet"); + } + return NULL; +} + +static int send_notify_for_refer(SalOp* op, const char *sipfrag){ + belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + 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_set_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); + + return sal_op_send_request(op,notify); +} + +int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ + belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; + switch(state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: + send_notify_for_refer(op,"SIP/2.0 100 Trying\r\n"); + break; + case BELLE_SIP_DIALOG_CONFIRMED: + if(send_notify_for_refer(op,"SIP/2.0 200 Ok\r\n")) { + /* we need previous notify transaction to complete, so buffer the request for later*/ + /*op->sipfrag_pending="SIP/2.0 200 Ok\r\n";*/ + ms_error("Cannot notify 200 ok frag to [%p] for new op [%p]",op,newcall); + } + break; + default: + break; + } + return 0; +} + void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ ms_warning("sal_expire_old_registration_contacts not implemented "); } @@ -664,49 +720,37 @@ void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ void sal_use_dates(Sal *ctx, bool_t enabled){ ms_warning("sal_use_dates not implemented yet"); } -/* -static void process_refer(SalOp *op, belle_sip_request_event_t *event){ + + + +static void process_refer(SalOp *op, const belle_sip_request_event_t *event){ 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_uri_t* refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + 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_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + 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){ - char *tmp; - if (refer_to_uri){ - 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 (belle_sip_uri_get_header(refer_to_uri,"Replaces")) - 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); + 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"))); } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,202,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,202,ans); - eXosip_unlock(); - } - else - { + if (referred_by){ + sal_op_set_referred_by(op,referred_by); + } + refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); + resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); } + } -*/ + diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 6d6b7a955..7f052e358 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -34,6 +34,9 @@ void sal_op_release(SalOp *op){ belle_sip_refresher_stop(op->registration_refresher); belle_sip_object_unref(op->registration_refresher); } + if(op->replaces) belle_sip_object_unref(op->replaces); + if(op->referred_by) belle_sip_object_unref(op->referred_by); + if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); __sal_op_free(op); return ; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 36f3f6b82..f0d6e6da1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5232,10 +5232,7 @@ static void linphone_core_uninit(LinphoneCore *lc) #endif } -#ifdef BUILD_UPNP - linphone_upnp_context_destroy(lc->upnp); - lc->upnp = NULL; -#endif //BUILD_UPNP + if (lc->friends) /* FIXME we should wait until subscription to complete*/ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); @@ -5257,10 +5254,18 @@ static void linphone_core_uninit(LinphoneCore *lc) codecs_config_uninit(lc); ui_config_uninit(lc); sip_config_uninit(lc); + + + sip_setup_unregister_all(); + +#ifdef BUILD_UPNP + if (lc->upnp) linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; +#endif //BUILD_UPNP + if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config); lp_config_destroy(lc->config); lc->config = NULL; /* Mark the config as NULL to block further calls */ - sip_setup_unregister_all(); ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); diff --git a/tester/call_tester.c b/tester/call_tester.c index 3ca6ebe71..b44b17ad6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -385,7 +385,6 @@ static void simple_conference() { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); - linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); @@ -439,6 +438,7 @@ static void simple_call_transfer() { stats initial_laure_stat;*/ LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + char* laure_identity=linphone_address_as_string(laure->identity); MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); @@ -452,8 +452,21 @@ static void simple_call_transfer() { marie_call_pauline=linphone_core_get_current_call(marie->lc); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + linphone_core_transfer_call(pauline->lc,pauline_called_by_marie,laure_identity); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallRefered,1,2000)); + /*marie pausing pauline*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPausing,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausedByRemote,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); + /*marie calling laure*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,2,2000)); /* initial_marie_stat=marie->stat; From 62cc1e417b4db4b0303ebd5f882b72edeca0b20f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 15 Feb 2013 12:09:59 +0100 Subject: [PATCH 044/909] fix OPTIONS --- coreapi/bellesip_sal/sal_impl.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 0cd5aa3a6..ee82867c0 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -145,7 +145,7 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op->dir=SalOpDirIncoming; sal_op_message_fill_cbs(op); - } else if (strcmp("OPTION",belle_sip_request_get_method(req))==0) { + } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; diff --git a/mediastreamer2 b/mediastreamer2 index eeaab2239..a964bf24c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit eeaab2239d6545f18d5219b62adda8d1dda3b104 +Subproject commit a964bf24c47febe55276a8b5ef3e323503c08668 From 615fb7ad5d98d227751fb9c9d14e51c72dcbda68 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 15 Feb 2013 18:47:46 +0100 Subject: [PATCH 045/909] continue call transfer impl --- coreapi/Makefile.am | 3 +- coreapi/bellesip_sal/sal_impl.h | 4 +- coreapi/bellesip_sal/sal_op_call.c | 122 +------------ coreapi/bellesip_sal/sal_op_call_transfer.c | 181 ++++++++++++++++++++ coreapi/linphonecall.c | 3 + tester/call_tester.c | 17 +- tester/liblinphone_tester.c | 2 + tester/liblinphone_tester.h | 7 +- 8 files changed, 214 insertions(+), 125 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_call_transfer.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 40a7f99d9..70a7f82b5 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -58,7 +58,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_sdp.c \ bellesip_sal/sal_op_message.c \ - bellesip_sal/sal_op_presence.c + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_call_transfer.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1e3962221..424fc6961 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -92,5 +92,7 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ void sal_op_message_fill_cbs(SalOp*op); - +/*call transfert*/ +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f0acc8112..14ea90b56 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" -static void process_refer(SalOp *op, const belle_sip_request_event_t *event); static void sdp_process(SalOp *h){ ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); @@ -370,7 +369,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t resp=belle_sip_response_create_from_request(req,200); belle_sip_server_transaction_send_response(server_transaction,resp); }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { - process_refer(op,event); + sal_op_process_refer(op,event); + } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + sal_op_call_process_notify(op,event); } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); @@ -628,91 +629,6 @@ int sal_call_is_offerer(const SalOp *h){ return h->sdp_offering; } - -/*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(SalOp *op, const char *refer_to){ - belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); - 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) { - ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); - return sal_op_send_request(op,req); -} -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; -} -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 *h){ - if (h!=NULL && h->replaces!=NULL){ - ms_fatal("sal_call_get_replaces not implemented yet"); - } - return NULL; -} - -static int send_notify_for_refer(SalOp* op, const char *sipfrag){ - belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); - 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_set_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); - - return sal_op_send_request(op,notify); -} - -int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ - belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; - switch(state) { - case BELLE_SIP_DIALOG_NULL: - case BELLE_SIP_DIALOG_EARLY: - send_notify_for_refer(op,"SIP/2.0 100 Trying\r\n"); - break; - case BELLE_SIP_DIALOG_CONFIRMED: - if(send_notify_for_refer(op,"SIP/2.0 200 Ok\r\n")) { - /* we need previous notify transaction to complete, so buffer the request for later*/ - /*op->sipfrag_pending="SIP/2.0 200 Ok\r\n";*/ - ms_error("Cannot notify 200 ok frag to [%p] for new op [%p]",op,newcall); - } - break; - default: - break; - } - return 0; -} - void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ ms_warning("sal_expire_old_registration_contacts not implemented "); } @@ -722,35 +638,3 @@ void sal_use_dates(Sal *ctx, bool_t enabled){ } - -static void process_refer(SalOp *op, const belle_sip_request_event_t *event){ - 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_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); - 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"))); - } - if (referred_by){ - sal_op_set_referred_by(op,referred_by); - } - refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); - resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); - belle_sip_server_transaction_send_response(server_transaction,resp); - } - -} - 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..be1b6bc3d --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -0,0 +1,181 @@ +/* +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(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + 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) { + ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); + return sal_op_send_request(op,req); +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); + return -1; +} +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 *h){ + if (h!=NULL && h->replaces!=NULL){ + ms_fatal("sal_call_get_replaces not implemented yet"); + } + return NULL; +} + +static int send_notify_for_refer(SalOp* op, const char *sipfrag){ + belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + 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_set_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); + + return sal_op_send_request(op,notify); +} + +int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ + belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; + switch(state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: + send_notify_for_refer(op,"SIP/2.0 100 Trying\r\n"); + break; + case BELLE_SIP_DIALOG_CONFIRMED: + if(send_notify_for_refer(op,"SIP/2.0 200 Ok\r\n")) { + /* we need previous notify transaction to complete, so buffer the request for later*/ + /*op->sipfrag_pending="SIP/2.0 200 Ok\r\n";*/ + ms_error("Cannot notify 200 ok frag to [%p] for new op [%p]",op,newcall); + } + break; + default: + break; + } + return 0; +} + + +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ + 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_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + 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"))); + } + if (referred_by){ + sal_op_set_referred_by(op,referred_by); + } + refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); + resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event){ + + belle_sip_server_transaction_t* server_transaction = belle_sip_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); + 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 + && strcasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"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; + if (code==100){ + status=SalReferTrying; + }else if (code==200){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 31b945acb..1ec0bd810 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2335,6 +2335,9 @@ 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(call->state)); call->transfer_state = state; if (lc->vtable.transfer_state_changed) lc->vtable.transfer_state_changed(lc, call, state); diff --git a/tester/call_tester.c b/tester/call_tester.c index b44b17ad6..455be9bdd 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -60,7 +60,21 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState CU_FAIL("unexpected event");break; } } +void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { + char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); + 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); + + stats* counters = (stats*)linphone_core_get_user_data(lc); + switch (cstate) { + case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; + default: + CU_FAIL("unexpected event");break; + } +} static void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); @@ -466,7 +480,8 @@ static void simple_call_transfer() { /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + /* initial_marie_stat=marie->stat; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 7a1c8f133..ebbafc7d1 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -158,6 +158,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) { mgr->v_table.message_received=message_received; mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; + mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); @@ -198,6 +199,7 @@ CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); } int main (int argc, char *argv[]) { int i; + char *test_name=NULL; char *suite_name=NULL; for(i=1;i Date: Mon, 18 Feb 2013 15:57:19 +0100 Subject: [PATCH 046/909] continue transfer implemenation --- coreapi/bellesip_sal/sal_op_call_transfer.c | 36 ++++-- coreapi/linphonecall.c | 2 +- tester/call_tester.c | 115 ++++++++++++++------ tester/liblinphone_tester.h | 7 +- 4 files changed, 115 insertions(+), 45 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index be1b6bc3d..115b07698 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -37,19 +37,41 @@ static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* ref belle_sip_object_ref(op->referred_by); } -int sal_call_refer(SalOp *op, const char *refer_to){ - belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + +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) { - ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + 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_header)); + 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_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; + +int sal_call_refer(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* 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,NULL); +} + +int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){ + belle_sip_dialog_state_t other_call_dialod_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL; + belle_sip_header_refer_to_t* refer_to; + belle_sip_header_referred_by_t* referred_by; + + /*first, build refer to*/ + if (other_call_dialod_state!=BELLE_SIP_DIALOG_CONFIRMED) { + ms_error(" wrong dialog state [%s] for op [%p], sould be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(other_call_dialod_state) + ,other_call_op); + return -1; + } else { + refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog)); + referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog)); + } + 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"); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1ec0bd810..9a0687367 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2337,7 +2337,7 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat 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(call->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); diff --git a/tester/call_tester.c b/tester/call_tester.c index 455be9bdd..42148cbf6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -69,8 +69,13 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, ms_free(from); stats* counters = (stats*)linphone_core_get_user_data(lc); - switch (cstate) { + switch (new_call_state) { case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; + case LinphoneCallOutgoingProgress :counters->number_of_LinphoneTransfertCallOutgoingProgress++;break; + case LinphoneCallOutgoingRinging :counters->number_of_LinphoneTransfertCallOutgoingRinging++;break; + case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneTransfertCallOutgoingEarlyMedia++;break; + case LinphoneCallConnected :counters->number_of_LinphoneTransfertCallConnected++;break; + case LinphoneCallStreamsRunning :counters->number_of_LinphoneTransfertCallStreamsRunning++;break; default: CU_FAIL("unexpected event");break; } @@ -447,9 +452,6 @@ static void call_early_media() { static void simple_call_transfer() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); -/* stats initial_marie_stat; - stats initial_pauline_stat; - stats initial_laure_stat;*/ LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); @@ -460,7 +462,7 @@ static void simple_call_transfer() { LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; -/* LinphoneCall* marie_call_laure;*/ + CU_ASSERT_TRUE(call(marie,pauline)); marie_call_pauline=linphone_core_get_current_call(marie->lc); @@ -479,42 +481,81 @@ static void simple_call_transfer() { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransfertCallOutgoingProgress,1,2000)); + linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransfertCallConnected,1,2000)); - -/* - 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); - - - linphone_core_transfer_call() - CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); - - - - linphone_core_add_to_conference(marie->lc,marie_call_pauline); - - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); - - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); - - CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); - CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) - - linphone_core_terminate_conference(marie->lc); - + /*terminate marie to pauline call*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + +static void call_transfer_existing_call_outgoing_call() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; + LinphoneCall* marie_call_laure; + LinphoneCall* laure_called_by_marie; + + /*marie call pauline*/ + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + /*marie pause pauline*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + /*marie call laure*/ + CU_ASSERT_TRUE(call(marie,laure)); + marie_call_laure=linphone_core_get_current_call(marie->lc); + laure_called_by_marie=linphone_core_get_current_call(laure->lc); + /*marie pause pauline*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_laure,laure,laure_called_by_marie)); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + + + linphone_core_transfer_call_to_another(marie->lc,marie_call_pauline,marie_call_laure); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*pauline calling laure*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransfertCallOutgoingProgress,1,2000)); + linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransfertCallConnected,1,2000)); + + /*terminate marie to pauline/laure call*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); - -*/ linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); @@ -559,7 +600,9 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "simple_call_transfer", simple_call_transfer)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "call_transfer_existing_call_outgoing_call", call_transfer_existing_call_outgoing_call)) { + return CU_get_error(); + } return 0; } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 55428cb05..46263bf46 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -57,6 +57,11 @@ typedef struct _stats { int number_of_LinphoneCallReleased; int number_of_LinphoneTransferCallOutgoingInit; + int number_of_LinphoneTransfertCallOutgoingProgress; + int number_of_LinphoneTransfertCallOutgoingRinging; + int number_of_LinphoneTransfertCallOutgoingEarlyMedia; + int number_of_LinphoneTransfertCallConnected; + int number_of_LinphoneTransfertCallStreamsRunning; int number_of_LinphoneMessageReceived; int number_of_LinphoneMessageReceivedLegacy; @@ -91,7 +96,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, 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); -Qvoid new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; From 3fd27c09c84a852927437b195edfa60ee68c85ae Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 18 Feb 2013 16:10:42 +0100 Subject: [PATCH 047/909] fix compilation issue --- coreapi/bellesip_sal/sal_op_call_transfer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 115b07698..d8823afa8 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -180,7 +180,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even if (sipfrag){ int code=belle_sip_response_get_status_code(sipfrag); - SalReferStatus status; + SalReferStatus status=SalReferFailed; if (code==100){ status=SalReferTrying; }else if (code==200){ From 85c3a634802a7613b06c47b2ab1ecdad3e74afcf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 18 Feb 2013 16:20:48 +0100 Subject: [PATCH 048/909] fix wrong merge --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index a964bf24c..73a772ac4 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a964bf24c47febe55276a8b5ef3e323503c08668 +Subproject commit 73a772ac4754734c57ecbc1149cbe665acd2f376 From 5737db398608c1ded65396869573b86d132e9a0d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 19 Feb 2013 15:55:09 +0100 Subject: [PATCH 049/909] implement attended transfert --- coreapi/bellesip_sal/sal_op_call.c | 4 ++-- coreapi/bellesip_sal/sal_op_call_transfer.c | 19 +++++++++++++------ tester/call_tester.c | 21 ++++++++++++++++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 14ea90b56..49a12cd00 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -198,8 +198,8 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); - /*if (op->state != SalOpStateActive)*/ - op->base.root->callbacks.call_accepted(op); + op->base.root->callbacks.call_accepted(op); /*INVITE*/ + op->state=SalOpStateActive; } else { /*nop*/ diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 115b07698..b52802062 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -58,19 +58,26 @@ int sal_call_refer(SalOp *op, const char *refer_to){ } int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){ - belle_sip_dialog_state_t other_call_dialod_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL; + 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_refer_to_t* refer_to; belle_sip_header_referred_by_t* referred_by; /*first, build refer to*/ - if (other_call_dialod_state!=BELLE_SIP_DIALOG_CONFIRMED) { - ms_error(" wrong dialog state [%s] for op [%p], sould be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(other_call_dialod_state) + 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; - } else { - refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog)); - referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog)); } + 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)); + referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog)); return sal_call_refer_to(op,refer_to,referred_by); } int sal_call_accept_refer(SalOp *h){ diff --git a/tester/call_tester.c b/tester/call_tester.c index 42148cbf6..c68ec96ab 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -259,8 +259,9 @@ static void call_paused_resumed() { call_obj = linphone_core_get_current_call(pauline->lc); linphone_core_pause_call(pauline->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); linphone_core_resume_call(pauline->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -295,8 +296,9 @@ static void call_paused_resumed_from_callee() { call_obj = linphone_core_get_current_call(marie->lc); linphone_core_pause_call(marie->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); linphone_core_resume_call(marie->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -508,6 +510,7 @@ static void call_transfer_existing_call_outgoing_call() { LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); MSList* lcs=ms_list_append(NULL,marie->lc); + const MSList* calls; lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,laure->lc); @@ -538,13 +541,25 @@ static void call_transfer_existing_call_outgoing_call() { linphone_core_transfer_call_to_another(marie->lc,marie_call_pauline,marie_call_laure); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + /*pauline pausing marie*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausing,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPaused,1,2000)); /*pauline calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransfertCallOutgoingProgress,1,2000)); - linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + + /*laure accept call*/ + for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { + LinphoneCall* call = (LinphoneCall*)calls->data; + if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) { + CU_ASSERT_EQUAL(linphone_call_get_replaced_call(call),laure_called_by_marie); + linphone_core_accept_call(laure->lc,call); + break; + } + } CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); From 5b14c78bbd4a22494ec54531129e5ab30b4d1667 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 20 Feb 2013 10:34:12 +0100 Subject: [PATCH 050/909] Add sal_op_call_transfer.c to android build --- build/android/common.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/build/android/common.mk b/build/android/common.mk index cd1dfdf01..342c9358a 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -38,6 +38,7 @@ LOCAL_SRC_FILES := \ bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_call_transfer.c \ bellesip_sal/sal_op_impl.c \ bellesip_sal/sal_op_message.c \ bellesip_sal/sal_op_presence.c \ From f22fe042e66cd14e6ca558a27b2c85951ef958dd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 20 Feb 2013 11:44:23 +0100 Subject: [PATCH 051/909] make sure only INVITE message invoke call_received in dialog state NULL --- coreapi/bellesip_sal/sal_op_call.c | 46 ++++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 49a12cd00..c75eb0e18 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -279,24 +279,26 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { - if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { - belle_sip_object_ref(op->replaces); - } else if(op->replaces) { - ms_warning("replace header already set"); - } - - process_sdp_for_invite(op,req); - - if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { - if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { - op->auto_answer_asked=TRUE; - ms_message("The caller asked to automatically answer the call(Emergency?)\n"); + if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { + if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { + belle_sip_object_ref(op->replaces); + } else if(op->replaces) { + ms_warning("replace header already set"); } - } - op->base.root->callbacks.call_received(op); + process_sdp_for_invite(op,req); - break; + if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { + if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { + op->auto_answer_asked=TRUE; + ms_message("The caller asked to automatically answer the call(Emergency?)\n"); + } + } + + op->base.root->callbacks.call_received(op); + + break; + } /* else same behavior as for EARLY state*/ } case BELLE_SIP_DIALOG_EARLY: { //hmm probably a cancel @@ -412,17 +414,23 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { return; } int sal_call(SalOp *op, const char *from, const char *to){ - belle_sip_request_t* req; + belle_sip_request_t* invite; op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); - req=sal_op_build_request(op,"INVITE"); + invite=sal_op_build_request(op,"INVITE"); - sal_op_fill_invite(op,req); + sal_op_fill_invite(op,invite); sal_op_call_fill_cbs(op); - sal_op_send_request_with_contact(op,req); + 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)); + } + + sal_op_send_request_with_contact(op,invite); return 0; } From 7da04a1a9e4c9b53443368e7c34c05a00b69717f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 20 Feb 2013 17:53:51 +0100 Subject: [PATCH 052/909] fix upnp and better contact management --- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call.c | 6 +++--- coreapi/bellesip_sal/sal_op_impl.c | 19 +++++++++++++---- coreapi/bellesip_sal/sal_op_presence.c | 4 ++-- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/proxy.c | 24 +++++++++++++--------- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 424fc6961..f6f395fb5 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -81,7 +81,7 @@ void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog); 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_contact(SalOp* op, belle_sip_request_t* request) ; + void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index c75eb0e18..611ddf62f 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -430,9 +430,9 @@ int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by)); } - sal_op_send_request_with_contact(op,invite); + return sal_op_send_request(op,invite); + - return 0; } void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_io_error=call_process_io_error; @@ -549,7 +549,7 @@ int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); sal_op_fill_invite(op, reinvite); - return sal_op_send_request_with_contact(op,reinvite); + return sal_op_send_request(op,reinvite); } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ return h->base.remote_media;; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 7f052e358..8f3254460 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -151,6 +151,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } if (add_contact) { contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) @@ -163,12 +164,22 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { - return _sal_op_send_request_with_contact(op, request,FALSE); -} -int sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request) { - return _sal_op_send_request_with_contact(op, request,TRUE); + bool_t need_ack=FALSE; + /* + 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),"OPTION")==0) + need_ack=TRUE; + + return _sal_op_send_request_with_contact(op, request,need_ack); } + void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { switch(code) { case 400: diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 590a92a18..9da9e1080 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -591,7 +591,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); - return sal_op_send_request_with_contact(op,req); + return sal_op_send_request(op,req); } int sal_unsubscribe(SalOp *op){ belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ @@ -601,7 +601,7 @@ int sal_unsubscribe(SalOp *op){ } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); - return sal_op_send_request_with_contact(op,req); + return sal_op_send_request(op,req); } int sal_subscribe_accept(SalOp *op){ belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index ea1eb6c82..a8ac7e874 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -119,7 +119,7 @@ static int send_register_request_with_expires(SalOp* op, belle_sip_request_t* re 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_with_contact(op,request); + return sal_op_send_request(op,request); } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 92df31eed..47a7cdd57 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -255,7 +255,7 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) obj->lc=lc; linphone_proxy_config_done(obj); } -#ifndef USE_BELLESIP + static char *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); char *ret=NULL; @@ -278,6 +278,12 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ localport = linphone_upnp_context_get_external_port(obj->lc->upnp); } #endif //BUILD_UPNP +#ifndef USE_BELLESIP + else { + linphone_address_destroy(contact); + return NULL; + } +#endif if(localip == NULL) { localip = localip_tmp; linphone_core_get_local_ip(obj->lc,host,localip_tmp); @@ -288,7 +294,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_set_port_int(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) { @@ -297,6 +303,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ 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); @@ -307,20 +314,17 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_destroy (proxy); return ret; } -#endif + static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ -#ifndef USE_BELLESIP char *contact; -#endif if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); -#ifndef USE_BELLESIP /*contact is automatically guessed by belle-sip*/ - contact=guess_contact_for_register(obj); - sal_op_set_contact(obj->op,contact); - ms_free(contact); -#endif + if ((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"); From abc0561441df285f3a093db609b4d317c3996df8 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 21 Feb 2013 11:08:52 +0100 Subject: [PATCH 053/909] make sure local ip is only guessed by core in case of upnp --- coreapi/proxy.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 47a7cdd57..706e93456 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -277,13 +277,16 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp); localport = linphone_upnp_context_get_external_port(obj->lc->upnp); } -#endif //BUILD_UPNP -#ifndef USE_BELLESIP - else { +#endif //BUILD_UPNP +#ifdef USE_BELLESIP +#ifdef BUILD_UPNP + else +#endif /*BUILD_UPNP*/ + { linphone_address_destroy(contact); return NULL; } -#endif +#endif /*USE_BELLESIP*/ if(localip == NULL) { localip = localip_tmp; linphone_core_get_local_ip(obj->lc,host,localip_tmp); From 2d49bfd8bec3bc21d4ff3961ecfeb224aaf3ef3c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 21 Feb 2013 14:53:10 +0100 Subject: [PATCH 054/909] finalize call transfert implementation --- coreapi/bellesip_sal/sal_op_call_transfer.c | 37 +++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 8dd289414..920f6a4cf 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -60,10 +60,12 @@ int sal_call_refer(SalOp *op, const char *refer_to){ 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) @@ -77,13 +79,29 @@ int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){ } 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) @@ -93,9 +111,16 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){ return 0; } /* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - ms_fatal("sal_call_get_replaces not implemented yet"); +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; } From 6791abd00d0fbb07eeb8aa1cbbba346777c81337 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 22 Feb 2013 15:44:33 +0100 Subject: [PATCH 055/909] implement CallReleased state transition --- coreapi/bellesip_sal/sal_impl.c | 20 ++++++++----- coreapi/bellesip_sal/sal_op_call.c | 47 ++++++++++++++++++++++-------- mediastreamer2 | 2 +- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ee82867c0..754c0ce46 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -310,8 +310,9 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } case 401: case 407:{ - if (op->state == SalOpStateTerminating) { - belle_sip_message("Op is in state terminating, nothing else to do"); + 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 "); return; } else { sal_process_authentication(op,response); @@ -340,12 +341,17 @@ static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *eve 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; + if(client_transaction) + trans=BELLE_SIP_TRANSACTION(client_transaction); + else + trans=BELLE_SIP_TRANSACTION(server_transaction); -/* SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); - if (op->calbacks.process_transaction_terminated) { - op->calbacks.process_transaction_terminated(op,event); - } else */{ - ms_error("Unhandled transaction terminated [%p]",client_transaction!=NULL?(void*)client_transaction:(void*)server_transaction); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(trans); + if (op && op->callbacks.process_transaction_terminated) { + op->callbacks.process_transaction_terminated(op,event); + } else { + ms_error("Unhandled transaction terminated [%p]",trans); } } static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 611ddf62f..0f752acf4 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -90,7 +90,7 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat if (belle_sip_dialog_get_previous_state(op->dialog) == BELLE_SIP_DIALOG_CONFIRMED) { /*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=SalOpStateTerminated; + op->state=SalOpStateTerminating; } else { /*let the process response handle this case*/ } @@ -119,6 +119,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t 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); char* reason; @@ -129,6 +130,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t ms_warning("Discarding state less response [%i] on op [%p]",code,op); return; } + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); reason=(char*)belle_sip_response_get_reason_phrase(response); if (reason_header){ reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); @@ -148,16 +150,19 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t /*check if op is terminating*/ - if (op->state == SalOpStateTerminating - && (!op->dialog - || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL - || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_EARLY)) { - /*FIXME if DIALOG_CONFIRM then ACK+BYE*/ - cancelling_invite(op); + if (op->state == SalOpStateTerminating) { + if( strcmp("INVITE",belle_sip_request_get_method(req))==0 + && (!op->dialog + || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL + || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_EARLY)) { + /*FIXME if DIALOG_CONFIRM then ACK+BYE*/ + cancelling_invite(op); - return; + return; + } else if (strcmp("BYE",belle_sip_request_get_method(req))==0) { + return; /*probably a 200ok for a bye*/ + } } - if (!op->dialog) { ms_message("call op [%p] receive out of dialog answer [%i]",op,code); return; @@ -185,7 +190,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t case SalOpStateActive: /*re-invite case*/ if (code >=200 && code<300 - && strcmp("INVITE",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction))))==0) { + && strcmp("INVITE",belle_sip_request_get_method(req))==0) { handle_sdp_from_response(op,response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack==NULL) { @@ -232,7 +237,25 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t } } static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - ms_error("process_transaction_terminated not implemented yet"); + SalOp* op = (SalOp*)user_ctx; + belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event); + belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); + belle_sip_request_t* req; + belle_sip_response_t* resp; + if (client_transaction) { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); + } else { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); + } + if (strcmp("BYE",belle_sip_request_get_method(req))==0 + && belle_sip_response_get_status_code(resp) !=401 + && belle_sip_response_get_status_code(resp) !=407) { + op->base.root->callbacks.call_released(op); + op->state=SalOpStateTerminated; + } + } 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; @@ -572,7 +595,7 @@ int sal_call_terminate(SalOp *op){ switch(dialog_state) { case BELLE_SIP_DIALOG_CONFIRMED: { sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); - op->state=SalOpStateTerminated; + op->state=SalOpStateTerminating; break; } case BELLE_SIP_DIALOG_NULL: { diff --git a/mediastreamer2 b/mediastreamer2 index a8538b58b..756a51419 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a8538b58b7845f06f8526aca9bcf6657cf0abea5 +Subproject commit 756a51419d833105a6378db71679073f6e9492b0 From 73722ac3ee8819f6915f7f7a987ece3940f520b5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 25 Feb 2013 11:24:56 +0100 Subject: [PATCH 056/909] add function to disable contact fixing --- coreapi/bellesip_sal/sal_impl.c | 131 +++++++++++++++++--------------- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/linphonecore.c | 4 +- coreapi/sal.h | 3 + 4 files changed, 78 insertions(+), 61 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 754c0ce46..c7ced7384 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -222,74 +222,77 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } if (op->callbacks.process_response_event) { - /*Fix contact if needed*/ - via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); - received = belle_sip_header_via_get_received(via_header); - rport = belle_sip_header_via_get_rport(via_header); - if (!sal_op_get_contact(op)) { - /*check if contqct set in reauest*/ - if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { - /*no contact set yet, try to see if sip tack has an updated one*/ - contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_object_unref(contact_address); - } else { + if (op->base.root->nat_helper_enabled) { + /*Fix contact if needed*/ + via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); + received = belle_sip_header_via_get_received(via_header); + rport = belle_sip_header_via_get_rport(via_header); + if (!sal_op_get_contact(op)) { + /*check if contqct set in reauest*/ - /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ - contact_address=belle_sip_header_address_new(); - contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); - belle_sip_header_address_set_uri(contact_address,contact_uri); + if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { + /*no contact set yet, try to see if sip tack has an updated one*/ + contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_object_unref(contact_address); + } else { + /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ + contact_address=belle_sip_header_address_new(); + contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); + belle_sip_header_address_set_uri(contact_address,contact_uri); + + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + } + if (belle_sip_header_via_get_listening_port(via_header) + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + } + contact_updated=TRUE; + } + } + + if (received!=NULL || rport>0) { + if (sal_op_get_contact(op)){ + contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); + } + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } + + /*try to fix transport if needed (very unlikely)*/ if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + if (!belle_sip_uri_get_transport_param(contact_uri) + ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); + } } - if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { - belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + if (contact_updated) { + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); + sal_op_set_contact(op,new_contact); + belle_sip_free(new_contact); } - contact_updated=TRUE; + if (contact_address)belle_sip_object_unref(contact_address); } } - - if (received!=NULL || rport>0) { - if (sal_op_get_contact(op)){ - contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - } - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } - - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) - ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; - } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); - } - } - if (contact_updated) { - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); - sal_op_set_contact(op,new_contact); - belle_sip_free(new_contact); - } - if (contact_address)belle_sip_object_unref(contact_address); - } /*update request/response * maybe only the transaction should be kept*/ old_request=op->request; @@ -369,6 +372,7 @@ Sal * sal_init(){ char stack_string[64]; belle_sip_listener_t* listener; Sal * sal=ms_new0(Sal,1); + sal->nat_helper_enabled=TRUE; snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); @@ -590,3 +594,10 @@ void sal_set_send_error(Sal *sal,int 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; + ms_message("Sal nat helper [%s]",enable?"enabled":"disabled"); +} +bool_t sal_nat_helper_enabled(Sal *sal) { + return sal->nat_helper_enabled; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index f6f395fb5..dc72545a0 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -35,6 +35,7 @@ struct Sal{ bool_t one_matching_codec; unsigned int keep_alive; bool_t use_tcp_tls_keep_alive; + bool_t nat_helper_enabled; }; typedef enum SalOpSate { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fc0a218bc..cb0f01e82 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -465,7 +465,8 @@ static void net_config_read (LinphoneCore *lc) linphone_core_set_mtu(lc,tmp); tmp=lp_config_get_int(lc->config,"net","download_ptime",0); linphone_core_set_download_ptime(lc,tmp); - + /*only set at setup*/ + sal_nat_helper_enable(lc->sal,lp_config_get_int(lc->config,"net","enable_nat_helper",1)); } static void build_sound_devices_table(LinphoneCore *lc){ @@ -1284,6 +1285,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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); diff --git a/coreapi/sal.h b/coreapi/sal.h index e48b593e4..d7c75b46c 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -516,4 +516,7 @@ void __sal_op_free(SalOp *b); void sal_set_send_error(Sal *sal,int value); /*1 for no error*/ 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 From 472805cef0046f3ef2ad7bc7ea19542322a1686e Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 26 Feb 2013 09:56:28 +0100 Subject: [PATCH 057/909] Disable NAT helper with uPnP --- coreapi/linphonecore.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cb0f01e82..f1c0b0129 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4307,6 +4307,14 @@ 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); + break; + default: + sal_nat_helper_enable(lc->sal, TRUE); + 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); From 40b65a779f523a908ae0b72e0dacf6a7187adce9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 26 Feb 2013 13:30:39 +0100 Subject: [PATCH 058/909] better op management to avoid transaction to refference a freed op --- coreapi/bellesip_sal/sal_impl.c | 2 ++ coreapi/bellesip_sal/sal_impl.h | 9 +++++++ coreapi/bellesip_sal/sal_op_call.c | 30 ++++++++++++++++------ coreapi/bellesip_sal/sal_op_impl.c | 22 ++++++++++++++-- coreapi/bellesip_sal/sal_op_message.c | 20 ++++++++++++++- coreapi/bellesip_sal/sal_op_presence.c | 4 --- coreapi/bellesip_sal/sal_op_registration.c | 2 +- mediastreamer2 | 2 +- tester/register_tester.c | 9 ++++--- 9 files changed, 79 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c7ced7384..cedd2b83f 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -313,6 +313,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } case 401: case 407:{ + /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ belle_sip_message("Op is in state terminating, nothing else to do "); @@ -356,6 +357,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } else { ms_error("Unhandled transaction terminated [%p]",trans); } + if (op) sal_op_unref(op); /*no longuer need to ref op*/ } static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { SalAuthInfo auth_info; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index dc72545a0..3c71af87f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -36,6 +36,7 @@ struct Sal{ unsigned int keep_alive; bool_t use_tcp_tls_keep_alive; bool_t nat_helper_enabled; + }; typedef enum SalOpSate { @@ -70,6 +71,8 @@ struct SalOp{ SalOpSate_t state; SalOpDir_t dir; belle_sip_refresher_t* refresher; + unsigned int call_released_timer; + unsigned int ref; }; belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); @@ -80,6 +83,12 @@ 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); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 0f752acf4..3440d532d 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -236,6 +236,13 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t /*dialog will terminated shortly, nothing to do*/ } } +static int call_released(void *user_ctx, unsigned int events) { + SalOp* op = (SalOp*)user_ctx; + op->base.root->callbacks.call_released(op); + op->state=SalOpStateTerminated; + op->call_released_timer=0; + return BELLE_SIP_STOP; +} 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); @@ -252,8 +259,11 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ if (strcmp("BYE",belle_sip_request_get_method(req))==0 && belle_sip_response_get_status_code(resp) !=401 && belle_sip_response_get_status_code(resp) !=407) { - op->base.root->callbacks.call_released(op); - op->state=SalOpStateTerminated; + + op->call_released_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack) + , call_released + , op + , 32000/*FIXME, should be T1*64*/); } } @@ -285,15 +295,19 @@ static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { 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 = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); - if (server_transaction) belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ - if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); - op->pending_server_trans=server_transaction; belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; belle_sip_header_t* call_info; + if (server_transaction) belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ + if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { + if (op->pending_server_trans)belle_sip_object_unref(op->pending_server_trans); + /*updating pending invite transaction*/ + op->pending_server_trans=server_transaction; + } + 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)); @@ -330,10 +344,10 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t /*first answer 200 ok to cancel*/ belle_sip_server_transaction_send_response(server_transaction ,belle_sip_response_create_from_request(req,200)); - /*terminate invite request*/ + /*terminate invite transaction*/ call_terminated(op - ,belle_sip_request_event_get_server_transaction(event) - ,belle_sip_request_event_get_request(event),487); + ,op->pending_server_trans + ,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487); } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 8f3254460..8efc282d3 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -23,10 +23,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new0(SalOp,1); __sal_op_init(op,sal); + sal_op_ref(op); return op; } - void sal_op_release(SalOp *op){ + op->state=SalOpStateTerminated; + sal_op_unref(op); +} +void sal_op_release_impl(SalOp *op){ + ms_message("Destroying op [%p]",op); if (op->request) belle_sip_object_unref(op->request); if (op->auth_info) sal_auth_info_delete(op->auth_info); if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); @@ -38,6 +43,7 @@ void sal_op_release(SalOp *op){ if(op->referred_by) belle_sip_object_unref(op->referred_by); if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); + if (op->call_released_timer) belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->call_released_timer); __sal_op_free(op); return ; } @@ -143,7 +149,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } client_transaction = belle_sip_provider_create_client_transaction(prov,request); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); if ( strcmp("INVITE",belle_sip_request_get_method(request))==0) { if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ @@ -256,3 +262,15 @@ void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { belle_sip_object_ref(op->dialog); } } +/*return reffed op*/ +SalOp* sal_op_ref(SalOp* op) { + op->ref++; + return op; +} +/*return null, destroy op if ref count =0*/ +void* sal_op_unref(SalOp* op) { + if (--op->ref <=0) { + sal_op_release_impl(op); + } + return NULL; +} diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 46492f63a..9949c03ce 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -30,14 +30,29 @@ static void process_error( SalOp* op) { static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ SalOp* op = (SalOp*)user_ctx; +// belle_sip_object_t* source = belle_sip_io_error_event_get_source(event); +// if (BELLE_SIP_IS_INSTANCE_OF(source,belle_sip_transaction_t)) { +// /*reset op to make sure transaction terminated does not need op*/ +// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(source),NULL); +// } process_error(op); } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; +// belle_sip_client_transaction_t *client_transaction=belle_sip_timeout_event_get_client_transaction(event); +// belle_sip_server_transaction_t *server_transaction=belle_sip_timeout_event_get_server_transaction(event); +// /*reset op to make sure transaction terminated does not need op*/ +// if (client_transaction) { +// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL); +// } else { +// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),NULL); +// } process_error(op); + } static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; + /*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/ int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); SalTextDeliveryStatus status; if (code>=100 && code <200) @@ -46,7 +61,10 @@ static void process_response_event(void *op_base, const belle_sip_response_event status=SalTextDeliveryDone; else status=SalTextDeliveryFailed; - + if (status != SalTextDeliveryInProgress) { + /*reset op to make sure transaction terminated does not need op + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/ + } op->base.root->callbacks.text_delivery_update(op,status); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 9da9e1080..18775a6c0 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -618,10 +618,6 @@ int sal_subscribe_decline(SalOp *op){ } int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); -/* belle_sip_header_address_t* identity=sal_op_get_contact_address(op); - if (identity==NULL) identity=sal_op_get_to_address(op); - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,identity);*/ add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*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))); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index a8ac7e874..609fb2b03 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -106,7 +106,7 @@ static void register_process_timeout(void *user_ctx, const belle_sip_timeout_eve } } static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - ms_error("process_transaction_terminated not implemented yet"); + /*ms_error("register_process_transaction_terminated not implemented yet");*/ } diff --git a/mediastreamer2 b/mediastreamer2 index 4ed2e518c..7a11d31f5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4ed2e518cf79c62fe8df7f23ce99e0fbfe2e799d +Subproject commit 7a11d31f5cab97ff0de373d617720bb651d19b7d diff --git a/tester/register_tester.c b/tester/register_tester.c index 1a6d7eaf8..a6b4b920a 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -48,7 +48,7 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route,bool_t late_auth_info) { int retry=0; LCSipTransports transport = {5070,5070,0,5071}; - + char* addr; CU_ASSERT_PTR_NOT_NULL_FATAL(lc); stats* counters = (stats*)linphone_core_get_user_data(lc); reset_counters(counters); @@ -59,7 +59,8 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const LinphoneAddress *from = create_linphone_address(domain); - linphone_proxy_config_set_identity(proxy_cfg,linphone_address_as_string(from)); + linphone_proxy_config_set_identity(proxy_cfg,addr=linphone_address_as_string(from)); + ms_free(addr); const char* server_addr = linphone_address_get_domain(from); linphone_proxy_config_enable_register(proxy_cfg,TRUE); @@ -284,7 +285,7 @@ static void io_recv_error(){ int register_test_suite () { CU_pSuite pSuite = CU_add_suite("Register", NULL, NULL); - if (NULL == CU_add_test(pSuite, "simple_register_tester", simple_register)) { + if (NULL == CU_add_test(pSuite, "simple_register", simple_register)) { return CU_get_error(); } if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { @@ -293,7 +294,7 @@ int register_test_suite () { if (NULL == CU_add_test(pSuite, "tls register tester", simple_tls_register)) { return CU_get_error(); } - if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { + if (NULL == CU_add_test(pSuite, "simple_authenticated_register", simple_authenticated_register)) { return CU_get_error(); } if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { From 35f3f8c72b617baa4d66968497645761db9125ba Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 26 Feb 2013 13:30:39 +0100 Subject: [PATCH 059/909] better op management to avoid transaction to refference a freed op --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e033b06a7..7a11d31f5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e033b06a731d0b9bc4e69afc690f6469eae73f66 +Subproject commit 7a11d31f5cab97ff0de373d617720bb651d19b7d From d70ed5075d307011c0de8ed7ddab27f29d735d4f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 26 Feb 2013 16:00:18 +0100 Subject: [PATCH 060/909] fix case where bye is not answer at all --- coreapi/bellesip_sal/sal_op_call.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 0f752acf4..d21c2fa24 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -250,8 +250,8 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); } if (strcmp("BYE",belle_sip_request_get_method(req))==0 - && belle_sip_response_get_status_code(resp) !=401 - && belle_sip_response_get_status_code(resp) !=407) { + && (!resp || (belle_sip_response_get_status_code(resp) !=401 + && belle_sip_response_get_status_code(resp) !=407))) { op->base.root->callbacks.call_released(op); op->state=SalOpStateTerminated; } From 7ac3735bde39757a1759d5eaedbf437a974e3f9d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 27 Feb 2013 11:24:39 +0100 Subject: [PATCH 061/909] make sure exosip is optionnal --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 7361fa6dc..a311afe34 100644 --- a/configure.ac +++ b/configure.ac @@ -419,8 +419,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, @@ -436,8 +434,6 @@ AC_ARG_ENABLE(ssl, 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]) @@ -685,6 +681,10 @@ if test $USE_BELLESIP_TRUE !='#' ; then SIPSTACK_LIBS=$BELLESIP_LIBS AC_DEFINE(USE_BELLESIP,1,[Defined when bellesip is used]) else + dnl check for osip2 + LP_CHECK_OSIP2 + dnl setup flags for exosip library + LP_SETUP_EXOSIP SIPSTACK_CFLAGS=$EXOSIP_CFLAGS $OSIP_CFLAGS SIPSTACK_LIBS=$EXOSIP_LIBS $OSIP_LIBS fi From 348e1ef87464285fcf9f34cee41f98f217be8bd7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 27 Feb 2013 12:40:46 +0100 Subject: [PATCH 062/909] Added vcxproj --- build/vsx/LibLinphone/LibLinphone.vcxproj | 201 ++++++++++++++++++ .../LibLinphone/LibLinphone.vcxproj.filters | 65 ++++++ 2 files changed, 266 insertions(+) create mode 100644 build/vsx/LibLinphone/LibLinphone.vcxproj create mode 100644 build/vsx/LibLinphone/LibLinphone.vcxproj.filters diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj new file mode 100644 index 000000000..14a40eaaa --- /dev/null +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + LibLinphone + en-US + 11.0 + + + + DynamicLibrary + true + v110 + false + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + _USRDLL;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + Level4 + $(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\oRTP\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;HAVE_SPEEXDSP;ORTP_INET6;WIN32;_DEBUG;_WINDOWS;_USRDLL;MEDIASTREAMER2_EXPORTS;MEDIASTREAMER2_INTERNAL_EXPORTS;WINDOW_NATIVE;_CRT_SECURE_NO_DEPRECATE;_TRUE_TIME;MS2_INTERNAL;MS2_FILTERS;IN_LINPHONE;USE_BELLESIP;%(PreprocessorDefinitions) + false + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + mediastreamer2_dll.lib;ortp_dll.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName)_dll.lib + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters new file mode 100644 index 000000000..7b4e3d0d3 --- /dev/null +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0b06ac3fb57e7e4453c6ee3be79663011f4bd3b0 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 27 Feb 2013 14:42:21 +0100 Subject: [PATCH 063/909] implement op->call_id --- coreapi/bellesip_sal/sal_impl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index cedd2b83f..619defd5c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -182,6 +182,9 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev 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)))); + } if (op->callbacks.process_request_event) { op->callbacks.process_request_event(op,event); } else { @@ -220,7 +223,9 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); } - + if (!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)))); + } if (op->callbacks.process_response_event) { if (op->base.root->nat_helper_enabled) { @@ -377,7 +382,10 @@ Sal * sal_init(){ sal->nat_helper_enabled=TRUE; snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); +#if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION) belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); +#endif + belle_sip_header_user_agent_add_product(sal->user_agent,stack_string); belle_sip_object_ref(sal->user_agent); belle_sip_set_log_handler(_belle_sip_log); From c3ebf99f5ea6ec9d1ef26b2c65f1f4262f4f00ca Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 27 Feb 2013 17:28:15 +0100 Subject: [PATCH 064/909] Fix compilation for WP8 --- build/vsx/LibLinphone/LibLinphone.vcxproj | 126 +++++++++--------- .../LibLinphone/LibLinphone.vcxproj.filters | 33 ++--- coreapi/bellesip_sal/sal_impl.c | 11 +- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_call_transfer.c | 4 +- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/bellesip_sal/sal_op_registration.c | 3 +- coreapi/callbacks.c | 4 +- coreapi/conference.c | 9 +- coreapi/ec-calibrator.c | 4 +- coreapi/friend.c | 10 +- coreapi/linphonecall.c | 61 ++++++--- coreapi/linphonecore.c | 18 ++- coreapi/lpconfig.c | 21 ++- coreapi/misc.c | 7 +- coreapi/offeranswer.c | 2 +- coreapi/private.h | 2 +- coreapi/sal.c | 2 +- coreapi/siplogin.c | 5 +- coreapi/test_ecc.c | 11 +- coreapi/upnp.c | 2 +- coreapi/upnp.h | 2 +- {coreapi => include/sal}/sal.h | 0 23 files changed, 194 insertions(+), 147 deletions(-) rename {coreapi => include/sal}/sal.h (100%) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 14a40eaaa..5dde944fb 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -94,20 +94,22 @@ Level4 - $(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\..\oRTP\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;HAVE_SPEEXDSP;ORTP_INET6;WIN32;_DEBUG;_WINDOWS;_USRDLL;MEDIASTREAMER2_EXPORTS;MEDIASTREAMER2_INTERNAL_EXPORTS;WINDOW_NATIVE;_CRT_SECURE_NO_DEPRECATE;_TRUE_TIME;MS2_INTERNAL;MS2_FILTERS;IN_LINPHONE;USE_BELLESIP;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;BUILD_UPNP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + false + false Console false false true - mediastreamer2_dll.lib;ortp_dll.lib;%(AdditionalDependencies) + belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) $(TargetDir)$(TargetName)_dll.lib @@ -117,10 +119,11 @@ - _USRDLL;NDEBUG;%(PreprocessorDefinitions) + _USRDLL;NDEBUG;IN_LINPHONE;WIN32;USE_BELLESIP;%(PreprocessorDefinitions) NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(Project)../../../../belle-sip/include;$(Project)../../../../oRTP/include;$(Project)../../../../mediastreamer2/include;$(Project)../../../coreapi;%(AdditionalIncludeDirectories) Console @@ -129,6 +132,65 @@ true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + false + true + false + true + false + + true @@ -138,62 +200,6 @@ false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters index 7b4e3d0d3..846ce2633 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters @@ -14,14 +14,9 @@ - - - - - @@ -29,37 +24,29 @@ - - - - - - - - - - - - + + + + + + + + + - - - - - - + \ No newline at end of file diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index cedd2b83f..22494b2a8 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config.h" #endif - void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { int ortp_level; switch(lev) { @@ -209,8 +208,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even int rport; bool_t contact_updated=FALSE; char* new_contact; - belle_sip_request_t* old_request=NULL;; - belle_sip_response_t* old_response=NULL;; + belle_sip_request_t* old_request=NULL; + belle_sip_response_t* old_response=NULL; if (op->state == SalOpStateTerminated) { @@ -346,12 +345,14 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans 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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(trans); + op = (SalOp*)belle_sip_transaction_get_application_data(trans); if (op && op->callbacks.process_transaction_terminated) { op->callbacks.process_transaction_terminated(op,event); } else { @@ -377,7 +378,7 @@ Sal * sal_init(){ sal->nat_helper_enabled=TRUE; snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); - belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); + belle_sip_header_user_agent_add_product(sal->user_agent, LINPHONE_PACKAGE_NAME "/" LINPHONE_VERSION); belle_sip_header_user_agent_add_product(sal->user_agent,stack_string); belle_sip_object_ref(sal->user_agent); belle_sip_set_log_handler(_belle_sip_log); diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index a4125f17f..085ce8f8b 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef SAL_IMPL_H_ #define SAL_IMPL_H_ -#include "sal.h" +#include "sal/sal.h" #include "belle-sip/belle-sip.h" #include "belle-sip/belle-sdp.h" diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 920f6a4cf..5afa9d8dc 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -162,8 +162,8 @@ int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ 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_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_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); belle_sip_response_t* resp; belle_sip_uri_t* refer_to_uri; diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 18775a6c0..8020436fc 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -479,7 +479,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_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_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);; + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); SalPresenceStatus estatus=SalPresenceOffline; SalSubscribeStatus sub_state; diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 609fb2b03..5ae44d93e 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -125,6 +125,7 @@ static int send_register_request_with_expires(SalOp* op, belle_sip_request_t* re int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; + belle_sip_uri_t* req_uri; sal_op_set_from(op,from); sal_op_set_to(op,from); sal_op_set_route(op,proxy); @@ -134,7 +135,7 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ op->callbacks.process_transaction_terminated=register_process_transaction_terminated; req = sal_op_build_request(op,"REGISTER"); - belle_sip_uri_t* req_uri = belle_sip_request_get_uri(req); + req_uri = belle_sip_request_get_uri(req); belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ return send_register_request_with_expires(op,req,expires); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 23f586088..b274dde1f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "sal.h" +#include "sal/sal.h" #include "linphonecore.h" #include "private.h" @@ -179,9 +179,9 @@ static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, c #endif static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) { + MSList *elem; ms_warning(" searching for already_a_call_with_remote_address."); - MSList *elem; for(elem=lc->calls;elem!=NULL;elem=elem->next){ const LinphoneCall *call=(LinphoneCall*)elem->data; const LinphoneAddress *cRemote=linphone_call_get_remote_address(call); diff --git a/coreapi/conference.c b/coreapi/conference.c index 16be62613..c98392e95 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -215,6 +215,7 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){ int err=0; + char *str; if (!call->current_params.in_conference){ if (call->params.in_conference){ @@ -227,7 +228,7 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a } call->params.in_conference=FALSE; - char *str=linphone_call_get_remote_address_as_string(call); + str=linphone_call_get_remote_address_as_string(call); ms_message("%s will be removed from conference", str); ms_free(str); if (active){ @@ -283,10 +284,11 @@ static int convert_conference_to_call(LinphoneCore *lc){ * @returns 0 if successful, -1 otherwise. **/ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ + int err; char * str=linphone_call_get_remote_address_as_string(call); ms_message("Removing call %s from the conference", str); ms_free(str); - int err=remove_from_conference(lc,call, FALSE); + err=remove_from_conference(lc,call, FALSE); if (err){ ms_error("Error removing participant from conference."); return err; @@ -335,13 +337,14 @@ int linphone_core_leave_conference(LinphoneCore *lc){ * @returns 0 if successful, -1 otherwise **/ int linphone_core_enter_conference(LinphoneCore *lc){ + LinphoneConference *conf; if (linphone_core_sound_resources_locked(lc)) { return -1; } if (lc->current_call != NULL) { linphone_core_pause_call(lc, lc->current_call); } - LinphoneConference *conf=&lc->conf_ctx; + conf=&lc->conf_ctx; if (conf->local_participant==NULL) add_local_endpoint(conf,lc); return 0; } diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 8efbabb1b..f0f009747 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -241,11 +241,13 @@ void ec_calibrator_destroy(EcCalibrator *ecc){ } int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data){ + unsigned int rate; + if (lc->ecc!=NULL){ ms_error("Echo calibration is still on going !"); return -1; } - unsigned int rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); + rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,cb_data); return 0; } diff --git a/coreapi/friend.c b/coreapi/friend.c index 3bc30cff0..b1dd9c4c9 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -152,11 +152,13 @@ LinphoneFriend * linphone_friend_new(){ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ LinphoneAddress* linphone_address = linphone_address_new(addr); + LinphoneFriend *fr; + if (linphone_address == NULL) { ms_error("Cannot create friend for address [%s]",addr?addr:"null"); return NULL; } - LinphoneFriend *fr=linphone_friend_new(); + fr=linphone_friend_new(); if (linphone_friend_set_addr(fr,linphone_address)<0){ linphone_friend_destroy(fr); return NULL; @@ -440,6 +442,8 @@ LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, cons const MSList *elem; const char *username; const char *domain; + const char *it_username; + const char *it_host; LinphoneFriend *lf=NULL; if (puri==NULL){ @@ -453,8 +457,8 @@ LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, cons } for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ lf=(LinphoneFriend*)elem->data; - const char *it_username=linphone_address_get_username(lf->uri); - const char *it_host=linphone_address_get_domain(lf->uri);; + 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; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ba495f41d..86a5540aa 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -120,9 +120,10 @@ static void linphone_call_videostream_encryption_changed(void *data, bool_t encr static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) { char status[255]={0}; + LinphoneCall *call; ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted"); - LinphoneCall *call = (LinphoneCall *)data; + call = (LinphoneCall *)data; call->audiostream_encrypted=encrypted; if (encrypted && call->core->vtable.display_status != NULL) { @@ -1333,6 +1334,13 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0); int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0); + float speed; + float force; + int sustain; + float transmit_thres; + MSFilter *f=NULL; + float floorgain; + int spk_agc; if (!muted) linphone_core_set_mic_gain_db (lc, mic_gain); @@ -1346,12 +1354,11 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); - float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); + speed=lp_config_get_float(lc->config,"sound","el_speed",-1); thres=lp_config_get_float(lc->config,"sound","el_thres",-1); - float force=lp_config_get_float(lc->config,"sound","el_force",-1); - int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); - float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1); - MSFilter *f=NULL; + force=lp_config_get_float(lc->config,"sound","el_force",-1); + sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); + transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1); f=st->volsend; if (speed==-1) speed=0.03; if (force==-1) force=25; @@ -1369,8 +1376,8 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute } if (st->volrecv){ /* parameters for a limited noise-gate effect, using echo limiter threshold */ - float floorgain = 1/pow(10,(mic_gain)/10); - int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); + floorgain = 1/pow(10,(mic_gain)/10); + spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain); @@ -1478,9 +1485,19 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna LinphoneCore *lc=call->core; int used_pt=-1; char rtcp_tool[128]={0}; + const SalStreamDescription *stream; + MSSndCard *playcard; + MSSndCard *captcard; + bool_t use_ec; + bool_t mute; + const char *playfile; + const char *recfile; + const SalStreamDescription *local_st_desc; + int crypto_idx; + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); /* look for savp stream first */ - const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpSavp,SalAudio); /* no savp audio stream, use avp */ if (!stream) @@ -1488,13 +1505,12 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna SalProtoRtpAvp,SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ - MSSndCard *playcard=lc->sound_conf.lsd_card ? + playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; - MSSndCard *captcard=lc->sound_conf.capt_sndcard; - const char *playfile=lc->play_file; - const char *recfile=lc->rec_file; + captcard=lc->sound_conf.capt_sndcard; + playfile=lc->play_file; + recfile=lc->rec_file; call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); - bool_t use_ec; if (used_pt!=-1){ call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); @@ -1570,9 +1586,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna /* valid local tags are > 0 */ if (stream->proto == SalProtoRtpSavp) { - const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, + local_st_desc=sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp,SalAudio); - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); if (crypto_idx >= 0) { audio_stream_enable_srtp( @@ -1588,7 +1604,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna }else call->audiostream_encrypted=FALSE; if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ - bool_t mute=stream->dir==SalStreamRecvOnly; + mute=stream->dir==SalStreamRecvOnly; linphone_call_add_to_conf(call, mute); } call->current_params.in_conference=call->params.in_conference; @@ -1696,13 +1712,15 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ LinphoneCore *lc=call->core; + LinphoneAddress *me; + char *cname; + bool_t use_arc; call->current_params.audio_codec = NULL; call->current_params.video_codec = NULL; - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); - char *cname; - bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); + me=linphone_core_get_primary_contact_parsed(lc); + use_arc=linphone_core_adaptive_rate_control_enabled(lc); #ifdef VIDEO_ENABLED const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); @@ -2373,10 +2391,11 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, VideoStream* vstream = call->videostream; if (vstream && vstream->output) { float zoom[3]; + float halfsize; if (zoom_factor < 1) zoom_factor = 1; - float halfsize = 0.5 * 1.0 / zoom_factor; + halfsize = 0.5 * 1.0 / zoom_factor; if ((*cx - halfsize) < 0) *cx = 0 + halfsize; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f1c0b0129..199a1cc3b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2176,7 +2176,7 @@ void linphone_core_iterate(LinphoneCore *lc){ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){ enum_lookup_res_t *enumres=NULL; char *enum_domain=NULL; - LinphoneProxyConfig *proxy=lc->default_proxy;; + LinphoneProxyConfig *proxy=lc->default_proxy; char *tmpurl; LinphoneAddress *uri; @@ -5344,9 +5344,10 @@ static void linphone_core_uninit(LinphoneCore *lc) } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ - ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); // second get the list of available proxies const MSList *elem=linphone_core_get_proxy_config_list(lc); + + 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) ) { @@ -5661,13 +5662,18 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ } const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri) { + MSList *calls; + const LinphoneCall *c; + const LinphoneAddress *address; + char *current_uri; + if (uri == NULL) return NULL; - MSList *calls=lc->calls; + calls=lc->calls; while(calls) { - const LinphoneCall *c=(LinphoneCall*)calls->data; + c=(LinphoneCall*)calls->data; calls=calls->next; - const LinphoneAddress *address = linphone_call_get_remote_address(c); - char *current_uri=linphone_address_as_string_uri_only(address); + address = linphone_call_get_remote_address(c); + current_uri=linphone_address_as_string_uri_only(address); if (strcmp(uri,current_uri)==0) { ms_free(current_uri); return c; diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 4608beecf..5f90855f5 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -34,6 +34,9 @@ #include #include #include +#if _MSC_VER +#include +#endif #endif /*_WIN32_WCE*/ @@ -140,18 +143,20 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){ void lp_config_parse(LpConfig *lpconfig, FILE *file){ char tmp[MAX_LEN]= {'\0'}; LpSection *cur=NULL; + char *pos1,*pos2; + int nbs; + char secname[MAX_LEN]; + char key[MAX_LEN]; + LpItem *item; if (file==NULL) return; while(fgets(tmp,MAX_LEN,file)!=NULL){ tmp[sizeof(tmp) -1] = '\0'; - char *pos1,*pos2; pos1=strchr(tmp,'['); if (pos1!=NULL && is_first_char(tmp,pos1) ){ pos2=strchr(pos1,']'); if (pos2!=NULL){ - int nbs; - char secname[MAX_LEN]; secname[0]='\0'; /* found section */ *pos2='\0'; @@ -171,7 +176,6 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ }else { pos1=strchr(tmp,'='); if (pos1!=NULL){ - char key[MAX_LEN]; key[0]='\0'; *pos1='\0'; @@ -191,7 +195,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ if (pos2-pos1>=0){ /* found a pair key,value */ if (cur!=NULL){ - LpItem *item=lp_section_find_item(cur,key); + item=lp_section_find_item(cur,key); if (item==NULL){ lp_section_add_item(cur,lp_item_new(key,pos1)); }else{ @@ -211,17 +215,20 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ LpConfig * lp_config_new(const char *filename){ LpConfig *lpconfig=lp_new0(LpConfig,1); + struct stat fileStat; if (filename!=NULL){ lpconfig->filename=ortp_strdup(filename); lpconfig->file=fopen(filename,"rw"); if (lpconfig->file!=NULL){ - struct stat fileStat; 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_IRUSR | S_IWUSR) == -1) { + if (_chmod(filename, _S_IREAD | _S_IWRITE) == -1) { ms_warning("unable to correct permissions on " "configuration file: %s", strerror(errno)); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 927c3b55a..bc681d2fa 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -32,7 +32,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#if _MSC_VER +#include +#else #include +#endif #include #endif /*_WIN32_WCE*/ @@ -585,9 +589,10 @@ int linphone_core_get_edge_ptime(LinphoneCore *lc){ } void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){ + int threshold; if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ ms_message("Stun server ping time is %i ms",ping_time_ms); - int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); + threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); if (ping_time_ms>threshold){ /* we might be in a 2G network*/ diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index ab38f7636..81e212b40 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "sal.h" +#include "sal/sal.h" #include "offeranswer.h" #include "private.h" diff --git a/coreapi/private.h b/coreapi/private.h index d478a32ef..c76e3ccbc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,7 +31,7 @@ extern "C" { #include "linphonefriend.h" #include "linphone_tunnel.h" #include "linphonecore_utils.h" -#include "sal.h" +#include "sal/sal.h" #include "sipsetup.h" #ifdef HAVE_CONFIG_H diff --git a/coreapi/sal.c b/coreapi/sal.c index ffb1b215a..07d189ed8 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. protocols and implementations under linphone, for example SIP, JINGLE... **/ -#include "sal.h" +#include "sal/sal.h" const char* sal_transport_to_string(SalTransport transport) { switch (transport) { case SalTransportUDP:return "udp"; diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index 6903638d6..f29398c93 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -113,10 +113,9 @@ SipSetup linphone_sip_login={ NULL, NULL, NULL, + sip_login_do_logout, NULL, - NULL, - NULL, - sip_login_do_logout + NULL }; diff --git a/coreapi/test_ecc.c b/coreapi/test_ecc.c index 43ae0dcb2..a0baeea40 100644 --- a/coreapi/test_ecc.c +++ b/coreapi/test_ecc.c @@ -21,6 +21,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "linphonecore_utils.h" +#if _MSC_VER +#include +#endif static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){ ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure"); @@ -30,6 +33,9 @@ static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus st static char config_file[1024]; void parse_args(int argc, char *argv[]){ +#ifndef F_OK +#define F_OK 4 +#endif if (argc != 3 || strncmp("-c",argv[1], 2) || access(argv[2],F_OK)!=0) { printf("Usage: test_ecc [-c config_file] where config_file will be written with the detected value\n"); exit(-1); @@ -38,10 +44,11 @@ void parse_args(int argc, char *argv[]){ } int main(int argc, char *argv[]){ - if (argc>1) parse_args(argc,argv); int count=0; LinphoneCoreVTable vtable={0}; - LinphoneCore *lc=linphone_core_new(&vtable,config_file,NULL,NULL); + LinphoneCore *lc; + if (argc>1) parse_args(argc,argv); + lc=linphone_core_new(&vtable,config_file,NULL,NULL); linphone_core_enable_logs(NULL); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 86d16d0f0..4672685bd 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -491,7 +491,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind mapping.remote_port = port->external_port; mapping.remote_host = ""; snprintf(description, 128, "%s %s at %s:%d", - PACKAGE_NAME, + LINPHONE_PACKAGE_NAME, (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP": "UDP", port->local_addr, port->local_port); mapping.description = description; diff --git a/coreapi/upnp.h b/coreapi/upnp.h index fe403a772..81edc5986 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/upnp_igd.h" #include "linphonecore.h" -#include "sal.h" +#include "sal/sal.h" typedef struct _UpnpSession UpnpSession; typedef struct _UpnpContext UpnpContext; diff --git a/coreapi/sal.h b/include/sal/sal.h similarity index 100% rename from coreapi/sal.h rename to include/sal/sal.h From e7af27f1a16f7f231798b067ac5035f51ad75bf8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Feb 2013 11:08:09 +0100 Subject: [PATCH 065/909] Fix link step of compilation --- build/vsx/LibLinphone/LibLinphone.vcxproj | 4 +--- build/vsx/LibLinphone/LibLinphone.vcxproj.filters | 2 -- coreapi/misc.c | 7 ++++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 5dde944fb..ddd2609d9 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -95,7 +95,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;BUILD_UPNP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing @@ -161,7 +161,6 @@ - @@ -173,7 +172,6 @@ - diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters index 846ce2633..23a8a72b9 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters @@ -26,7 +26,6 @@ - @@ -46,7 +45,6 @@ - \ No newline at end of file diff --git a/coreapi/misc.c b/coreapi/misc.c index bc681d2fa..d87d003a8 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -48,6 +48,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif +#if _MSC_VER +#define snprintf _snprintf +#define popen _popen +#define pclose _pclose +#endif #if !defined(WIN32) @@ -107,7 +112,7 @@ int remove_lock_file() char *int2str(int number) { char *numstr=ms_malloc(10); - snprintf(numstr,10,"%i",number); + _snprintf(numstr,10,"%i",number); return numstr; } From 29d9fa7c925bd826578fb6bd257d0172e7d523eb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Feb 2013 11:24:28 +0100 Subject: [PATCH 066/909] Fix win32 targets --- build/vsx/LibLinphone/LibLinphone.vcxproj | 45 ++++++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index ddd2609d9..57a94e932 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -65,7 +65,11 @@ - _USRDLL;%(PreprocessorDefinitions) + Level4 + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + false + Default NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) @@ -75,11 +79,23 @@ false false true + belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName)_dll.lib + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + - _USRDLL;NDEBUG;%(PreprocessorDefinitions) + Level4 + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + true + true + Default + true NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) @@ -88,8 +104,14 @@ Console false false - true + false + belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName)_dll.lib + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + @@ -119,18 +141,29 @@ - _USRDLL;NDEBUG;IN_LINPHONE;WIN32;USE_BELLESIP;%(PreprocessorDefinitions) + Level4 + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + true + true + Default + true NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(Project)../../../../belle-sip/include;$(Project)../../../../oRTP/include;$(Project)../../../../mediastreamer2/include;$(Project)../../../coreapi;%(AdditionalIncludeDirectories) Console false false - true + false + belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName)_dll.lib + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + From 1721fbd084e2bb79ef1712e453b31acc8bc0549d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Feb 2013 13:26:08 +0100 Subject: [PATCH 067/909] Started linphone exports --- coreapi/linphonecore.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2c2168646..9a0526f36 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -33,6 +33,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 +#ifdef LIBLINPHONE_EXPORTS +#define LINPHONE_PUBLIC __declspec(dllexport) +#else +#define LINPHONE_PUBLIC __declspec(dllimport) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -848,7 +854,7 @@ const char *linphone_core_get_version(void); const char *linphone_core_get_user_agent_name(void); const char *linphone_core_get_user_agent_version(void); -LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, +LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config, void* userdata); /* function to be periodically called in a main loop */ @@ -1416,11 +1422,8 @@ 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); - - #ifdef __cplusplus } #endif - #endif From bf0db8f9e4e18b4745a55e7943b59ced8ff4a8d2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 28 Feb 2013 16:06:13 +0100 Subject: [PATCH 068/909] io error repporting for calls --- coreapi/bellesip_sal/sal_impl.c | 10 ++++++++-- coreapi/bellesip_sal/sal_op_call.c | 9 ++++++++- coreapi/bellesip_sal/sal_op_impl.c | 6 +++--- coreapi/sal.h | 3 +++ tester/call_tester.c | 20 ++++++++++++++++++++ tester/liblinphone_tester.c | 10 ++++++---- 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 619defd5c..17e3f2d42 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -582,8 +582,8 @@ MSList * sal_get_pending_auths(Sal *sal){ /*misc*/ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen){ - ms_fatal("sal_get_default_local_ip not implemented yet"); - return ; + strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); + ms_error("Could not find default routable ip address !"); } const char *sal_get_root_ca(Sal* ctx) { @@ -611,3 +611,9 @@ void sal_nat_helper_enable(Sal *sal,bool_t enable) { 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); +} diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 88f6d7457..f2ec4e883 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -81,7 +81,14 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription } static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - ms_error("call_process_io_error not implemented yet"); + SalOp* op=(SalOp*)user_ctx; + if (!op->dialog) { + /*call terminated very early*/ + op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); + op->state=SalOpStateTerminated; + } 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; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index c33feb7d4..43ceb22ae 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -169,7 +169,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { - bool_t need_ack=FALSE; + bool_t need_contact=FALSE; /* Header field where proxy ACK BYE CAN INV OPT REG ___________________________________________________________ @@ -179,9 +179,9 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { ||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),"OPTION")==0) - need_ack=TRUE; + need_contact=TRUE; - return _sal_op_send_request_with_contact(op, request,need_ack); + return _sal_op_send_request_with_contact(op, request,need_contact); } diff --git a/coreapi/sal.h b/coreapi/sal.h index d7c75b46c..886f69c0f 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -519,4 +519,7 @@ 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); + +void sal_set_dns_timeout(Sal* sal,int timeout); +int sal_get_dns_timeout(const Sal* sal); #endif diff --git a/tester/call_tester.c b/tester/call_tester.c index c68ec96ab..8ffbdb7bf 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -197,6 +197,22 @@ static void call_canceled() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void call_with_dns_time_out() { + LinphoneCoreManager* marie = linphone_core_manager_new(NULL); + LCSipTransports transport = {9773,0,0,0}; + linphone_core_set_sip_transports(marie->lc,&transport); + linphone_core_iterate(marie->lc); + sal_set_dns_timeout(marie->lc->sal,0); + linphone_core_invite(marie->lc,"sip:toto@toto.com"); + linphone_core_iterate(marie->lc); + linphone_core_iterate(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + linphone_core_manager_destroy(marie); +} + static void call_ringing_canceled() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -585,6 +601,10 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "call_with_dns_time_out", call_with_dns_time_out)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { return CU_get_error(); } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index ebbafc7d1..4c8861a13 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -159,17 +159,19 @@ LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) { mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; - mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); + mgr->lc=configure_lc_from(&mgr->v_table,rc_file,rc_file?1:0); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); linphone_core_get_default_proxy(mgr->lc,&proxy); - mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - linphone_address_clean(mgr->identity); + if (proxy) { + mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(mgr->identity); + } return mgr; } void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); - linphone_address_destroy(mgr->identity); + if (mgr->identity) linphone_address_destroy(mgr->identity); free(mgr); } From ed4ef8a76c203ef56ad4a32ca89e1a9465028ee1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Feb 2013 16:27:20 +0100 Subject: [PATCH 069/909] Added project for tester + more linphonecore exports --- .../LibLinphoneTester.vcxproj | 159 ++++++++++++++++ .../LibLinphoneTester.vcxproj.filters | 19 ++ coreapi/linphonecore.h | 176 +++++++++--------- coreapi/linphonefriend.h | 14 +- include/sal/sal.h | 10 +- tester/call_tester.c | 63 ++++--- tester/liblinphone_tester.c | 18 +- tester/message_tester.c | 3 +- tester/presence_tester.c | 9 +- tester/register_tester.c | 38 ++-- 10 files changed, 359 insertions(+), 150 deletions(-) create mode 100644 build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj create mode 100644 build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj new file mode 100644 index 000000000..1685afd27 --- /dev/null +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5e94a00b-b14a-4e42-8284-8cb0ef099534} + LibLinphoneTester + en-US + 11.0 + + + + DynamicLibrary + true + v110 + false + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + false + + + + _USRDLL;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + WIN32;_DEBUG;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + + + Console + false + false + true + ws2_32.lib;%(AdditionalDependencies) + ole32.lib;%(IgnoreSpecificDefaultLibraries) + $(SolutionDir)$(Platform)\$(Configuration) + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + true + + + true + false + + + + + + + + + + + + + + + {902daf1d-ebf1-4d03-b598-143500a50ab4} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters new file mode 100644 index 000000000..5e3ead950 --- /dev/null +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters @@ -0,0 +1,19 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + \ No newline at end of file diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9a0526f36..2012492c4 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -83,12 +83,12 @@ typedef struct SalAddress LinphoneAddress; #include "linphone/linphonefriend.h" #endif -LinphoneAddress * linphone_address_new(const char *uri); +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); -const char *linphone_address_get_display_name(const LinphoneAddress* u); -const char *linphone_address_get_username(const LinphoneAddress *u); -const char *linphone_address_get_domain(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. * @@ -98,17 +98,17 @@ 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); -void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name); -void linphone_address_set_username(LinphoneAddress *uri, const char *username); -void linphone_address_set_domain(LinphoneAddress *uri, const char *host); +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*/ -void linphone_address_clean(LinphoneAddress *uri); -char *linphone_address_as_string(const LinphoneAddress *u); +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); -bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); -void linphone_address_destroy(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; @@ -190,9 +190,9 @@ 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); -LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp); -void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); -bool_t linphone_call_params_video_enabled(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); @@ -372,28 +372,28 @@ typedef enum _LinphoneCallState{ LinphoneCallReleased /**< The call object is no more retained by the core */ } LinphoneCallState; -const char *linphone_call_state_to_string(LinphoneCallState cs); +LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs); LinphoneCore *linphone_call_get_core(const LinphoneCall *call); -LinphoneCallState linphone_call_get_state(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call); bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); -const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); +LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); -LinphoneCall * linphone_call_ref(LinphoneCall *call); -void linphone_call_unref(LinphoneCall *call); -LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall * linphone_call_ref(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_unref(LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); const char *linphone_call_get_refer_to(const LinphoneCall *call); bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); -LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); int linphone_call_get_duration(const LinphoneCall *call); -const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); bool_t linphone_call_camera_enabled(const LinphoneCall *lc); int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); -LinphoneReason linphone_call_get_reason(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); const char *linphone_call_get_remote_user_agent(LinphoneCall *call); const char *linphone_call_get_remote_contact(LinphoneCall *call); float linphone_call_get_play_volume(LinphoneCall *call); @@ -403,10 +403,10 @@ float linphone_call_get_average_quality(LinphoneCall *call); const char* linphone_call_get_authentication_token(LinphoneCall *call); bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); -void linphone_call_send_vfu_request(LinphoneCall *call); -void *linphone_call_get_user_pointer(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_send_vfu_request(LinphoneCall *call); +LINPHONE_PUBLIC void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); -void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); +LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); void linphone_call_start_recording(LinphoneCall *call); @@ -493,23 +493,23 @@ typedef enum _LinphoneRegistrationState{ * Human readable version of the #LinphoneRegistrationState * @param cs sate */ -const char *linphone_registration_state_to_string(LinphoneRegistrationState cs); +LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegistrationState cs); -LinphoneProxyConfig *linphone_proxy_config_new(void); -int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); -int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); -int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); -void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires); +LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void); +LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); +LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); +LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); +LINPHONE_PUBLIC void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires); /** * Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig . *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. * @param obj object pointer * @param val if true, registration will be engaged */ -void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); +LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); #define linphone_proxy_config_enableregister linphone_proxy_config_enable_register -void linphone_proxy_config_edit(LinphoneProxyConfig *obj); -int linphone_proxy_config_done(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC void linphone_proxy_config_edit(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *obj); /** * Indicates either or not, PUBLISH must be issued for this #LinphoneProxyConfig . *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. @@ -517,18 +517,18 @@ int linphone_proxy_config_done(LinphoneProxyConfig *obj); * @param val if true, publish will be engaged * */ -void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val); +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); -bool_t linphone_proxy_config_is_registered(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); -const char *linphone_proxy_config_get_identity(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); -const char *linphone_proxy_config_get_addr(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); @@ -617,7 +617,7 @@ struct _LinphoneAuthInfo; **/ typedef struct _LinphoneAuthInfo LinphoneAuthInfo; -LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, +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); @@ -668,23 +668,23 @@ typedef enum _LinphoneChatMessageStates { */ typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); -LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); void linphone_chat_room_destroy(LinphoneChatRoom *cr); -LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); -void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); -void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); +LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); +LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); -const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); +LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); -LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); -const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); -void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); -const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); +LINPHONE_PUBLIC LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); +LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); @@ -847,7 +847,7 @@ typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *contex /* THE main API */ -void linphone_core_enable_logs(FILE *file); +LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file); void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); void linphone_core_disable_logs(void); const char *linphone_core_get_version(void); @@ -859,7 +859,7 @@ LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable /* function to be periodically called in a main loop */ /* For ICE to work properly it should be called every 20ms */ -void linphone_core_iterate(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_iterate(LinphoneCore *lc); #if 0 /*not implemented yet*/ /** * @ingroup initializing @@ -884,43 +884,43 @@ void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const c LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); -LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); -LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); -int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); +LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); -int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); +LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); -bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); +LINPHONE_PUBLIC bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); bool_t linphone_core_in_call(const LinphoneCore *lc); -LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); -int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); -int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri); int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); -int linphone_core_terminate_all_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_terminate_all_calls(LinphoneCore *lc); -int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_pause_all_calls(LinphoneCore *lc); -int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); @@ -964,7 +964,7 @@ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); int linphone_core_get_upload_ptime(LinphoneCore *lc); /* returns a MSList of PayloadType */ -const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); /* returns a MSList of PayloadType */ @@ -974,7 +974,7 @@ int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); -int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); +LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); /** * Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algirithm @@ -996,7 +996,7 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t * @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS * @return Returns NULL if not found. */ -PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; +LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); @@ -1012,21 +1012,21 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType */ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); -int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); void linphone_core_clear_proxy_config(LinphoneCore *lc); void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); -void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); -int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); +LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); -void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); +LINPHONE_PUBLIC void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); @@ -1086,9 +1086,9 @@ void linphone_core_set_sip_port(LinphoneCore *lc, int port); int linphone_core_get_sip_port(LinphoneCore *lc); -int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); +LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); -int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); +LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); /** * * Give access to the UDP sip socket. Can be useful to configure this socket as persistent I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP) @@ -1181,13 +1181,13 @@ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); char linphone_core_get_sound_source(LinphoneCore *lc); void linphone_core_set_sound_source(LinphoneCore *lc, char source); -void linphone_core_set_ring(LinphoneCore *lc, const char *path); +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); -void linphone_core_set_ringback(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC void linphone_core_set_ringback(LinphoneCore *lc, const char *path); const char * linphone_core_get_ringback(const LinphoneCore *lc); void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *); @@ -1226,9 +1226,9 @@ void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); /* video support */ bool_t linphone_core_video_supported(LinphoneCore *lc); -void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled); +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); -void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); +LINPHONE_PUBLIC void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc); typedef struct MSVideoSizeDef{ @@ -1296,7 +1296,7 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu); * Calling this method with true trigger linphone to initiate a registration process for all proxies. * Calling this method disables the automatic network detection mode. It means you must call this method after each network state changes. */ -void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value); +LINPHONE_PUBLIC void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value); /** * @ingroup network_parameters * return network state either as positioned by the application or by linphone itself. @@ -1314,8 +1314,8 @@ void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable); */ bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc); -void *linphone_core_get_user_data(LinphoneCore *lc); -void linphone_core_set_user_data(LinphoneCore *lc, void *userdata); +LINPHONE_PUBLIC void *linphone_core_get_user_data(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_user_data(LinphoneCore *lc, void *userdata); /* returns LpConfig object to read/write to the config file: usefull if you wish to extend the config file with your own sections */ @@ -1327,7 +1327,7 @@ void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallbac /*returns the list of registered SipSetup (linphonecore plugins) */ const MSList * linphone_core_get_sip_setups(LinphoneCore *lc); -void linphone_core_destroy(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_destroy(LinphoneCore *lc); /*for advanced users:*/ typedef RtpTransport * (*LinphoneRtpTransportFactoryFunc)(void *data, int port); @@ -1349,7 +1349,7 @@ int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, r int linphone_core_get_calls_nb(const LinphoneCore *lc); -const MSList *linphone_core_get_calls(LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_calls(LinphoneCore *lc); LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc); /** @@ -1364,16 +1364,16 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); -int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); +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); -bool_t linphone_core_is_in_conference(const LinphoneCore *lc); +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); -int linphone_core_terminate_conference(LinphoneCore *lc); -int linphone_core_get_conference_size(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_terminate_conference(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_conference_size(LinphoneCore *lc); int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path); int linphone_core_stop_conference_recording(LinphoneCore *lc); @@ -1387,8 +1387,8 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone /** * Choose media encryption policy to be used for RTP packets */ -int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); -LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); +LINPHONE_PUBLIC LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc); /** diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index ab75b7bf7..90491df5b 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -117,7 +117,7 @@ LinphoneFriend * linphone_friend_new(); * @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink */ -LinphoneFriend *linphone_friend_new_with_addr(const char *addr); +LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_addr(const char *addr); /** * Destructor @@ -137,7 +137,7 @@ int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneAddress* address) * @param lf #LinphoneFriend object * @return #LinphoneAddress */ -const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); +LINPHONE_PUBLIC const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); /** * get subscription flag value * @param lf #LinphoneFriend object @@ -153,7 +153,7 @@ bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf); * @param val if TRUE this friend will receive subscription message */ -int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val); +LINPHONE_PUBLIC int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val); #define linphone_friend_send_subscribe linphone_friend_enable_subscribes /** @@ -179,12 +179,12 @@ LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneF * Once the modifications are done, then the application must call * linphone_friend_done() to commit the changes. **/ -void linphone_friend_edit(LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_friend_edit(LinphoneFriend *fr); /** * Commits modification made to the friend configuration. * @param fr #LinphoneFriend object **/ -void linphone_friend_done(LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); @@ -229,7 +229,7 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char * @param lc #LinphoneCore object * @param fr #LinphoneFriend to add */ -void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr); /** * remove a friend from the buddy list * @param lc #LinphoneCore object @@ -246,7 +246,7 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); * get Buddy list of LinphoneFriend * @param lc #LinphoneCore object * */ -const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); /** * notify all friends that have subscribed * @param lc #LinphoneCore object diff --git a/include/sal/sal.h b/include/sal/sal.h index d7c75b46c..4062f6df0 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -29,6 +29,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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 @@ -513,9 +519,9 @@ void __sal_op_free(SalOp *b); /*test api*/ /*0 for no error*/ -void sal_set_send_error(Sal *sal,int value); +LINPHONE_PUBLIC void sal_set_send_error(Sal *sal,int value); /*1 for no error*/ -void sal_set_recv_error(Sal *sal,int value); +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); diff --git a/tester/call_tester.c b/tester/call_tester.c index c68ec96ab..55f1f7dc8 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -32,11 +32,11 @@ static int uninit(void) { 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("call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(cstate)); ms_free(to); ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); switch (cstate) { case LinphoneCallIncomingReceived:counters->number_of_LinphoneCallIncomingReceived++;break; case LinphoneCallOutgoingInit :counters->number_of_LinphoneCallOutgoingInit++;break; @@ -63,12 +63,12 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState 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); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); switch (new_call_state) { case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; case LinphoneCallOutgoingProgress :counters->number_of_LinphoneTransfertCallOutgoingProgress++;break; @@ -83,19 +83,21 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, static void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + stats* counters; LinphoneCore* lc=(LinphoneCore*)user_data; ms_message("call from [%s] to [%s] receive iFrame",from,to); ms_free(to); ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_IframeDecoded++; } static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; - linphone_core_get_default_proxy(callee_mgr->lc,&proxy); int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; + LinphoneAddress* identity; + linphone_core_get_default_proxy(callee_mgr->lc,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); @@ -126,7 +128,7 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m linphone_core_get_default_proxy(caller_mgr->lc,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); linphone_address_destroy(identity); @@ -148,7 +150,8 @@ static void simple_call() { LinphoneCore* lc_pauline=pauline->lc; stats* stat_marie=&marie->stat; stats* stat_pauline=&pauline->stat; - + LinphoneProxyConfig* proxy; + LinphoneAddress* identity; linphone_core_invite(lc_marie,"pauline"); @@ -158,10 +161,9 @@ static void simple_call() { CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); - LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(lc_marie,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); linphone_address_destroy(identity); @@ -218,11 +220,11 @@ static void call_ringing_canceled() { static void call_early_declined() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); - + LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); - LinphoneCall* in_call=linphone_core_get_current_call(marie->lc); + in_call=linphone_core_get_current_call(marie->lc); linphone_call_ref(in_call); linphone_core_terminate_call(marie->lc,in_call); @@ -318,9 +320,9 @@ static void call_with_video_added() { LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCall* call_obj; LinphoneVideoPolicy pauline_policy; + LinphoneCallParams* marie_params; pauline_policy.automatically_accept=TRUE; pauline_policy.automatically_initiate=TRUE; - LinphoneCallParams* marie_params; CU_ASSERT_TRUE(call(pauline,marie)); @@ -363,14 +365,14 @@ static void simple_conference() { LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); - MSList* lcs=ms_list_append(NULL,marie->lc); - lcs=ms_list_append(lcs,pauline->lc); - lcs=ms_list_append(lcs,laure->lc); - LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; LinphoneCall* marie_call_laure; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + CU_ASSERT_TRUE(call(marie,pauline)); marie_call_pauline=linphone_core_get_current_call(marie->lc); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); @@ -457,14 +459,14 @@ static void simple_call_transfer() { LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + LinphoneCall* marie_call_pauline; + 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); - LinphoneCall* marie_call_pauline; - LinphoneCall* pauline_called_by_marie; - CU_ASSERT_TRUE(call(marie,pauline)); marie_call_pauline=linphone_core_get_current_call(marie->lc); @@ -509,15 +511,16 @@ static void call_transfer_existing_call_outgoing_call() { LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); - MSList* lcs=ms_list_append(NULL,marie->lc); - const MSList* calls; - lcs=ms_list_append(lcs,pauline->lc); - lcs=ms_list_append(lcs,laure->lc); - LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; LinphoneCall* marie_call_laure; LinphoneCall* laure_called_by_marie; + LinphoneCall* lcall; + + MSList* lcs=ms_list_append(NULL,marie->lc); + const MSList* calls; + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); /*marie call pauline*/ CU_ASSERT_TRUE(call(marie,pauline)); @@ -553,10 +556,10 @@ static void call_transfer_existing_call_outgoing_call() { /*laure accept call*/ for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { - LinphoneCall* call = (LinphoneCall*)calls->data; - if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) { - CU_ASSERT_EQUAL(linphone_call_get_replaced_call(call),laure_called_by_marie); - linphone_core_accept_call(laure->lc,call); + lcall = (LinphoneCall*)calls->data; + if (linphone_call_get_state(lcall) == LinphoneCallIncomingReceived) { + CU_ASSERT_EQUAL(linphone_call_get_replaced_call(lcall),laure_called_by_marie); + linphone_core_accept_call(laure->lc,lcall); break; } } @@ -606,9 +609,11 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { return CU_get_error(); } +#ifdef VIDEO_ENABLED if (NULL == CU_add_test(pSuite, "call_with_video_added", call_with_video_added)) { return CU_get_error(); } +#endif if (NULL == CU_add_test(pSuite, "simple_conference", simple_conference)) { return CU_get_error(); } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index ebbafc7d1..6effc6390 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -35,8 +35,9 @@ static int uninit(void) { } static void core_init_test(void) { LinphoneCoreVTable v_table; + LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); - LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(lc); linphone_core_destroy(lc); } @@ -63,12 +64,14 @@ static stats global_stat; void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + stats* counters; + LinphoneAuthInfo *info; ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_auth_info_requested++; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } @@ -93,9 +96,10 @@ void reset_counters( stats* counters) { LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count) { LinphoneCore* lc; int retry=0; - lc = linphone_core_new(v_table,NULL,file,NULL); + stats* counters; + lc = linphone_core_new(v_table,NULL,file,NULL); linphone_core_set_user_data(lc,&global_stat); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); linphone_core_set_ring(lc,"./share/rings/oldphone.wav"); linphone_core_set_ringback(lc,"./share/ringback.wav"); @@ -114,9 +118,9 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { MSList* lcs=NULL; + bool_t result; if (lc_1) lcs=ms_list_append(lcs,lc_1); - bool_t result; if (lc_2) lcs=ms_list_append(lcs,lc_2); result=wait_for_list(lcs,counter,value,2000); @@ -138,10 +142,10 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { static void enable_codec(LinphoneCore* lc,const char* type,int rate) { MSList* codecs=ms_list_copy(linphone_core_get_audio_codecs(lc)); MSList* codecs_it; + PayloadType* pt; for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) { linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); } - PayloadType* pt; if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { linphone_core_enable_payload_type(lc,pt, 1); } diff --git a/tester/message_tester.c b/tester/message_tester.c index 424a12b32..ce3423d78 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -27,11 +27,12 @@ void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const Linph } void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message) { char* from=linphone_address_as_string(linphone_chat_message_get_from(message)); + stats* counters; ms_message("Message from [%s] is [%s] , external URL [%s]",from ,linphone_chat_message_get_text(message) ,linphone_chat_message_get_external_body_url(message)); ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_LinphoneMessageReceived++; if (linphone_chat_message_get_external_body_url(message)) counters->number_of_LinphoneMessageExtBodyReceived++; diff --git a/tester/presence_tester.c b/tester/presence_tester.c index eb4bb1b95..95f1e72ad 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -24,18 +24,20 @@ void new_subscribtion_request(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); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NewSubscriptionRequest++; linphone_core_add_friend(lc,lf); /*accept subscription*/ } void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { + stats* counters; char* from=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("New Notify request from [%s] ",from); ms_free(from); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NotifyReceived++; } @@ -55,8 +57,9 @@ static void simple_subscribe() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); + LinphoneFriend* friend; CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); - LinphoneFriend* friend = (LinphoneFriend*) marie_friends->data; + friend = (LinphoneFriend*) marie_friends->data; linphone_friend_edit(friend); linphone_friend_enable_subscribes(friend,TRUE); linphone_friend_done(friend); diff --git a/tester/register_tester.c b/tester/register_tester.c index a6b4b920a..cdc41df10 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -29,11 +29,12 @@ static LinphoneCore* create_lc() { 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)); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); switch (cstate) { case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; @@ -49,19 +50,24 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const int retry=0; LCSipTransports transport = {5070,5070,0,5071}; char* addr; + LinphoneProxyConfig* proxy_cfg; + stats* counters; + LinphoneAddress *from; + const char* server_addr; + LinphoneAuthInfo *info; + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); reset_counters(counters); linphone_core_set_sip_transports(lc,&transport); - LinphoneProxyConfig* proxy_cfg; proxy_cfg = linphone_proxy_config_new(); - LinphoneAddress *from = create_linphone_address(domain); + from = create_linphone_address(domain); linphone_proxy_config_set_identity(proxy_cfg,addr=linphone_address_as_string(from)); ms_free(addr); - const char* server_addr = linphone_address_get_domain(from); + server_addr = linphone_address_get_domain(from); linphone_proxy_config_enable_register(proxy_cfg,TRUE); linphone_proxy_config_expires(proxy_cfg,1); @@ -79,7 +85,7 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { linphone_core_iterate(lc); if (counters->number_of_auth_info_requested>0 && late_auth_info) { - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } ms_usleep(100000); @@ -149,22 +155,25 @@ static void simple_auth_register_with_refresh() { static void simple_tcp_register(){ char route[256]; + LinphoneCore* lc; sprintf(route,"sip:%s;transport=tcp",test_domain); - LinphoneCore* lc = create_lc(); + lc = create_lc(); register_with_refresh(lc,FALSE,NULL,route); } static void simple_tls_register(){ char route[256]; + LinphoneCore* lc; sprintf(route,"sip:%s;transport=tls",test_domain); - LinphoneCore* lc = create_lc(); + lc = create_lc(); register_with_refresh(lc,FALSE,NULL,route); } static void simple_authenticated_register(){ + stats* counters; LinphoneCore* lc = create_lc(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } @@ -173,21 +182,23 @@ static void authenticated_register_with_no_initial_credentials(){ LinphoneCoreVTable v_table; LinphoneCore* lc; stats stat; + stats* counters; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; v_table.auth_info_requested=auth_info_requested; - lc = linphone_core_new(&v_table,NULL,NULL,NULL); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters= (stats*)linphone_core_get_user_data(lc); counters->number_of_auth_info_requested=0; register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); } static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username) { + stats* counters; ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_auth_info_requested++; } @@ -195,12 +206,13 @@ static void authenticated_register_with_late_credentials(){ LinphoneCoreVTable v_table; LinphoneCore* lc; stats stat; + stats* counters; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; v_table.auth_info_requested=auth_info_requested2; lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh_base_2(lc,FALSE,auth_domain,NULL,TRUE); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_destroy(lc); From d4a36148d08715914539fc60639161785e5e31da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 1 Mar 2013 10:40:11 +0100 Subject: [PATCH 070/909] Reorganize liblinphone tests. --- tester/Makefile.am | 2 +- tester/call_tester.c | 119 ++++++++------------ tester/liblinphone_tester.c | 217 ++++++++++++++++++++++++------------ tester/liblinphone_tester.h | 52 ++++++++- tester/message_tester.c | 43 +++---- tester/presence_tester.c | 40 +++---- tester/register_tester.c | 75 +++++-------- tester/setup_tester.c | 52 +++++++++ 8 files changed, 370 insertions(+), 230 deletions(-) create mode 100644 tester/setup_tester.c diff --git a/tester/Makefile.am b/tester/Makefile.am index e1d2c692f..801d20ca0 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -4,7 +4,7 @@ if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester TESTS=$(noinst_PROGRAMS) -liblinphone_tester_SOURCES= liblinphone_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c +liblinphone_tester_SOURCES= liblinphone_tester.c setup_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/call_tester.c b/tester/call_tester.c index 8ffbdb7bf..44383a4c9 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -22,13 +23,6 @@ #include "liblinphone_tester.h" -static int init(void) { - return 0; -} -static int uninit(void) { - return 0; -} - 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); @@ -60,6 +54,7 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState CU_FAIL("unexpected event");break; } } + void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); @@ -80,6 +75,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, CU_FAIL("unexpected event");break; } } + static void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); @@ -90,6 +86,7 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_IframeDecoded++; } + static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); @@ -140,7 +137,8 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1); } -static void simple_call() { + +static void simple_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -180,7 +178,8 @@ static void simple_call() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void call_canceled() { + +static void cancelled_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -198,7 +197,7 @@ static void call_canceled() { linphone_core_manager_destroy(pauline); } -static void call_with_dns_time_out() { +static void call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new(NULL); LCSipTransports transport = {9773,0,0,0}; linphone_core_set_sip_transports(marie->lc,&transport); @@ -213,7 +212,7 @@ static void call_with_dns_time_out() { linphone_core_manager_destroy(marie); } -static void call_ringing_canceled() { +static void cancelled_ringing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -231,7 +230,7 @@ static void call_ringing_canceled() { linphone_core_manager_destroy(pauline); } -static void call_early_declined() { +static void early_declined_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -252,7 +251,7 @@ static void call_early_declined() { linphone_core_manager_destroy(pauline); } -static void call_terminated_by_caller() { +static void call_terminated_by_caller(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -266,7 +265,7 @@ static void call_terminated_by_caller() { linphone_core_manager_destroy(pauline); } -static void call_paused_resumed() { +static void call_paused_resumed(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCall* call_obj; @@ -303,7 +302,8 @@ static bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,Linph CU_ASSERT_EQUAL(linphone_call_get_state(call_2),LinphoneCallPausedByRemote); return linphone_call_get_state(call_1) == LinphoneCallPaused && linphone_call_get_state(call_2)==LinphoneCallPausedByRemote; } -static void call_paused_resumed_from_callee() { + +static void call_paused_resumed_from_callee(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCall* call_obj; @@ -329,7 +329,7 @@ static void call_paused_resumed_from_callee() { linphone_core_manager_destroy(pauline); } -static void call_with_video_added() { +static void call_with_video_added(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCall* call_obj; @@ -371,7 +371,8 @@ static void call_with_video_added() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void simple_conference() { + +static void simple_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); stats initial_marie_stat; stats initial_pauline_stat; @@ -428,8 +429,7 @@ static void simple_conference() { ms_list_free(lcs); } - -static void call_srtp() { +static void srtp_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -450,7 +450,7 @@ static void call_srtp() { linphone_core_manager_destroy(pauline); } -static void call_early_media() { +static void early_media_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_early_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -468,22 +468,19 @@ static void call_early_media() { linphone_core_manager_destroy(pauline); } -static void simple_call_transfer() { +static void simple_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/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); - LinphoneCall* marie_call_pauline; - LinphoneCall* pauline_called_by_marie; - CU_ASSERT_TRUE(call(marie,pauline)); - marie_call_pauline=linphone_core_get_current_call(marie->lc); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); reset_counters(&marie->stat); @@ -520,7 +517,7 @@ static void simple_call_transfer() { ms_list_free(lcs); } -static void call_transfer_existing_call_outgoing_call() { +static void call_transfer_existing_call_outgoing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); @@ -593,51 +590,29 @@ static void call_transfer_existing_call_outgoing_call() { ms_list_free(lcs); } -int call_test_suite () { - CU_pSuite pSuite = CU_add_suite("Call", init, uninit); - if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_with_dns_time_out", call_with_dns_time_out)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_early_media", call_early_media)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_paused_resumed_from_callee", call_paused_resumed_from_callee)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_with_video_added", call_with_video_added)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_conference", simple_conference)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_call_transfer", simple_call_transfer)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "call_transfer_existing_call_outgoing_call", call_transfer_existing_call_outgoing_call)) { - return CU_get_error(); - } +test_t call_tests[] = { + { "Early declined call", early_declined_call }, + { "Cancelled call", cancelled_call }, + { "Call with DNS timeout", call_with_dns_time_out }, + { "Cancelled ringing call", cancelled_ringing_call }, + { "Simple call", simple_call }, + { "Early-media call", early_media_call }, + { "Call terminated by caller", call_terminated_by_caller }, + { "Call paused resumed", call_paused_resumed }, + { "Call paused resumed from callee", call_paused_resumed_from_callee }, + { "SRTP call", srtp_call }, + { "Call with video added", call_with_video_added }, + { "Simple conference", simple_conference }, + { "Simple call transfer", simple_call_transfer }, + { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } +}; + +test_suite_t call_test_suite = { + "Call", + NULL, + NULL, + sizeof(call_tests) / sizeof(call_tests[0]), + call_tests +}; - return 0; -} diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 4c8861a13..26c6fbacd 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -22,24 +22,21 @@ #include "liblinphone_tester.h" +static test_suite_t **test_suite = NULL; +static int nb_test_suites = 0; + + +#if HAVE_CU_CURSES +static unsigned char curses = 0; +#endif + + +static stats global_stat; 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"; -static int init(void) { - return 0; -} -static int uninit(void) { - return 0; -} -static void core_init_test(void) { - LinphoneCoreVTable v_table; - memset (&v_table,0,sizeof(v_table)); - LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(lc); - linphone_core_destroy(lc); -} LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); @@ -54,13 +51,6 @@ LinphoneAddress * create_linphone_address(const char * domain) { CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); return addr; } -static void linphone_address_test(void) { - linphone_address_destroy(create_linphone_address(NULL)); -} - - -static stats global_stat; - void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { ms_message("Auth info requested for user id [%s] at realm [%s]\n" @@ -110,8 +100,6 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in return lc; } - - bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { MSList* lcs=NULL; if (lc_1) @@ -123,6 +111,7 @@ bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { ms_list_free(lcs); return result; } + bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; MSList* iterator; @@ -135,6 +124,7 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { if(*counterlc); if (mgr->identity) linphone_address_destroy(mgr->identity); @@ -176,44 +166,152 @@ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { } - -int init_test_suite () { - -CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); - - - if (NULL == CU_add_test(pSuite, "linphone address tester", linphone_address_test)) { - return CU_get_error(); +static void add_test_suite(test_suite_t *suite) { + if (test_suite == NULL) { + test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); } - if (NULL == CU_add_test(pSuite, "linphone core init/uninit tester", core_init_test)) { - return CU_get_error(); + 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 *)); } +} - register_test_suite(); +static int run_test_suite(test_suite_t *suite) { + int i; - call_test_suite(); + CU_pSuite pSuite = CU_add_suite(suite->name, suite->init_func, suite->cleanup_func); - message_test_suite(); - - presence_test_suite(); + 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; } -int main (int argc, char *argv[]) { + +static int test_suite_index(const char *suite_name) { int i; - char *test_name=NULL; + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + if ((strcmp(suite_name, test_suite[i]->name) == 0) && (strlen(suite_name) == strlen(test_suite[i]->name))) { + return i; + } + } + + return -1; +} + +int liblinphone_tester_nb_test_suites(void) { + return nb_test_suites; +} + +int liblinphone_tester_nb_tests(const char *suite_name) { + int i = test_suite_index(suite_name); + if (i < 0) return 0; + return test_suite[i]->nb_tests; +} + +const char * liblinphone_tester_test_suite_name(int suite_index) { + if (suite_index >= liblinphone_tester_nb_test_suites()) return NULL; + return test_suite[suite_index]->name; +} + +const char * liblinphone_tester_test_name(const char *suite_name, int test_index) { + int suite_index = test_suite_index(suite_name); + if ((suite_index < 0) || (suite_index >= liblinphone_tester_nb_test_suites())) return NULL; + if (test_index >= test_suite[suite_index]->nb_tests) return NULL; + return test_suite[suite_index]->tests[test_index].name; +} + +void liblinphone_tester_init(void) { + add_test_suite(&setup_test_suite); + add_test_suite(®ister_test_suite); + add_test_suite(&call_test_suite); + add_test_suite(&message_test_suite); + add_test_suite(&presence_test_suite); +} + +void liblinphone_tester_uninit(void) { + if (test_suite != NULL) { + free(test_suite); + test_suite = NULL; + nb_test_suites = 0; + } +} + +int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { + int i; + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + run_test_suite(test_suite[i]); + } + +#if HAVE_CU_GET_SUITE + if (suite_name){ + CU_pSuite suite; + CU_basic_set_mode(CU_BRM_VERBOSE); + suite=CU_get_suite(suite_name); + if (test_name) { + CU_pTest test=CU_get_test_by_name(test_name, suite); + CU_basic_run_test(suite, test); + } else + CU_basic_run_suite(suite); + } else +#endif + { +#if HAVE_CU_CURSES + if (curses) { + /* Run tests using the CUnit curses interface */ + CU_curses_run_tests(); + } + else +#endif + { + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + } + } + + CU_cleanup_registry(); + return CU_get_error(); +} + + +#ifndef WINAPI_FAMILY_PHONE_APP +int main (int argc, char *argv[]) { + int i; + int ret; char *suite_name=NULL; + char *test_name=NULL; + for(i=1;i\n" + "\t\t\t---auth-domain \n" +#if HAVE_CU_GET_SUITE + "\t\t\t--suite \n" + "\t\t\t--test \n" +#endif +#if HAVE_CU_CURSES + "\t\t\t--curses\n" +#endif + , argv[0]); + return 0; }else if (strcmp(argv[i],"--verbose")==0){ - linphone_core_enable_logs(NULL); + linphone_core_enable_logs(NULL); }else if (strcmp(argv[i],"--domain")==0){ i++; test_domain=argv[i]; - } else if (strcmp(argv[i],"--auth-domain")==0){ + }else if (strcmp(argv[i],"--auth-domain")==0){ i++; auth_domain=argv[i]; }else if (strcmp(argv[i],"--test")==0){ @@ -225,29 +323,10 @@ int main (int argc, char *argv[]) { } } - /* initialize the CUnit test registry */ - if (CUE_SUCCESS != CU_initialize_registry()) - return CU_get_error(); - - init_test_suite(); - /* Run all tests using the CUnit Basic interface */ - CU_basic_set_mode(CU_BRM_VERBOSE); -if (suite_name){ -#if 1 /*HAVE_CU_GET_SUITE*/ - CU_pSuite suite; - suite=CU_get_suite(suite_name); - if (test_name) { - CU_pTest test=CU_get_test_by_name(test_name, suite); - CU_basic_run_test(suite, test); - } else - CU_basic_run_suite(suite); -#else - fprintf(stderr,"Your CUnit version does not support suite selection.\n"); -#endif - } else - CU_basic_run_tests(); - - CU_cleanup_registry(); - return CU_get_error(); - + liblinphone_tester_init(); + ret = liblinphone_tester_run_tests(suite_name, test_name); + liblinphone_tester_uninit(); + return ret; } +#endif + diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 46263bf46..1d17dbffc 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -21,6 +21,51 @@ +#include "CUnit/Basic.h" + + +typedef void (*test_function_t)(void); +typedef int (*test_suite_function_t)(const char *name); + +typedef struct { + const char *name; + test_function_t func; +} test_t; + +typedef struct { + const char *name; + CU_InitializeFunc init_func; + CU_CleanupFunc cleanup_func; + int nb_tests; + test_t *tests; +} test_suite_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern 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 int liblinphone_tester_nb_test_suites(void); +extern int liblinphone_tester_nb_tests(const char *suite_name); +extern const char * liblinphone_tester_test_suite_name(int suite_index); +extern const char * liblinphone_tester_test_name(const char *suite_name, int test_index); +extern void liblinphone_tester_init(void); +extern void liblinphone_tester_uninit(void); +extern int liblinphone_tester_run_tests(const char *suite_name, const char *test_name); + + +#ifdef __cplusplus +}; +#endif + + const char* test_domain; const char* auth_domain; const char* test_username; @@ -77,6 +122,7 @@ typedef struct _stats { int number_of_IframeDecoded; }stats; + typedef struct _LinphoneCoreManager { LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -104,9 +150,7 @@ LinphoneAddress * create_linphone_address(const char * domain); LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count); 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); -int call_test_suite (); -int register_test_suite (); -int message_test_suite (); -int presence_test_suite (); + #endif /* LIBLINPHONE_TESTER_H_ */ + diff --git a/tester/message_tester.c b/tester/message_tester.c index 424a12b32..5050a84a8 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -15,16 +15,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" + void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { stats* counters = (stats*)linphone_core_get_user_data(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)); ms_message("Message from [%s] is [%s] , external URL [%s]",from @@ -57,7 +60,7 @@ void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMes } -static void text_message() { +static void text_message(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); char* to = linphone_address_as_string(marie->identity); @@ -69,7 +72,7 @@ static void text_message() { linphone_core_manager_destroy(pauline); } -static void text_message_with_ack() { +static void text_message_with_ack(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); char* to = linphone_address_as_string(marie->identity); @@ -82,7 +85,8 @@ static void text_message_with_ack() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void text_message_with_external_body() { + +static void text_message_with_external_body(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); char* to = linphone_address_as_string(marie->identity); @@ -99,7 +103,7 @@ static void text_message_with_external_body() { linphone_core_manager_destroy(pauline); } -static void text_message_with_send_error() { +static void text_message_with_send_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); char* to = linphone_address_as_string(pauline->identity); @@ -118,20 +122,19 @@ static void text_message_with_send_error() { linphone_core_manager_destroy(pauline); } -int message_test_suite () { - CU_pSuite pSuite = CU_add_suite("Message", NULL, NULL); - if (NULL == CU_add_test(pSuite, "text_message", text_message)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "text_message_with_ack", text_message_with_ack)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "text_message_with_send_error", text_message_with_send_error)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "text_message_with_external_body", text_message_with_external_body)) { - return CU_get_error(); - } - return 0; -} +test_t message_tests[] = { + { "Text message", text_message }, + { "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 } +}; + +test_suite_t message_test_suite = { + "Message", + NULL, + NULL, + sizeof(message_tests) / sizeof(message_tests[0]), + message_tests +}; + diff --git a/tester/presence_tester.c b/tester/presence_tester.c index eb4bb1b95..478f042c6 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -29,8 +30,8 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NewSubscriptionRequest++; linphone_core_add_friend(lc,lf); /*accept subscription*/ - } + void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { char* from=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("New Notify request from [%s] ",from); @@ -39,7 +40,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { counters->number_of_NotifyReceived++; } -static void simple_publish() { +static void simple_publish(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(marie->lc,&proxy); @@ -50,8 +51,7 @@ static void simple_publish() { linphone_core_manager_destroy(marie); } - -static void simple_subscribe() { +static void simple_subscribe(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); @@ -69,7 +69,8 @@ static void simple_subscribe() { linphone_core_manager_destroy(pauline); } -static void unsubscribe_while_subscribing() { + +static void unsubscribe_while_subscribing(void) { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ linphone_friend_edit(friend); @@ -78,19 +79,20 @@ static void unsubscribe_while_subscribing() { linphone_core_add_friend(marie->lc,friend); linphone_core_iterate(marie->lc); linphone_core_manager_destroy(marie); - } -int presence_test_suite () { - CU_pSuite pSuite = CU_add_suite("Presence", NULL, NULL); - if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "unsubscribe_while_subscribing", unsubscribe_while_subscribing)) { - return CU_get_error(); - } - return 0; -} + +test_t presence_tests[] = { + { "Simple Subscribe", simple_subscribe }, + { "Simple Publish", simple_publish }, + { "Unsubscribe while subscribing", unsubscribe_while_subscribing }, +}; + +test_suite_t presence_test_suite = { + "Presence", + NULL, + NULL, + sizeof(presence_tests) / sizeof(presence_tests[0]), + presence_tests +}; + diff --git a/tester/register_tester.c b/tester/register_tester.c index a6b4b920a..16ae53da3 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -27,7 +28,6 @@ static LinphoneCore* create_lc() { return create_lc_with_auth(0); } - void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ ms_message("New registration state %s for user id [%s] at proxy [%s]\n" ,linphone_registration_state_to_string(cstate) @@ -45,6 +45,7 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } } + static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route,bool_t late_auth_info) { int retry=0; LCSipTransports transport = {5070,5070,0,5071}; @@ -92,9 +93,11 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); } + static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { register_with_refresh_base_2(lc,refresh,domain,route,FALSE); } + static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { stats* counters = (stats*)linphone_core_get_user_data(lc); register_with_refresh_base(lc,refresh,domain,route); @@ -124,6 +127,7 @@ static void register_with_refresh_with_send_error(void) { CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); } + static void simple_register(){ LinphoneCore* lc = create_lc(); stats* counters = (stats*)linphone_core_get_user_data(lc); @@ -131,7 +135,6 @@ static void simple_register(){ CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } - /*take care of min expires configuration from server*/ static void simple_register_with_refresh() { LinphoneCore* lc = create_lc(); @@ -153,6 +156,7 @@ static void simple_tcp_register(){ LinphoneCore* lc = create_lc(); register_with_refresh(lc,FALSE,NULL,route); } + static void simple_tls_register(){ char route[256]; sprintf(route,"sip:%s;transport=tls",test_domain); @@ -183,6 +187,7 @@ static void authenticated_register_with_no_initial_credentials(){ register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); } + static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username) { ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username @@ -282,48 +287,28 @@ static void io_recv_error(){ linphone_core_destroy(lc); } -int register_test_suite () { - CU_pSuite pSuite = CU_add_suite("Register", NULL, NULL); - if (NULL == CU_add_test(pSuite, "simple_register", simple_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "tcp register tester", simple_tcp_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "tls register tester", simple_tls_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_authenticated_register", simple_authenticated_register)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "authenticated_register_with_late_credentials", authenticated_register_with_late_credentials)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_register_with_refresh", simple_register_with_refresh)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "simple_auth_register_with_refresh", simple_auth_register_with_refresh)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "register_with_refresh_with_send_error", register_with_refresh_with_send_error)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "transport_change", transport_change)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "network_state_change", network_state_change)) { - return CU_get_error(); - } - if (NULL == CU_add_test(pSuite, "io_recv_error_0", io_recv_error)) { - return CU_get_error(); - } +test_t register_tests[] = { + { "Simple register", simple_register }, + { "TCP register", simple_tcp_register }, + { "TLS register", simple_tls_register }, + { "Simple authenticated register", simple_authenticated_register }, + { "Digest auth without initial credentials", authenticated_register_with_no_initial_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 & send error", register_with_refresh_with_send_error }, + { "Multi account", multiple_proxy }, + { "Transport change", transport_change }, + { "Network state change", network_state_change }, + { "io_recv_error_0", io_recv_error } +}; + +test_suite_t register_test_suite = { + "Register", + NULL, + NULL, + sizeof(register_tests) / sizeof(register_tests[0]), + register_tests +}; - return 0; -} diff --git a/tester/setup_tester.c b/tester/setup_tester.c new file mode 100644 index 000000000..4ee2564c5 --- /dev/null +++ b/tester/setup_tester.c @@ -0,0 +1,52 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + + + +static void core_init_test(void) { + LinphoneCoreVTable v_table; + memset (&v_table,0,sizeof(v_table)); + LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_destroy(lc); +} + +static void linphone_address_test(void) { + linphone_address_destroy(create_linphone_address(NULL)); +} + + +test_t setup_tests[] = { + { "Linphone Address", linphone_address_test }, + { "Linphone core init/uninit", core_init_test }, +}; + +test_suite_t setup_test_suite = { + "Setup", + NULL, + NULL, + sizeof(setup_tests) / sizeof(setup_tests[0]), + setup_tests +}; + From 5baaa9fc434436571234d15de887f6eb3c6c6676 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Mar 2013 14:59:50 +0100 Subject: [PATCH 071/909] Fix merge + compil wp --- .../vsx/LibLinphoneTester/LibLinphoneTester.vcxproj | 6 ++++++ .../LibLinphoneTester.vcxproj.filters | 12 ++++++++++++ include/sal/sal.h | 2 +- tester/call_tester.c | 4 ++-- tester/liblinphone_tester.c | 13 ++++++++----- tester/setup_tester.c | 3 ++- 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj index 1685afd27..bf77462b5 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -134,6 +134,7 @@ +
@@ -152,6 +153,11 @@ {08dd0d38-d9b5-4626-b60d-b4d76b571142} + + + + + diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters index 5e3ead950..e7b5435bd 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters @@ -12,8 +12,20 @@ + + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/include/sal/sal.h b/include/sal/sal.h index 71edb3d1e..80a747fe3 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -526,6 +526,6 @@ LINPHONE_PUBLIC void sal_set_recv_error(Sal *sal,int value); void sal_nat_helper_enable(Sal *sal,bool_t enable); bool_t sal_nat_helper_enabled(Sal *sal); -void sal_set_dns_timeout(Sal* sal,int timeout); +LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); int sal_get_dns_timeout(const Sal* sal); #endif diff --git a/tester/call_tester.c b/tester/call_tester.c index 16ad764ed..b7ff3465c 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -475,9 +475,7 @@ static void simple_call_transfer(void) { LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); LinphoneCall* pauline_called_by_marie; - LinphoneCall* marie_call_pauline; - LinphoneCall* pauline_called_by_marie; char* laure_identity=linphone_address_as_string(laure->identity); MSList* lcs=ms_list_append(NULL,marie->lc); @@ -610,7 +608,9 @@ test_t call_tests[] = { { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, { "SRTP call", srtp_call }, +#ifdef VIDEO_ENABLED { "Call with video added", call_with_video_added }, +#endif { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 26c6fbacd..e92037e17 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -53,12 +53,14 @@ LinphoneAddress * create_linphone_address(const char * domain) { } void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + stats* counters; + LinphoneAuthInfo *info; ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_auth_info_requested++; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } @@ -83,9 +85,10 @@ void reset_counters( stats* counters) { LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count) { LinphoneCore* lc; int retry=0; + stats* counters; lc = linphone_core_new(v_table,NULL,file,NULL); linphone_core_set_user_data(lc,&global_stat); - stats* counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)linphone_core_get_user_data(lc); linphone_core_set_ring(lc,"./share/rings/oldphone.wav"); linphone_core_set_ringback(lc,"./share/ringback.wav"); @@ -102,9 +105,9 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { MSList* lcs=NULL; + bool_t result; if (lc_1) lcs=ms_list_append(lcs,lc_1); - bool_t result; if (lc_2) lcs=ms_list_append(lcs,lc_2); result=wait_for_list(lcs,counter,value,2000); @@ -128,10 +131,10 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { static void enable_codec(LinphoneCore* lc,const char* type,int rate) { MSList* codecs=ms_list_copy(linphone_core_get_audio_codecs(lc)); MSList* codecs_it; + PayloadType* pt; for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) { linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); } - PayloadType* pt; if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { linphone_core_enable_payload_type(lc,pt, 1); } diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 4ee2564c5..4fee989e9 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -26,8 +26,9 @@ static void core_init_test(void) { LinphoneCoreVTable v_table; + LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); - LinphoneCore* lc = linphone_core_new(&v_table,NULL,NULL,NULL); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(lc); linphone_core_destroy(lc); } From bf73a512ab179b9c239cfb94ff45067f5a02546e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Mar 2013 16:45:31 +0100 Subject: [PATCH 072/909] Added wp8 test app --- build/vsx/LibLinphone/LibLinphone.vcxproj | 5 +- .../LibLinphoneTester-wp8.sln | 261 ++++++++++++++++++ .../LibLinphoneTester-wp8.v11.suo | Bin 0 -> 110592 bytes .../LibLinphoneTester-wp8/App.xaml | 20 ++ .../LibLinphoneTester-wp8/App.xaml.cs | 234 ++++++++++++++++ .../Assets/AlignmentGrid.png | Bin 0 -> 9042 bytes .../Assets/ApplicationIcon.png | Bin 0 -> 3392 bytes .../Assets/Tiles/FlipCycleTileLarge.png | Bin 0 -> 9930 bytes .../Assets/Tiles/FlipCycleTileMedium.png | Bin 0 -> 9070 bytes .../Assets/Tiles/FlipCycleTileSmall.png | Bin 0 -> 3674 bytes .../Assets/Tiles/IconicTileMediumLarge.png | Bin 0 -> 4937 bytes .../Assets/Tiles/IconicTileSmall.png | Bin 0 -> 3724 bytes .../LibLinphoneTester-wp8.csproj | 183 ++++++++++++ .../LibLinphoneTester-wp8.csproj.user | 22 ++ .../LibLinphoneTester-wp8/LocalizedStrings.cs | 14 + .../LibLinphoneTester-wp8/MainPage.xaml | 42 +++ .../LibLinphoneTester-wp8/MainPage.xaml.cs | 58 ++++ .../Properties/AppManifest.xml | 6 + .../Properties/AssemblyInfo.cs | 37 +++ .../Properties/WMAppManifest.xml | 48 ++++ .../Resources/AppResources.Designer.cs | 127 +++++++++ .../Resources/AppResources.resx | 137 +++++++++ .../LibLinphoneTester-wp8/TestCasePage.xaml | 40 +++ .../TestCasePage.xaml.cs | 63 +++++ .../LibLinphoneTester-wp8/TestResultPage.xaml | 41 +++ .../TestResultPage.xaml.cs | 98 +++++++ .../LibLinphoneTester.vcxproj | 38 ++- .../LibLinphoneTester.vcxproj.filters | 2 + .../linphone-tester-native.cpp | 101 +++++++ .../linphone-tester-native.h | 25 ++ tester/liblinphone_tester.h | 2 +- 31 files changed, 1582 insertions(+), 22 deletions(-) create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs create mode 100644 build/vsx/LibLinphoneTester/linphone-tester-native.cpp create mode 100644 build/vsx/LibLinphoneTester/linphone-tester-native.h diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 57a94e932..8eea9170a 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -131,9 +131,12 @@ false false true - belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) + ws2_32.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) $(TargetDir)$(TargetName)_dll.lib + ole32.lib;%(IgnoreSpecificDefaultLibraries) + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln new file mode 100644 index 000000000..cc2bd5fa0 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -0,0 +1,261 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "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\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester", "..\LibLinphoneTester\LibLinphoneTester.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}" + ProjectSection(ProjectDependencies) = postProject + {902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4} + {08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\windows\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\..\oRTP\build\vsx\oRTP\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\vsx\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\windows\gsm\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\windows\speex\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\windows\speex\speexdsp\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\windows\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {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|Mixed Platforms.ActiveCfg = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Deploy.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.ActiveCfg = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Build.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Deploy.0 = Debug|x86 + {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|Any CPU.ActiveCfg = Release|Any CPU + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Build.0 = Release|Any CPU + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Deploy.0 = Release|Any CPU + {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|Mixed Platforms.ActiveCfg = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Build.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Deploy.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.ActiveCfg = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Build.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Deploy.0 = Release|x86 + {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|Any CPU.ActiveCfg = Debug|Win32 + {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|Mixed Platforms.ActiveCfg = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.ActiveCfg = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Mixed Platforms.Build.0 = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.ActiveCfg = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.ActiveCfg = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.ActiveCfg = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Mixed Platforms.Build.0 = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Mixed Platforms.Build.0 = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Mixed Platforms.Build.0 = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.ActiveCfg = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Mixed Platforms.Build.0 = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.ActiveCfg = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Mixed Platforms.Build.0 = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.ActiveCfg = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Mixed Platforms.Build.0 = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Mixed Platforms.Build.0 = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Mixed Platforms.Build.0 = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.Build.0 = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo new file mode 100644 index 0000000000000000000000000000000000000000..d48a9cb52df2d7aa2f35175669445320e3890c27 GIT binary patch literal 110592 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 literal 0 HcmV?d00001 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml new file mode 100644 index 000000000..ad710fdad --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs new file mode 100644 index 000000000..5052b5a01 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs @@ -0,0 +1,234 @@ +using System; +using System.Diagnostics; +using System.Resources; +using System.Windows; +using System.Windows.Markup; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; +using LibLinphoneTester_wp8.Resources; +using linphone_tester_native; + +namespace LibLinphoneTester_wp8 +{ + public partial class App : Application + { + /// + /// Provides easy access to the root frame of the Phone Application. + /// + /// The root frame of the Phone Application. + public static PhoneApplicationFrame RootFrame { get; private set; } + + /// + /// Constructor for the Application object. + /// + public App() + { + // Global handler for uncaught exceptions. + UnhandledException += Application_UnhandledException; + + // Standard XAML initialization + InitializeComponent(); + + // Phone-specific initialization + InitializePhoneApplication(); + + // Language display initialization + InitializeLanguage(); + + // Show graphics profiling information while debugging. + if (Debugger.IsAttached) + { + // Display the current frame rate counters. + Application.Current.Host.Settings.EnableFrameRateCounter = true; + + // Show the areas of the app that are being redrawn in each frame. + //Application.Current.Host.Settings.EnableRedrawRegions = true; + + // Enable non-production analysis visualization mode, + // which shows areas of a page that are handed off to GPU with a colored overlay. + //Application.Current.Host.Settings.EnableCacheVisualization = true; + + // Prevent the screen from turning off while under the debugger by disabling + // the application's idle detection. + // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run + // and consume battery power when the user is not using the phone. + PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; + } + + tester = new LinphoneTesterNative(); + suite = null; + } + + // Code to execute when the application is launching (eg, from Start) + // This code will not execute when the application is reactivated + private void Application_Launching(object sender, LaunchingEventArgs e) + { + } + + // Code to execute when the application is activated (brought to foreground) + // This code will not execute when the application is first launched + private void Application_Activated(object sender, ActivatedEventArgs e) + { + } + + // Code to execute when the application is deactivated (sent to background) + // This code will not execute when the application is closing + private void Application_Deactivated(object sender, DeactivatedEventArgs e) + { + } + + // Code to execute when the application is closing (eg, user hit Back) + // This code will not execute when the application is deactivated + private void Application_Closing(object sender, ClosingEventArgs e) + { + } + + // Code to execute if a navigation fails + private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) + { + if (Debugger.IsAttached) + { + // A navigation has failed; break into the debugger + Debugger.Break(); + } + } + + // Code to execute on Unhandled Exceptions + private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + if (Debugger.IsAttached) + { + // An unhandled exception has occurred; break into the debugger + Debugger.Break(); + } + } + + #region Phone application initialization + + // Avoid double-initialization + private bool phoneApplicationInitialized = false; + + // Do not add any additional code to this method + private void InitializePhoneApplication() + { + if (phoneApplicationInitialized) + return; + + // Create the frame but don't set it as RootVisual yet; this allows the splash + // screen to remain active until the application is ready to render. + RootFrame = new PhoneApplicationFrame(); + RootFrame.Navigated += CompleteInitializePhoneApplication; + + // Handle navigation failures + RootFrame.NavigationFailed += RootFrame_NavigationFailed; + + // Handle reset requests for clearing the backstack + RootFrame.Navigated += CheckForResetNavigation; + + // Ensure we don't initialize again + phoneApplicationInitialized = true; + } + + // Do not add any additional code to this method + private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) + { + // Set the root visual to allow the application to render + if (RootVisual != RootFrame) + RootVisual = RootFrame; + + // Remove this handler since it is no longer needed + RootFrame.Navigated -= CompleteInitializePhoneApplication; + } + + private void CheckForResetNavigation(object sender, NavigationEventArgs e) + { + // If the app has received a 'reset' navigation, then we need to check + // on the next navigation to see if the page stack should be reset + if (e.NavigationMode == NavigationMode.Reset) + RootFrame.Navigated += ClearBackStackAfterReset; + } + + private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) + { + // Unregister the event so it doesn't get called again + RootFrame.Navigated -= ClearBackStackAfterReset; + + // Only clear the stack for 'new' (forward) and 'refresh' navigations + if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) + return; + + // For UI consistency, clear the entire page stack + while (RootFrame.RemoveBackEntry() != null) + { + ; // do nothing + } + } + + #endregion + + // Initialize the app's font and flow direction as defined in its localized resource strings. + // + // To ensure that the font of your application is aligned with its supported languages and that the + // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage + // and ResourceFlowDirection should be initialized in each resx file to match these values with that + // file's culture. For example: + // + // AppResources.es-ES.resx + // ResourceLanguage's value should be "es-ES" + // ResourceFlowDirection's value should be "LeftToRight" + // + // AppResources.ar-SA.resx + // ResourceLanguage's value should be "ar-SA" + // ResourceFlowDirection's value should be "RightToLeft" + // + // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072. + // + private void InitializeLanguage() + { + try + { + // Set the font to match the display language defined by the + // ResourceLanguage resource string for each supported language. + // + // Fall back to the font of the neutral language if the Display + // language of the phone is not supported. + // + // If a compiler error is hit then ResourceLanguage is missing from + // the resource file. + RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage); + + // Set the FlowDirection of all elements under the root frame based + // on the ResourceFlowDirection resource string for each + // supported language. + // + // If a compiler error is hit then ResourceFlowDirection is missing from + // the resource file. + FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); + RootFrame.FlowDirection = flow; + } + catch + { + // If an exception is caught here it is most likely due to either + // ResourceLangauge not being correctly set to a supported language + // code or ResourceFlowDirection is set to a value other than LeftToRight + // or RightToLeft. + + if (Debugger.IsAttached) + { + Debugger.Break(); + } + + throw; + } + } + + public bool suiteRunning() + { + return (suite != null) && (suite.running); + } + + public LinphoneTesterNative tester { get; set; } + public UnitTestSuite suite { get; set; } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png new file mode 100644 index 0000000000000000000000000000000000000000..f7d2e97804e451530960b57429a2b0a26c86f5d7 GIT binary patch literal 9042 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 IP1{HR1(GMkF8}}l literal 0 HcmV?d00001 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png new file mode 100644 index 0000000000000000000000000000000000000000..e93b89d600641c9d5b05f94493a9fde6afa850e8 GIT binary patch literal 9070 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 literal 0 HcmV?d00001 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png new file mode 100644 index 0000000000000000000000000000000000000000..d4b5ede1b567fd4b90505217330edf7de0474432 GIT binary patch literal 3724 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 + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + LibLinphoneTester_wp8 + LibLinphoneTester_wp8 + WindowsPhone + v8.0 + $(TargetFrameworkVersion) + true + + + true + true + LibLinphoneTester_wp8_$(Configuration)_$(Platform).xap + Properties\AppManifest.xml + LibLinphoneTester_wp8.App + true + 11.0 + true + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + true + full + false + Bin\x86\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\x86\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + true + full + false + Bin\ARM\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\ARM\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + + App.xaml + + + + MainPage.xaml + + + + True + True + AppResources.resx + + + TestCasePage.xaml + + + TestResultPage.xaml + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + Designer + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + PublicResXFileCodeGenerator + AppResources.Designer.cs + + + + + + + + {5E94A00B-B14A-4E42-8284-8CB0EF099534} + LibLinphoneTester + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user new file mode 100644 index 000000000..96fe30de2 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user @@ -0,0 +1,22 @@ + + + + 256 + 30F105C9-681E-420b-A277-7C086EAD8A4E + + + 256 + 30F105C9-681E-420b-A277-7C086EAD8A4E + + + + + + False + Managed + False + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs new file mode 100644 index 000000000..e639982ad --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs @@ -0,0 +1,14 @@ +using LibLinphoneTester_wp8.Resources; + +namespace LibLinphoneTester_wp8 +{ + /// + /// Provides access to string resources. + /// + public class LocalizedStrings + { + private static AppResources _localizedResources = new AppResources(); + + public AppResources LocalizedResources { get { return _localizedResources; } } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml new file mode 100644 index 000000000..c912857f9 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs new file mode 100644 index 000000000..aa5307968 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; + +namespace LibLinphoneTester_wp8 +{ + public partial class MainPage : PhoneApplicationPage + { + public MainPage() + { + InitializeComponent(); + + var tester = (Application.Current as App).tester; + List source = new List(); + source.Add(new UnitTestSuiteName("ALL")); + for (int i = 0; i < tester.nbTestSuites(); i++) + { + source.Add(new UnitTestSuiteName(tester.testSuiteName(i))); + } + + Tests.ItemsSource = source; + } + + private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) + { + UnitTestSuiteName test = (sender as LongListSelector).SelectedItem as UnitTestSuiteName; + if (test == null) return; + if (test.Name == "ALL") + { + NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); + } + else + { + NavigationService.Navigate(new Uri("/TestCasePage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); + } + } + } + + public class UnitTestSuiteName + { + public string Name + { + get; + set; + } + + public UnitTestSuiteName(string name) + { + this.Name = name; + } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml new file mode 100644 index 000000000..a95523275 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0b87f1f9b --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Resources; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("LibLinphoneTester_wp8")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LibLinphoneTester_wp8")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f1aad7a9-2083-4726-ab28-f57b1dd5891e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("en-US")] diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml new file mode 100644 index 000000000..7ce78feb0 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml @@ -0,0 +1,48 @@ + + + + + Assets\ApplicationIcon.png + + + + + + + + + + + + + + Assets\Tiles\FlipCycleTileSmall.png + 0 + Assets\Tiles\FlipCycleTileMedium.png + LibLinphoneTester_wp8 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs new file mode 100644 index 000000000..991c3a23d --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.17626 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LibLinphoneTester_wp8.Resources +{ + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class AppResources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal AppResources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LibLinphoneTester_wp8.Resources.AppResources", typeof(AppResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to LeftToRight. + /// + public static string ResourceFlowDirection + { + get + { + return ResourceManager.GetString("ResourceFlowDirection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to us-EN. + /// + public static string ResourceLanguage + { + get + { + return ResourceManager.GetString("ResourceLanguage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MY APPLICATION. + /// + public static string ApplicationTitle + { + get + { + return ResourceManager.GetString("ApplicationTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to button. + /// + public static string AppBarButtonText + { + get + { + return ResourceManager.GetString("AppBarButtonText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to menu item. + /// + public static string AppBarMenuItemText + { + get + { + return ResourceManager.GetString("AppBarMenuItemText", resourceCulture); + } + } + } +} diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx new file mode 100644 index 000000000..78837dc46 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + LeftToRight + Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language + + + en-US + Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language. + + + MY APPLICATION + + + add + + + Menu Item + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml new file mode 100644 index 000000000..b6f2ea932 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs new file mode 100644 index 000000000..aae5f878b --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; + +namespace LibLinphoneTester_wp8 +{ + public partial class TestCasePage : PhoneApplicationPage + { + public TestCasePage() + { + InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + suiteName = NavigationContext.QueryString["SuiteName"]; + verbose = Convert.ToBoolean(NavigationContext.QueryString["Verbose"]); + var tester = (Application.Current as App).tester; + List source = new List(); + source.Add(new UnitTestCaseName("ALL")); + for (int i = 0; i < tester.nbTests(suiteName); i++) + { + source.Add(new UnitTestCaseName(tester.testName(suiteName, i))); + } + + Tests.ItemsSource = source; + } + + private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) + { + UnitTestCaseName test = (sender as LongListSelector).SelectedItem as UnitTestCaseName; + if (test == null) return; + if (!(Application.Current as App).suiteRunning()) + { + NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + suiteName + "&CaseName=" + test.Name + "&Verbose=" + verbose, UriKind.Relative)); + } + } + + private string suiteName; + private bool verbose; + } + + public class UnitTestCaseName + { + public string Name + { + get; + set; + } + + public UnitTestCaseName(string name) + { + this.Name = name; + } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml new file mode 100644 index 000000000..97afd9af6 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs new file mode 100644 index 000000000..2ad80deb3 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs @@ -0,0 +1,98 @@ +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(String msg); + + public partial class TestResultPage : PhoneApplicationPage + { + public TestResultPage() + { + InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(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(String msg) + { + this.Dispatcher.BeginInvoke(() => + { + TestResults.Text += msg; + }); + } + } + + 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(String msg) + { + if (OutputDisplay != null) + { + OutputDisplay(msg); + } + System.Diagnostics.Debug.WriteLine(msg); + } + + public bool running { + get { return Running; } + protected set { Running = value; } + } + + private string SuiteName; + private string CaseName; + private bool Verbose; + private bool Running; + private OutputDisplayDelegate OutputDisplay; + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj index bf77462b5..cd448cb77 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -20,28 +20,29 @@ {5e94a00b-b14a-4e42-8284-8cb0ef099534} - LibLinphoneTester + linphone_tester_native en-US 11.0 + true DynamicLibrary true - v110 + v110_wp80 false DynamicLibrary true v110_wp80 - false + true DynamicLibrary false true - v110 + v110_wp80 false @@ -84,24 +85,25 @@ Console false false - true + false + Level4 WIN32;_DEBUG;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + Default NotUsing - false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + false Console false - false - true - ws2_32.lib;%(AdditionalDependencies) ole32.lib;%(IgnoreSpecificDefaultLibraries) + true + WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration) @@ -116,13 +118,10 @@ Console false false - true + false - - true - true false @@ -135,9 +134,13 @@ + + true + + @@ -153,13 +156,8 @@ {08dd0d38-d9b5-4626-b60d-b4d76b571142} - - - - - - + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters index e7b5435bd..2f40f9303 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters @@ -13,9 +13,11 @@ + + diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp new file mode 100644 index 000000000..ef7c34af3 --- /dev/null +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp @@ -0,0 +1,101 @@ +#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(int 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(msg); + } +} + +static void LinphoneNativeOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +{ + char fmt2[MAX_TRACE_SIZE]; + snprintf(fmt2, MAX_TRACE_SIZE, "%s\n", fmt); + nativeOutputTraceHandler((int)lev, fmt2, 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) { + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + } else { + ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); + } + ortp_set_log_handler(LinphoneNativeOutputTraceHandler); + CU_set_trace_handler(nativeOutputTraceHandler); + + liblinphone_tester_run_tests(wssuitename == all ? 0 : csuitename, wscasename == all ? 0 : ccasename); +} + +unsigned int LinphoneTesterNative::nbTestSuites() +{ + return liblinphone_tester_nb_test_suites(); +} + +unsigned int LinphoneTesterNative::nbTests(Platform::String^ suiteName) +{ + std::wstring suitename = suiteName->Data(); + char cname[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(cname, suitename.c_str(), sizeof(cname)); + return liblinphone_tester_nb_tests(cname); +} + +Platform::String^ LinphoneTesterNative::testSuiteName(int index) +{ + const char *cname = liblinphone_tester_test_suite_name(index); + wchar_t wcname[MAX_SUITE_NAME_SIZE]; + mbstowcs(wcname, cname, sizeof(wcname)); + return ref new String(wcname); +} + +Platform::String^ LinphoneTesterNative::testName(Platform::String^ suiteName, int testIndex) +{ + std::wstring suitename = suiteName->Data(); + char csuitename[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(csuitename, suitename.c_str(), sizeof(csuitename)); + const char *cname = liblinphone_tester_test_name(csuitename, testIndex); + wchar_t wcname[MAX_SUITE_NAME_SIZE]; + mbstowcs(wcname, cname, sizeof(wcname)); + return ref new String(wcname); +} diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.h b/build/vsx/LibLinphoneTester/linphone-tester-native.h new file mode 100644 index 000000000..b0adb2cc2 --- /dev/null +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.h @@ -0,0 +1,25 @@ +#pragma once + +#include "liblinphone_tester.h" + +namespace linphone_tester_native +{ + public interface class OutputTraceListener + { + public: + void outputTrace(Platform::String^ msg); + }; + + public ref class LinphoneTesterNative sealed + { + public: + LinphoneTesterNative(); + virtual ~LinphoneTesterNative(); + void setOutputTraceListener(OutputTraceListener^ traceListener); + unsigned int nbTestSuites(); + unsigned int nbTests(Platform::String^ suiteName); + Platform::String^ testSuiteName(int index); + Platform::String^ testName(Platform::String^ suiteName, int testIndex); + void run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose); + }; +} \ No newline at end of file diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 1d17dbffc..23983972a 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -22,7 +22,7 @@ #include "CUnit/Basic.h" - +#include "linphonecore.h" typedef void (*test_function_t)(void); typedef int (*test_suite_function_t)(const char *name); From 264a6ac3aafe89a8fd6699fbaf764bcd6b087fc3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Mar 2013 11:13:14 +0100 Subject: [PATCH 073/909] Fix one more possible crash in TunnelManager if the ip address is NULL. --- coreapi/TunnelManager.cc | 4 ++++ gtk/update.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 4828bf114..d1020b1b2 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -102,6 +102,10 @@ int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, 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)); } 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) { From e3365fd0bf81e503ef4cbfed2687c1bd544bbc2b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Mar 2013 14:36:51 +0100 Subject: [PATCH 074/909] Update oRTP and mediastreamer2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 8d85a5ded..b2ddf6ece 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8d85a5ded3b18e2d3d4ba22ee75e0f1ef9c0f739 +Subproject commit b2ddf6ece0aede9c602cfb39d3f43f177c9dbf7e diff --git a/oRTP b/oRTP index b055a5050..16db79654 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b055a505042c4420e104ce81a09790c5373f62bb +Subproject commit 16db796543aa4cf0e44bb022f5556d7536e60c34 From d44378253138ee5be1146c3da1b1c0dc20625b2f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 4 Mar 2013 15:16:02 +0100 Subject: [PATCH 075/909] use cpu utils from ms2 --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 2e5c4cf59..948f88e3f 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -21,7 +21,7 @@ package org.linphone.core; import java.io.File; import java.io.IOException; -import org.linphone.CpuUtils; +import org.linphone.mediastream.CpuUtils; import org.linphone.mediastream.Version; import android.util.Log; diff --git a/mediastreamer2 b/mediastreamer2 index 8d85a5ded..81dd82dc6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8d85a5ded3b18e2d3d4ba22ee75e0f1ef9c0f739 +Subproject commit 81dd82dc688b0f3e5d3f4d6783a64d04240c35ca From 5ee5a32489283331f047cb678a261d36b82d84be Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Mar 2013 16:35:03 +0100 Subject: [PATCH 076/909] Fix linphonerc reading on wp8 --- .../LibLinphoneTester-wp8.v11.suo | Bin 110592 -> 144896 bytes .../LibLinphoneTester-wp8/Assets/laure_rc | 38 +++++++++++ .../LibLinphoneTester-wp8/Assets/marie_rc | 44 +++++++++++++ .../Assets/multi_account_lrc | 55 ++++++++++++++++ .../LibLinphoneTester-wp8/Assets/oldphone.wav | Bin 0 -> 312300 bytes .../LibLinphoneTester-wp8/Assets/pauline_rc | 43 ++++++++++++ .../LibLinphoneTester-wp8/Assets/ringback.wav | Bin 0 -> 24620 bytes .../LibLinphoneTester-wp8.csproj | 7 ++ .../linphone-tester-native.cpp | 3 +- tester/call_tester.c | 62 +++++++++--------- tester/liblinphone_tester.c | 19 ++++-- tester/liblinphone_tester.h | 9 ++- tester/message_tester.c | 16 ++--- tester/presence_tester.c | 8 +-- tester/register_tester.c | 2 +- 15 files changed, 253 insertions(+), 53 deletions(-) create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo index d48a9cb52df2d7aa2f35175669445320e3890c27..3b78758d40a2f62923ef1e0c18f59b48effa3186 100644 GIT binary patch delta 12832 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 +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc new file mode 100644 index 000000000..df91cf251 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc @@ -0,0 +1,55 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 + +[auth_info_0] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth.example.org" + +[auth_info_1] +username=pauline +userid=pauline +passwd=secret +realm="sip.example.org" + +[auth_info_2] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth1.example.org" + +[auth_info_3] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + +[proxy_0] +reg_proxy=sip.example.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_1] +reg_proxy=sip.example.org;transport=tcp +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_2] +reg_proxy=auth1.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav new file mode 100644 index 0000000000000000000000000000000000000000..e3056cc5dbbab5c93b84b85207cc44df80d1ab72 GIT binary patch literal 312300 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 +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=8090 +video_rtp_port=8092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav new file mode 100644 index 0000000000000000000000000000000000000000..21f4b5bfb763e5448843e4410ce9d742227aa572 GIT binary patch literal 24620 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 literal 0 HcmV?d00001 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj index 813ca7641..43c29fa40 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -129,6 +129,11 @@ + + + + + Designer @@ -139,6 +144,7 @@ PreserveNewest + PreserveNewest @@ -170,6 +176,7 @@ LibLinphoneTester + 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

Ke!Rdqux2s{L&6hCl;uCzyfA!e23AK>4*b@_#!H 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 bj_0mFG592W5k1kY=^1urFA!-0;>rI3$wnMA literal 312300 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 Date: Thu, 7 Mar 2013 16:08:04 +0100 Subject: [PATCH 099/909] history chat delete update README for macos --- README.macos | 3 + coreapi/chat.c | 2 +- coreapi/linphonecore.h | 1 + coreapi/message_storage.c | 368 +++++++++++++++++++------------------- gtk/chat.c | 6 +- gtk/friendlist.c | 26 +++ gtk/propertybox.c | 1 + 7 files changed, 224 insertions(+), 183 deletions(-) diff --git a/README.macos b/README.macos index 29666f440..bb78575bf 100644 --- a/README.macos +++ b/README.macos @@ -39,6 +39,9 @@ You need: - Install additional librairies required for wizard (linphone.org account creation assistant) $ sudo port install libsoup + - Install sqlite3 for message storage + $ sudo port install sqlite3 + ** WARNING 2013-03-06 glib-networking is currently broken in macports - generates crashes or hangs when used in a bundle ** As a temporary workaround, build a newer version by yourself: $ wget http://ftp.gnome.org/pub/gnome/sources/glib-networking/2.34/glib-networking-2.34.2.tar.xz diff --git a/coreapi/chat.c b/coreapi/chat.c index 5f79849dc..046c34733 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -182,10 +182,10 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_chat_message_set_external_body_url(msg, sal_msg->url); } linphone_address_destroy(addr); - linphone_chat_room_message_received(cr,lc,msg); linphone_core_set_history_message(cr,to,from,INCOMING, msg->message,my_ctime_r(&msg->time,buf),NOT_READ, LinphoneChatMessageStateDelivered); + linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); ms_free(from); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c1054922d..49074db3e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1420,6 +1420,7 @@ int linphone_core_get_video_dscp(const LinphoneCore *lc); MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message); void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read); +void linphone_core_delete_history(LinphoneCore *lc,const char *from); #ifdef __cplusplus } diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 90665c26c..3d6c45d93 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -1,82 +1,82 @@ -/* -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 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 - -#ifdef MSG_STORAGE_ENABLED - -#include "sqlite3.h" - +/* +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 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 + +#ifdef MSG_STORAGE_ENABLED + +#include "sqlite3.h" + 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"}; - -#define CONFIG_FILE ".linphone-history.db" - -char *linphone_message_storage_get_config_file(const char *filename){ - const int path_max=1024; - char *config_file=(char *)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(config_file,path_max,"%s",filename); - }else{ -#ifdef WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(config_file,NULL); - snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(config_file,path_max,"%s/%s",home,filename); -#endif - } - return config_file; -} - -void create_chat_message(char **argv, void *data){ - LinphoneChatRoom *cr = (LinphoneChatRoom *)data; - LinphoneChatMessage* new_message = linphone_chat_room_create_message(cr,argv[4]); +static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; + +#define CONFIG_FILE ".linphone-history.db" + +char *linphone_message_storage_get_config_file(const char *filename){ + const int path_max=1024; + char *config_file=(char *)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(config_file,path_max,"%s",filename); + }else{ +#ifdef WIN32 + const char *appdata=getenv("APPDATA"); + if (appdata){ + snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); + CreateDirectory(config_file,NULL); + snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); + } +#else + const char *home=getenv("HOME"); + if (home==NULL) home="."; + snprintf(config_file,path_max,"%s/%s",home,filename); +#endif + } + return config_file; +} + +void create_chat_message(char **argv, void *data){ + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + LinphoneChatMessage* new_message = linphone_chat_room_create_message(cr,argv[4]); struct tm ret={0}; char tmp1[80]={0}; - char tmp2[80]={0}; - - if(atoi(argv[3])==INCOMING){ - linphone_chat_message_set_from(new_message,linphone_address_new(argv[2])); - } else { - linphone_chat_message_set_from(new_message,linphone_address_new(argv[1])); - } - + char tmp2[80]={0}; + + if(atoi(argv[3])==INCOMING){ + linphone_chat_message_set_from(new_message,linphone_address_new(argv[2])); + } else { + linphone_chat_message_set_from(new_message,linphone_address_new(argv[1])); + } + if(argv[5]!=NULL){ int i,j; sscanf(argv[5],"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, @@ -87,108 +87,116 @@ void create_chat_message(char **argv, void *data){ } for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - } - new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); - new_message->state=atoi(argv[7]); - cr->messages_hist=ms_list_prepend(cr->messages_hist,(void *)new_message); -} - -static int callback(void *data, int argc, char **argv, char **colName){ - create_chat_message(argv,data); - return 0; -} - -void linphone_sql_request_message(sqlite3 *db,const char *stmt,void *data){ - char* errmsg; - int ret; - ret=sqlite3_exec(db,stmt,callback,data,&errmsg); - if(ret != SQLITE_OK) { - printf("Error in creation: %s.\n", errmsg); - } -} - -void linphone_sql_request(sqlite3* db,const char *stmt){ - char* errmsg; - int ret; - ret=sqlite3_exec(db,stmt,0,0,&errmsg); - if(ret != SQLITE_OK) { - printf("Error in creation: %s.\n", errmsg); - } -} - -void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, - int direction, const char *message,const char *date, int read, int state){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", - local_contact,remote_contact,direction,message,date,read,state); - linphone_sql_request(lc->db,buf); -} - -void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - char time_str[26]; - char *buf=sqlite3_mprintf("update history set status=%i where message = %Q and time = %Q;", - state,message,my_ctime_r(&date,time_str)); - linphone_sql_request(lc->db,buf); -} - -void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - char *buf=sqlite3_mprintf("update history set read=%i where remoteContact = %Q;", - read,from); - linphone_sql_request(lc->db,buf); -} - -MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - cr->messages_hist = NULL; - char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",to,nb_message); - linphone_sql_request_message(lc->db,buf,(void *)cr); - return cr->messages_hist; -} - -void linphone_close_storage(sqlite3* db){ - sqlite3_close(db); -} - -void linphone_create_table(sqlite3* db){ - char* errmsg; - 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) { - printf("Error in creation: %s.\n", errmsg); - } -} - -sqlite3 * linphone_message_storage_init(){ - int ret; - char *errmsg; - sqlite3 *db; - char *filename; - filename=linphone_message_storage_get_config_file(NULL); - ret=sqlite3_open(filename,&db); - if(ret != SQLITE_OK) { - printf("Error in the opening: %s.\n", errmsg); - sqlite3_close(db); - } - linphone_create_table(db); - return db; -} -#else - -void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, - int direction, const char *message,const char *date, int read, int state){ -} - -void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ -} - -void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ -} - -MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ - return NULL; -} + } + } + new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); + new_message->state=atoi(argv[7]); + cr->messages_hist=ms_list_prepend(cr->messages_hist,(void *)new_message); +} + +static int callback(void *data, int argc, char **argv, char **colName){ + create_chat_message(argv,data); + return 0; +} + +void linphone_sql_request_message(sqlite3 *db,const char *stmt,void *data){ + char* errmsg; + int ret; + ret=sqlite3_exec(db,stmt,callback,data,&errmsg); + if(ret != SQLITE_OK) { + printf("Error in creation: %s.\n", errmsg); + } +} + +void linphone_sql_request(sqlite3* db,const char *stmt){ + char* errmsg; + int ret; + ret=sqlite3_exec(db,stmt,0,0,&errmsg); + if(ret != SQLITE_OK) { + printf("Error in creation: %s.\n", errmsg); + } +} + +void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, + int direction, const char *message,const char *date, int read, int state){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", + local_contact,remote_contact,direction,message,date,read,state); + linphone_sql_request(lc->db,buf); +} + +void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + char time_str[26]; + char *buf=sqlite3_mprintf("update history set status=%i where message = %Q and time = %Q;", + state,message,my_ctime_r(&date,time_str)); + linphone_sql_request(lc->db,buf); +} + +void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + char *buf=sqlite3_mprintf("update history set read=%i where remoteContact = %Q;", + read,from); + linphone_sql_request(lc->db,buf); +} + +void linphone_core_delete_history(LinphoneCore *lc,const char *from){ + char *buf=sqlite3_mprintf("delete from history where remoteContact = %Q;",from); + linphone_sql_request(lc->db,buf); +} + +MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + cr->messages_hist = NULL; + char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",to,nb_message); + linphone_sql_request_message(lc->db,buf,(void *)cr); + return cr->messages_hist; +} + +void linphone_close_storage(sqlite3* db){ + sqlite3_close(db); +} + +void linphone_create_table(sqlite3* db){ + char* errmsg; + 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) { + printf("Error in creation: %s.\n", errmsg); + } +} + +sqlite3 * linphone_message_storage_init(){ + int ret; + char *errmsg; + sqlite3 *db; + char *filename; + filename=linphone_message_storage_get_config_file(NULL); + ret=sqlite3_open(filename,&db); + if(ret != SQLITE_OK) { + printf("Error in the opening: %s.\n", errmsg); + sqlite3_close(db); + } + linphone_create_table(db); + return db; +} +#else + +void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, + int direction, const char *message,const char *date, int read, int state){ +} + +void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ +} + +void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ +} + +MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ + return NULL; +} + +void linphone_core_delete_history(LinphoneCore *lc,const char *from){ +} #endif \ No newline at end of file diff --git a/gtk/chat.c b/gtk/chat.c index c93d9828c..b3a5ecfdc 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -23,6 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif +#define NB_MSG_HIST 250 + void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { GtkWidget *main_window=linphone_gtk_get_main_window (); GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); @@ -302,7 +304,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres "margin","indent",10,NULL); gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), "bg","paragraph-background-gdk",&colorb,NULL); - messages = linphone_chat_room_get_history(with_str,cr,10); + messages = linphone_chat_room_get_history(with_str,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); @@ -339,7 +341,7 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, udpate_tab_chat_header(chat_view,uri,cr); g_object_set_data(G_OBJECT(chat_view),"cr",cr); g_object_set_data(G_OBJECT(linphone_gtk_get_widget(main_window,"contact_list")),"chatview",(gpointer)chat_view); - messages = linphone_chat_room_get_history(uri_only,cr,10); + messages = linphone_chat_room_get_history(uri_only,cr,NB_MSG_HIST); g_object_set_data(G_OBJECT(chat_view),"from_message",uri_str); display_history_message(chat_view,messages,uri); } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 6ef326610..4ae86dfab 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -165,6 +165,21 @@ void linphone_gtk_remove_contact(GtkWidget *button){ } } +void linphone_gtk_delete_history(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkTreeSelection *select; + GtkTreeIter iter; + GtkTreeModel *model; + LinphoneFriend *lf=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_delete_history(linphone_gtk_get_core(),linphone_address_as_string_uri_only(linphone_friend_get_address(lf))); + linphone_gtk_show_friends(); + } +} + static void linphone_gtk_call_selected(GtkTreeView *treeview){ linphone_gtk_set_selection_to_uri_bar(treeview); linphone_gtk_start_call(linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), @@ -786,6 +801,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 +824,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 +864,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)); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 8481bef7e..1c189e0b8 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -778,6 +778,7 @@ static LangCodes supported_langs[]={ { "zh_TW" , N_("Traditional Chinese") }, { "nb_NO" , N_("Norwegian") }, { "he" , N_("Hebrew") }, + { "sr" , N_("Serbian") }, { NULL , NULL } }; From 673ddcae3da7925b841d91b6076e81e8fd8f82e0 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 7 Mar 2013 17:33:11 +0100 Subject: [PATCH 100/909] liblinphone tester: add android mk and modify sources for make it works --- build/android/common.mk | 5 +- build/android/liblinphone_tester.mk | 38 +++++++++ java/.DS_Store | Bin 6148 -> 0 bytes tester/call_tester.c | 62 +++++++------- tester/liblinphone_tester.c | 120 ++++++++++++++++++++++++++-- tester/liblinphone_tester.h | 7 +- tester/message_tester.c | 16 ++-- tester/presence_tester.c | 8 +- tester/register_tester.c | 4 +- 9 files changed, 204 insertions(+), 56 deletions(-) create mode 100644 build/android/liblinphone_tester.mk delete mode 100644 java/.DS_Store diff --git a/build/android/common.mk b/build/android/common.mk index 4221ea183..48c716cc8 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -89,8 +89,6 @@ LOCAL_C_INCLUDES += \ LOCAL_LDLIBS += -llog -ldl - - LOCAL_STATIC_LIBRARIES := \ cpufeatures \ libmediastreamer2 \ @@ -198,3 +196,6 @@ else endif endif +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) + diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk new file mode 100644 index 000000000..48e5d937c --- /dev/null +++ b/build/android/liblinphone_tester.mk @@ -0,0 +1,38 @@ +LOCAL_PATH := $(call my-dir)/../../tester + +common_SRC_FILES := \ + call_tester.c \ + liblinphone_tester.c \ + message_tester.c \ + presence_tester.c \ + register_tester.c \ + setup_tester.c \ + +# neon + +include $(CLEAR_VARS) + +ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) +LOCAL_MODULE := liblinphone_tester +LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_LDLIBS := -llog + +LOCAL_SHARED_LIBRARIES := cunit liblinphone +include $(BUILD_SHARED_LIBRARY) +endif + +# noneon + +include $(CLEAR_VARS) + +LOCAL_MODULE := liblinphone_testernoneon +ifeq ($(TARGET_ARCH_ABI),armeabi) +LOCAL_MODULE_FILENAME := liblinphone_testerarmv5 +endif +LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_LDLIBS := -llog + +LOCAL_SHARED_LIBRARIES := cunit liblinphonenoneon +include $(BUILD_SHARED_LIBRARY) + +#end diff --git a/java/.DS_Store b/java/.DS_Store deleted file mode 100644 index e6dc460bb1c6d2efab7037b03d06d0556d348790..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jqp4=5QS%qgvIYIqf#4$mI7itHYo8^+Vg;}!TM!kPMk^St>SKu2 zy&WuhT}`%Nw2S8Op?PPuDF&v|E?SVlv^p5502LT1&_&+c`M-yMoBu~GOsN1B_%j7` zzB}x;c&R*FKVHx3$E@1A!9l+q;q4~?i5lc; LinphoneCore* lc_pauline=pauline->lc; @@ -182,8 +182,8 @@ static void simple_call(void) { } static void cancelled_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); @@ -216,8 +216,8 @@ static void call_with_dns_time_out(void) { } static void cancelled_ringing_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); @@ -234,8 +234,8 @@ static void cancelled_ringing_call(void) { } static void early_declined_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); @@ -256,8 +256,8 @@ static void early_declined_call(void) { } static void call_terminated_by_caller(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ @@ -270,8 +270,8 @@ static void call_terminated_by_caller(void) { } static void call_paused_resumed(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* call_obj; CU_ASSERT_TRUE(call(pauline,marie)); @@ -308,8 +308,8 @@ static bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,Linph } static void call_paused_resumed_from_callee(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* call_obj; CU_ASSERT_TRUE(call(pauline,marie)); @@ -333,9 +333,11 @@ static void call_paused_resumed_from_callee(void) { linphone_core_manager_destroy(pauline); } +#ifdef VIDEO_ENABLED + static void call_with_video_added(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* call_obj; LinphoneVideoPolicy pauline_policy; LinphoneCallParams* marie_params; @@ -376,10 +378,12 @@ static void call_with_video_added(void) { linphone_core_manager_destroy(pauline); } +#endif + static void simple_conference(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(FILE_PREFIX, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); stats initial_marie_stat; stats initial_pauline_stat; stats initial_laure_stat; @@ -434,8 +438,8 @@ static void simple_conference(void) { } static void srtp_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); @@ -455,8 +459,8 @@ static void srtp_call(void) { } static void early_media_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_early_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); @@ -472,9 +476,9 @@ static void early_media_call(void) { } static void simple_call_transfer(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(FILE_PREFIX, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); LinphoneCall* pauline_called_by_marie; char* laure_identity=linphone_address_as_string(laure->identity); @@ -521,9 +525,9 @@ static void simple_call_transfer(void) { } static void call_transfer_existing_call_outgoing_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(FILE_PREFIX, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 31b64fe2e..9e411ef54 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -38,6 +38,11 @@ const char* test_username="liblinphone_tester"; const char* test_password="secret"; const char* test_route="sip2.linphone.org"; +#if WINAPI_FAMILY_PHONE_APP +const char *liblinphone_tester_file_prefix="Assets"; +#else +const char *liblinphone_tester_file_prefix="./tester"; +#endif LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); @@ -87,9 +92,9 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c LinphoneCore* lc; int retry=0; stats* counters; - char filepath[50]; - char ringpath[50]; - char ringbackpath[50]; + char filepath[256]; + char ringpath[256]; + char ringbackpath[256]; sprintf(filepath, "%s/%s", path, file); lc = linphone_core_new(v_table,NULL,filepath,NULL); linphone_core_set_user_data(lc,&global_stat); @@ -294,18 +299,59 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) return CU_get_error(); } +#ifdef ANDROID +#include + +static const char* LogDomain = "liblinphone_tester"; + +void linphone_android_log_handler(int prio, const char *fmt, va_list args) { + char str[4096]; + char *current; + char *next; + + vsnprintf(str, sizeof(str) - 1, fmt, args); + str[sizeof(str) - 1] = '\0'; + if (strlen(str) < 512) { + __android_log_write(prio, LogDomain, str); + } else { + current = str; + while ((next = strchr(current, '\n')) != NULL) { + *next = '\0'; + __android_log_write(prio, LogDomain, current); + current = next + 1; + } + __android_log_write(prio, LogDomain, current); + } +} + +static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + int prio; + switch(lev){ + case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; break; + case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; break; + case ORTP_WARNING: prio = ANDROID_LOG_WARN; break; + case ORTP_ERROR: prio = ANDROID_LOG_ERROR; break; + case ORTP_FATAL: prio = ANDROID_LOG_FATAL; break; + default: prio = ANDROID_LOG_DEFAULT; break; + } + linphone_android_log_handler(prio, fmt, args); +} +#endif #ifndef WINAPI_FAMILY_PHONE_APP int main (int argc, char *argv[]) { - int i; + int i,j; int ret; - char *suite_name=NULL; - char *test_name=NULL; + const char *suite_name=NULL; + const char *test_name=NULL; for(i=1;i\n" + "\t\t\t--config \n" "\t\t\t--domain \n" "\t\t\t---auth-domain \n" #if HAVE_CU_GET_SUITE @@ -318,7 +364,11 @@ int main (int argc, char *argv[]) { , argv[0]); return 0; }else if (strcmp(argv[i],"--verbose")==0){ +#ifndef ANDROID linphone_core_enable_logs(NULL); +#else + linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); +#endif }else if (strcmp(argv[i],"--domain")==0){ i++; test_domain=argv[i]; @@ -328,9 +378,23 @@ int main (int argc, char *argv[]) { }else if (strcmp(argv[i],"--test")==0){ i++; test_name=argv[i]; + }else if (strcmp(argv[i],"--config")==0){ + i++; + liblinphone_tester_file_prefix=argv[i]; }else if (strcmp(argv[i],"--suite")==0){ i++; suite_name=argv[i]; + }else if (strcmp(argv[i],"--list-suites")==0){ + for(j=0;j +#include +#define CALLBACK_BUFFER_SIZE 1024 +static JNIEnv *current_env = NULL; +static jobject current_obj = 0; + +void cunit_android_trace_handler(int level, const char *fmt, va_list args) { + char buffer[CALLBACK_BUFFER_SIZE]; + JNIEnv *env = current_env; + if(env == NULL) return; + vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args); + jstring javaString = (*env)->NewStringUTF(env, buffer); + jint javaLevel = level; + jclass cls = (*env)->GetObjectClass(env, current_obj); + jmethodID method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V"); + (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString); +} + +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, argv[i], 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; iidentity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); @@ -74,8 +74,8 @@ static void text_message(void) { } static void text_message_with_ack(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -88,8 +88,8 @@ static void text_message_with_ack(void) { } static void text_message_with_external_body(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -105,8 +105,8 @@ static void text_message_with_external_body(void) { } static void text_message_with_send_error(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); char* to = linphone_address_as_string(pauline->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 076f6c040..9d804ac55 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -43,7 +43,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { } static void simple_publish(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(marie->lc,&proxy); linphone_proxy_config_edit(proxy); @@ -54,8 +54,8 @@ static void simple_publish(void) { } static void simple_subscribe(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(FILE_PREFIX, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); LinphoneFriend* friend; CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); @@ -74,7 +74,7 @@ static void simple_subscribe(void) { } static void unsubscribe_while_subscribing(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(FILE_PREFIX, "marie_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ linphone_friend_edit(friend); linphone_friend_enable_subscribes(friend,TRUE); diff --git a/tester/register_tester.c b/tester/register_tester.c index bcab7ee84..94fd37ec5 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -234,7 +234,7 @@ static void authenticated_register_with_late_credentials(){ } static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { - return configure_lc_from(v_table, FILE_PREFIX, "multi_account_lrc", 3); + return configure_lc_from(v_table, liblinphone_tester_file_prefix, "multi_account_lrc", 3); } static void multiple_proxy(){ @@ -313,7 +313,9 @@ static void io_recv_error(){ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, +#ifndef ANDROID { "TLS register", simple_tls_register }, +#endif { "Simple authenticated register", simple_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, From 09b68886a34a42a7703c2756b559a04582a0bd8a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 7 Mar 2013 17:41:12 +0100 Subject: [PATCH 101/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index a824c4739..daa8d61fe 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a824c473919ab993e536e9f2d29471332e68280e +Subproject commit daa8d61feee22ffcc72a2db189aa88956697de20 From 48421099007b53c75c0cdd46c10d28ff9d16e3cb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 7 Mar 2013 18:43:59 +0100 Subject: [PATCH 102/909] remove contact as const char* from op->contact in case of bellesip --- .cproject | 2 +- console/Makefile.am | 1 + coreapi/bellesip_sal/sal_impl.c | 40 ++++-------- coreapi/bellesip_sal/sal_impl.h | 3 + coreapi/friend.c | 12 ++-- coreapi/linphonecore.c | 111 +++++++++++++++++++++----------- coreapi/presence.c | 8 +-- coreapi/proxy.c | 73 ++++++++++++++------- coreapi/sal.c | 31 +++++---- include/sal/sal.h | 15 +++++ 10 files changed, 180 insertions(+), 116 deletions(-) diff --git a/.cproject b/.cproject index 02473afca..ed10f0f5e 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + diff --git a/console/Makefile.am b/console/Makefile.am index 82ce998e5..e33d608d1 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -3,6 +3,7 @@ AM_CPPFLAGS=\ -I$(top_srcdir) \ -I$(top_srcdir)/coreapi \ + -I$(top_srcdir)/include \ -I$(top_srcdir)/exosip COMMON_CFLAGS=\ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index a88860e23..83073578b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -16,10 +16,9 @@ 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 void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { int ortp_level; @@ -232,30 +231,11 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); received = belle_sip_header_via_get_received(via_header); rport = belle_sip_header_via_get_rport(via_header); - if (!sal_op_get_contact(op)) { - /*check if contqct set in reauest*/ - - if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { - /*no contact set yet, try to see if sip tack has an updated one*/ - contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_object_unref(contact_address); - } else { - - /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ - contact_address=belle_sip_header_address_new(); - contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); - belle_sip_header_address_set_uri(contact_address,contact_uri); - - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - } - if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { - belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); - } - contact_updated=TRUE; - } + if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { + /*update contact with sent values in any cases*/ + contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_object_unref(contact_address); } if (received!=NULL || rport>0) { @@ -289,10 +269,12 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } } if (contact_updated) { + char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); - sal_op_set_contact(op,new_contact); + ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); belle_sip_free(new_contact); + belle_sip_free(old_contact); } if (contact_address)belle_sip_object_unref(contact_address); } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 085ce8f8b..e7e22b9b2 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -19,10 +19,13 @@ 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 */ diff --git a/coreapi/friend.c b/coreapi/friend.c index b1dd9c4c9..e55deb75d 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -108,7 +108,6 @@ 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); @@ -116,12 +115,6 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ if (cfg!=NULL){ route=linphone_proxy_config_get_route(cfg); from=linphone_proxy_config_get_identity(cfg); - if (cfg->op){ - fixed_contact=sal_op_get_contact(cfg->op); - if (fixed_contact) { - ms_message("Contact for subscribe has been fixed using proxy to %s",fixed_contact); - } - } }else from=linphone_core_get_primary_contact(fr->lc); if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ @@ -136,7 +129,10 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ } fr->outsub=sal_op_new(fr->lc->sal); sal_op_set_route(fr->outsub,route); - sal_op_set_contact(fr->outsub,fixed_contact); + if (cfg && cfg->op && sal_op_get_contact(cfg->op)) + sal_op_set_contact(fr->outsub,sal_op_get_contact(cfg->op)); + else + sal_op_set_contact(fr->outsub,NULL); sal_subscribe_presence(fr->outsub,from,friend); fr->subscribe_active=TRUE; ms_free(friend); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 199a1cc3b..16375869b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2318,54 +2318,68 @@ const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAdd } return linphone_core_get_primary_contact (lc); } - +#ifndef USE_BELLESIP static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ - LinphoneAddress *ctt; +#else +static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ +#endif + LinphoneAddress *ctt=NULL; +#ifdef USE_BELLESIP + LinphoneAddress *ret; +#else + char* ret; +#endif const char *localip=call->localip; /* first use user's supplied ip address if asked*/ if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ ctt=linphone_core_get_primary_contact_parsed(lc); - 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){ + linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); + #ifdef USE_BELLESIP + ret=ctt; + #else + ret=linphone_adress_as_string(ctt); + #endif + } else if (call->op && sal_op_get_contact(call->op)!=NULL){ + /* if already choosed, don't change it */ 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); - } - } - + } else if (call->ping_op && sal_op_get_contact(call->ping_op)) { + /* if the ping OPTIONS request succeeded use the contact guessed from the + received, rport*/ + ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; +#else + ret=ms_strdup(sal_op_get_contact(call->ping_op)); +#endif + } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(dest_proxy->op)){ /*if using a proxy, use the contact address as guessed with the REGISTERs*/ - 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); + ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); +#else + ret=ms_strdup(sal_op_get_contact(dest_proxy->op)); +#endif + } else { + ctt=linphone_core_get_primary_contact_parsed(lc); + if (ctt!=NULL){ + /*otherwise use supllied localip*/ + linphone_address_set_domain(ctt,localip); + linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); + ms_message("Contact has been fixed using local ip"/* to %s",ret*/); +#ifdef USE_BELLESIP + ret=ctt; +#else + ret=linphone_address_as_string_uri_only(ctt); +#endif } } +#ifndef USE_BELLESIP + if (ctt) linphone_address_destroy(ctt); +#endif + return ret; - 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){ @@ -2401,7 +2415,12 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ int err; +#ifndef USE_BELLESIP char *contact; +#else + LinphoneAddress *contact; +#endif + char *real_url,*barmsg; char *from; LinphoneProxyConfig *dest_proxy=call->dest_proxy; @@ -2410,7 +2429,12 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ contact=get_fixed_contact(lc,call,dest_proxy); if (contact){ sal_op_set_contact(call->op, contact); +#ifndef USE_BELLESIP ms_free(contact); +#else + linphone_address_destroy(contact); +#endif + } linphone_core_stop_dtmf_stream(lc); linphone_call_init_media_streams(call); @@ -3103,7 +3127,11 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { LinphoneProxyConfig *cfg=NULL; - const char *contact=NULL; +#ifndef USE_BELLESIP + char *contact=NULL; +#else + LinphoneAddress *contact=NULL; +#endif SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; @@ -3159,9 +3187,14 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, } /*try to be best-effort in giving real local or routable contact address*/ contact=get_fixed_contact(lc,call,call->dest_proxy); - if (contact) + if (contact) { sal_op_set_contact(call->op,contact); - +#ifdef USE_BELLESIP + linphone_address_destroy(contact); +#else + ms_free(contact); +#endif + } if (params){ const SalMediaDescription *md = sal_call_get_remote_media_description(call->op); _linphone_call_params_copy(&call->params,params); diff --git a/coreapi/presence.c b/coreapi/presence.c index ca6357258..4643d7d9f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -58,7 +58,6 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ char *tmp; LinphoneAddress *uri; LinphoneProxyConfig *cfg; - const char *fixed_contact; uri=linphone_address_new(from); linphone_address_clean(uri); @@ -68,10 +67,9 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ cfg=linphone_core_lookup_known_proxy(lc,uri); if (cfg!=NULL){ if (cfg->op){ - fixed_contact=sal_op_get_contact(cfg->op); - if (fixed_contact) { - sal_op_set_contact (op,fixed_contact); - ms_message("Contact for next subscribe answer has been fixed using proxy to %s",fixed_contact); + if (sal_op_get_contact(cfg->op)) { + sal_op_set_contact (op,sal_op_get_contact(cfg->op)); + ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/); } } } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 6998b8731..8ab64606b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -255,49 +255,62 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) obj->lc=lc; linphone_proxy_config_done(obj); } - +#ifndef USE_BELLESIP static char *guess_contact_for_register(LinphoneProxyConfig *obj){ - LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); char *ret=NULL; + #else +LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ + LinphoneAddress *ret=NULL; +#endif + LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); + const char *host; if (proxy==NULL) return NULL; host=linphone_address_get_domain (proxy); if (host!=NULL){ int localport = -1; - char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'}; + const char *localip = NULL; char *tmp; LCSipTransports tr; - LinphoneAddress *contact; + LinphoneAddress *contact=linphone_address_new(obj->reg_identity); + + if (obj->contact_params) + tmp=ms_strdup_printf("",linphone_address_get_username(contact) + ,linphone_address_get_domain(contact) + ,obj->contact_params); + else + tmp=ms_strdup_printf("",linphone_address_get_username(contact) + ,linphone_address_get_domain(contact)); - contact=linphone_address_new(obj->reg_identity); + linphone_address_destroy(contact); + contact=linphone_address_new(tmp); #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); + linphone_core_get_sip_transports(obj->lc,&tr); + if (tr.udp_port <= 0) { + if (tr.tcp_port>0) { + sal_address_set_param(contact,"transport","tcp"); + } else if (tr.tls_port>0) { + sal_address_set_param(contact,"transport","tls"); + } + } + } #endif //BUILD_UPNP -#ifdef USE_BELLESIP -#ifdef BUILD_UPNP - else -#endif /*BUILD_UPNP*/ - { - linphone_address_destroy(contact); - return NULL; - } -#endif /*USE_BELLESIP*/ + +#ifndef USE_BELLESIP if(localip == NULL) { + char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'}; 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); - 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) { @@ -306,27 +319,41 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ sal_address_set_param(contact,"transport","tls"); } } +#endif - 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_set_port_int(contact,localport); + linphone_address_set_domain(contact,localip); + linphone_address_set_display_name(contact,NULL); + +#ifndef USE_BELLESIP + ret = linphone_address_as_string(contact); linphone_address_destroy(contact); +#else + ret=contact; +#endif /*USE_BELLESIP*/ + linphone_address_destroy (proxy); ms_free(tmp); } - linphone_address_destroy (proxy); return ret; } static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ +#ifndef USE_BELLESIP char *contact; +#else + LinphoneAddress *contact; +#endif if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); if ((contact=guess_contact_for_register(obj))) { sal_op_set_contact(obj->op,contact); +#ifndef USE_BELLESIP ms_free(contact); +#else + linphone_address_destroy(contact); +#endif } sal_op_set_user_pointer(obj->op,obj); if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { diff --git a/coreapi/sal.c b/coreapi/sal.c index 07d189ed8..4685b0bc5 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -22,7 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The purpose of this layer is too allow experiment different call signaling protocols and implementations under linphone, for example SIP, JINGLE... **/ - +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "sal/sal.h" const char* sal_transport_to_string(SalTransport transport) { switch (transport) { @@ -246,16 +248,15 @@ static void assign_string(char **str, const char *arg){ *str=ms_strdup(arg); } - +#ifdef USE_BELLESIP void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ - char* address_string=sal_address_as_string(address); /*can probably be optimized*/ - sal_op_set_contact(op,address_string); - ms_free(address_string); + if (((SalOpBase*)op)->contact_address) sal_address_destroy(((SalOpBase*)op)->contact_address); + ((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL; } const SalAddress* sal_op_get_contact_address(const SalOp *op) { return ((SalOpBase*)op)->contact_address; } - +#endif #define SET_PARAM(op,name) \ char* name##_string=NULL; \ assign_address(&((SalOpBase*)op)->name##_address,name); \ @@ -265,10 +266,14 @@ const SalAddress* sal_op_get_contact_address(const SalOp *op) { assign_string(&((SalOpBase*)op)->name,name##_string); \ if(name##_string) ms_free(name##_string); +#ifndef USE_BELLESIP void sal_op_set_contact(SalOp *op, const char *contact){ - SET_PARAM(op,contact); + assign_string(&((SalOpBase*)op)->contact,contact); } - +const char *sal_op_get_contact(const SalOp *op){ + return ((SalOpBase*)op)->contact; +} +#endif void sal_op_set_route(SalOp *op, const char *route){ char* route_string=(void *)0; SalOpBase* op_base = (SalOpBase*)op; @@ -339,9 +344,7 @@ const char *sal_op_get_to(const SalOp *op){ const SalAddress *sal_op_get_to_address(const SalOp *op){ return ((SalOpBase*)op)->to_address; } -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; @@ -404,10 +407,16 @@ void __sal_op_free(SalOp *op){ ms_free(b->route); b->route=NULL; } +#ifndef USE_BELLESIP if (b->contact) { ms_free(b->contact); b->contact=NULL; } +#else + if (b->contact_address) { + sal_address_destroy(b->contact_address); + } +#endif if (b->origin){ ms_free(b->origin); b->origin=NULL; diff --git a/include/sal/sal.h b/include/sal/sal.h index 70a788769..f48edbde3 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -26,6 +26,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef sal_h #define sal_h +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "mediastreamer2/mscommon.h" #include "ortp/ortp_srtp.h" @@ -226,8 +230,11 @@ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ MSList* route_addresses; /*list of SalAddress* */ +#ifndef USE_BELLESIP char *contact; +#else SalAddress* contact_address; +#endif char *from; SalAddress* from_address; char *to; @@ -401,8 +408,12 @@ SalOp * sal_op_new(Sal *sal); /*generic SalOp API, working for all operations */ Sal *sal_op_get_sal(const SalOp *op); +#ifndef USE_BELLESIP void sal_op_set_contact(SalOp *op, const char *contact); +#else +#define sal_op_set_contact sal_op_set_contact_address /*for liblinphone compatibility*/ void sal_op_set_contact_address(SalOp *op, const SalAddress* address); +#endif void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_route_address(SalOp *op, const SalAddress* address); void sal_op_add_route_address(SalOp *op, const SalAddress* address); @@ -419,8 +430,12 @@ const char *sal_op_get_from(const SalOp *op); const SalAddress *sal_op_get_from_address(const SalOp *op); const char *sal_op_get_to(const SalOp *op); const SalAddress *sal_op_get_to_address(const SalOp *op); +#ifndef USE_BELLESIP const char *sal_op_get_contact(const SalOp *op); +#else const SalAddress *sal_op_get_contact_address(const SalOp *op); +#define sal_op_get_contact sal_op_get_contact_address /*for liblinphone compatibility*/ +#endif const char *sal_op_get_route(const SalOp *op); const MSList* sal_op_get_route_addresses(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); From 79fe5f18b718ca3e5460ee9558f069ad8f2e8404 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 7 Mar 2013 21:11:29 +0100 Subject: [PATCH 103/909] better contact/nat management --- configure.ac | 25 ++++++++---- coreapi/bellesip_sal/sal_impl.c | 68 ++++++++++++++++----------------- tester/liblinphone_tester.c | 3 ++ 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/configure.ac b/configure.ac index a311afe34..fda85dd08 100644 --- a/configure.ac +++ b/configure.ac @@ -759,13 +759,15 @@ 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, - [ - found_cunit=yes - CUNIT_LIBS="-lcunit" - ]) -fi + 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*) @@ -774,7 +776,16 @@ case "$target_os" in ;; esac AM_CONDITIONAL([BUILD_CUNIT_TESTS], [test x$found_cunit = xyes && test x$enable_tests != xno]) - +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 dnl ################################################## diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 83073578b..0ef2250df 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -237,46 +237,46 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even sal_op_set_contact_address(op,(const SalAddress *)contact_address); belle_sip_object_unref(contact_address); } + if (sal_op_get_contact(op)){ + if (received!=NULL || rport>0) { - if (received!=NULL || rport>0) { - if (sal_op_get_contact(op)){ contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - } - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) - ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; + /*try to fix transport if needed (very unlikely)*/ + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + if (!belle_sip_uri_get_transport_param(contact_uri) + ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); + } } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); + if (contact_updated) { + char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_free(new_contact); + belle_sip_free(old_contact); } + if (contact_address)belle_sip_object_unref(contact_address); } - if (contact_updated) { - char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_free(new_contact); - belle_sip_free(old_contact); - } - if (contact_address)belle_sip_object_unref(contact_address); } } /*update request/response diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 9e411ef54..d3997526d 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -20,6 +20,9 @@ #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" +#if HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +#endif static test_suite_t **test_suite = NULL; From 5d79ed6fc0a5568038a952875b7a6d9dfce4f0d1 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 7 Mar 2013 22:21:14 +0100 Subject: [PATCH 104/909] fix android build scripts --- build/android/common.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/android/common.mk b/build/android/common.mk index 48c716cc8..dc220634e 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -50,7 +50,8 @@ LOCAL_SRC_FILES := \ linphonecall.c \ conference.c \ ec-calibrator.c \ - linphone_tunnel_config.c + linphone_tunnel_config.c \ + message_storage.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" @@ -64,6 +65,7 @@ LOCAL_CFLAGS += \ -DHAVE_CONFIG_H \ -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ + -DUSE_BELLESIP LOCAL_CFLAGS += -DIN_LINPHONE From 4542532cd273d21f4c5535e1fc1ff20d61a0ac8c Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 8 Mar 2013 12:24:48 +0100 Subject: [PATCH 105/909] uPnP support network changes --- coreapi/linphonecore.c | 13 ++++ coreapi/upnp.c | 160 +++++++++++++++++++++++++++++++++++------ coreapi/upnp.h | 1 + mediastreamer2 | 2 +- 4 files changed, 152 insertions(+), 24 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eac319061..bdf2193c1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5288,9 +5288,22 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu } lc->netup_time=curtime; lc->network_reachable=isReachable; + if(!isReachable) { sal_reset_transports(lc->sal); } +#ifdef BUILD_UPNP + if(lc->upnp == NULL) { + if(isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + lc->upnp = linphone_upnp_context_new(lc); + } + } else { + if(!isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } + } +#endif } void linphone_core_refresh_registers(LinphoneCore* lc) { diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 240c34b38..596afe333 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -20,6 +20,10 @@ 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 @@ -27,7 +31,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define UPNP_CORE_READY_CHECK 1 #define UPNP_CORE_RETRY_DELAY 4 #define UPNP_CALL_RETRY_DELAY 1 - +#define UPNP_UUID_LEN 32 +#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]; @@ -86,6 +92,7 @@ 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_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); @@ -96,7 +103,7 @@ 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); @@ -105,6 +112,61 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB 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(*str1 != '\0' && *str2 != '\0' && i < len) { + char1 = toupper(*str1); + char2 = toupper(*str2); + if(char1 != char2) { + return char1 - char2; + } + str1++; + str2++; + len++; + } + 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_new(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 */ @@ -293,15 +355,17 @@ void linphone_upnp_context_destroy(UpnpContext *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 */ @@ -430,6 +494,10 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { return port; } +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) { @@ -477,6 +545,7 @@ 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); @@ -539,6 +608,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); @@ -769,7 +839,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); @@ -845,10 +915,11 @@ void linphone_upnp_update_config(UpnpContext* lupnp) { /* 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 +929,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); } @@ -958,6 +1030,7 @@ UpnpPortBinding *linphone_upnp_port_binding_new() { ms_mutex_init(&port->mutex, NULL); port->state = LinphoneUpnpStateIdle; 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'; @@ -993,11 +1066,27 @@ 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, @@ -1044,6 +1133,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); @@ -1130,25 +1222,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"s-%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; @@ -1163,15 +1265,22 @@ 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; } void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) { 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) { @@ -1201,6 +1310,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 fe403a772..d785954a4 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/mediastreamer2 b/mediastreamer2 index daa8d61fe..06e505707 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit daa8d61feee22ffcc72a2db189aa88956697de20 +Subproject commit 06e505707c31d11e056f2dad4de3ac617985333b From 3e9c5351b308aa6ac60db372eced838965454f46 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 8 Mar 2013 14:24:50 +0100 Subject: [PATCH 106/909] Updated wp project --- build/vsx/LibLinphone/LibLinphone.vcxproj | 1 + .../LibLinphoneTester-wp8.v11.suo | Bin 159746 -> 208928 bytes 2 files changed, 1 insertion(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 7b1119321..3644e8e47 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -190,6 +190,7 @@ + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo index 8a4e2eff39bb54d279ee8580c2743473c9b9fadb..adbab95b5f881b2e6067858dcdfc4177bbc60681 100644 GIT binary patch delta 16783 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 CDb1b$ delta 13121 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 Date: Fri, 8 Mar 2013 14:34:15 +0100 Subject: [PATCH 107/909] add early media confuguration file for test --- tester/marie_early_rc | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tester/marie_early_rc diff --git a/tester/marie_early_rc b/tester/marie_early_rc new file mode 100644 index 000000000..65934c3f3 --- /dev/null +++ b/tester/marie_early_rc @@ -0,0 +1,45 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +incoming_calls_early_media=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file From ff26494fac8f92b88df63bd8596995d3784b8880 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 8 Mar 2013 15:56:00 +0100 Subject: [PATCH 108/909] Updated wp test app --- .../LibLinphoneTester-wp8.v11.suo | Bin 208928 -> 208921 bytes .../LibLinphoneTester-wp8.csproj | 1 + .../LibLinphoneTester-wp8/TestResultPage.xaml | 6 +- .../TestResultPage.xaml.cs | 112 ++++++++++++------ .../LibLinphoneTester-wp8/log.html | 34 ++++++ .../linphone-tester-native.cpp | 2 +- .../linphone-tester-native.h | 2 +- tester/call_tester.c | 8 +- tester/register_tester.c | 2 +- 9 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo index adbab95b5f881b2e6067858dcdfc4177bbc60681..56db99fd17d8eb3bd1ae463d65cd2286d15a2eef 100644 GIT binary patch delta 7850 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 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj index c737c799f..1647d6be2 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -134,6 +134,7 @@ + Designer diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml index 97afd9af6..42f143fa0 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml @@ -31,10 +31,8 @@ - - - - + + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs index 2ad80deb3..129d2d833 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs @@ -12,40 +12,78 @@ using linphone_tester_native; namespace LibLinphoneTester_wp8 { - public delegate void OutputDisplayDelegate(String msg); + public delegate void OutputDisplayDelegate(int level, String msg); public partial class TestResultPage : PhoneApplicationPage { public TestResultPage() { InitializeComponent(); - } - - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(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(String msg) - { - this.Dispatcher.BeginInvoke(() => - { - TestResults.Text += msg; - }); + 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; + } + } + }); } } @@ -73,15 +111,15 @@ namespace LibLinphoneTester_wp8 }, tup); await t; Running = false; - } - - public void outputTrace(String msg) - { - if (OutputDisplay != null) - { - OutputDisplay(msg); - } - System.Diagnostics.Debug.WriteLine(msg); + } + + public void outputTrace(int level, String msg) + { + if (OutputDisplay != null) + { + OutputDisplay(level, msg); + } + System.Diagnostics.Debug.WriteLine(msg); } public bool running { diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html new file mode 100644 index 000000000..4fea1c8bb --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html @@ -0,0 +1,34 @@ + + + + + + +

+ + diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp index 79c85e441..310db9984 100644 --- a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp @@ -22,7 +22,7 @@ static void nativeOutputTraceHandler(int lev, const char *fmt, va_list args) 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(msg); + sTraceListener->outputTrace(lev, msg); } } diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.h b/build/vsx/LibLinphoneTester/linphone-tester-native.h index b0adb2cc2..a35658bf6 100644 --- a/build/vsx/LibLinphoneTester/linphone-tester-native.h +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.h @@ -7,7 +7,7 @@ namespace linphone_tester_native public interface class OutputTraceListener { public: - void outputTrace(Platform::String^ msg); + void outputTrace(int level, Platform::String^ msg); }; public ref class LinphoneTesterNative sealed diff --git a/tester/call_tester.c b/tester/call_tester.c index 188f08b77..e06692792 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -604,18 +604,18 @@ static void call_transfer_existing_call_outgoing_call(void) { test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Cancelled call", cancelled_call }, - { "Call with DNS timeout", call_with_dns_time_out }, + //{ "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, { "Simple call", simple_call }, - { "Early-media call", early_media_call }, + //{ "Early-media call", early_media_call }, { "Call terminated by caller", call_terminated_by_caller }, { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, - { "SRTP call", srtp_call }, + //{ "SRTP call", srtp_call }, #ifdef VIDEO_ENABLED { "Call with video added", call_with_video_added }, #endif - { "Simple conference", simple_conference }, + //{ "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } }; diff --git a/tester/register_tester.c b/tester/register_tester.c index 94fd37ec5..c42d40363 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -314,7 +314,7 @@ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, #ifndef ANDROID - { "TLS register", simple_tls_register }, + //{ "TLS register", simple_tls_register }, #endif { "Simple authenticated register", simple_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, From 7c9b370b9db37e1c559c678b6b8ae958e192be92 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 8 Mar 2013 16:01:42 +0100 Subject: [PATCH 109/909] Fix tester jni --- tester/liblinphone_tester.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index d3997526d..703ba318f 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -47,6 +47,12 @@ const char *liblinphone_tester_file_prefix="Assets"; const char *liblinphone_tester_file_prefix="./tester"; #endif +#ifdef ANDROID +extern void AndroidPrintf(FILE *stream, const char *fmt, ...); +#define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) +#endif + + LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(addr); @@ -347,6 +353,8 @@ int main (int argc, char *argv[]) { int ret; const char *suite_name=NULL; const char *test_name=NULL; + + liblinphone_tester_init(); for(i=1;iCallVoidMethod(env, current_obj, method, javaLevel, javaString); } +JNIEXPORT + JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) { int i, ret; int argc = (*env)->GetArrayLength(env, stringArray); @@ -436,7 +447,7 @@ JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i); const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0); argv[i] = strdup(rawString); - (*env)->ReleaseStringUTFChars(env, argv[i], rawString); + (*env)->ReleaseStringUTFChars(env, string, rawString); } current_env = env; current_obj = obj; From dd6f6daf7f53129f3a11fe46da2ca2ec06ccc03d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 8 Mar 2013 16:29:11 +0100 Subject: [PATCH 110/909] Revert commented tests commited by inadvertance --- tester/call_tester.c | 8 ++++---- tester/register_tester.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index e06692792..188f08b77 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -604,18 +604,18 @@ static void call_transfer_existing_call_outgoing_call(void) { test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Cancelled call", cancelled_call }, - //{ "Call with DNS timeout", call_with_dns_time_out }, + { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, { "Simple call", simple_call }, - //{ "Early-media call", early_media_call }, + { "Early-media call", early_media_call }, { "Call terminated by caller", call_terminated_by_caller }, { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, - //{ "SRTP call", srtp_call }, + { "SRTP call", srtp_call }, #ifdef VIDEO_ENABLED { "Call with video added", call_with_video_added }, #endif - //{ "Simple conference", simple_conference }, + { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } }; diff --git a/tester/register_tester.c b/tester/register_tester.c index c42d40363..94fd37ec5 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -314,7 +314,7 @@ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, #ifndef ANDROID - //{ "TLS register", simple_tls_register }, + { "TLS register", simple_tls_register }, #endif { "Simple authenticated register", simple_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, From a9611258608812e9d3a61ec4a9a516b3749c181f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 8 Mar 2013 17:12:58 +0100 Subject: [PATCH 111/909] proxy guess contact return NULL in case of bad contact params --- coreapi/proxy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8ab64606b..54fe50aa9 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -285,6 +285,11 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_destroy(contact); contact=linphone_address_new(tmp); + if (!contact) { + ms_error("No valid contact_params for [%p]",linphone_address_get_domain(proxy)); + return NULL; + } + #ifdef BUILD_UPNP if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp && linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) { From 42ab420ce6a395d65655f4351011d6a49c82ece8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 9 Mar 2013 10:34:32 +0100 Subject: [PATCH 112/909] clean message storage API relax requirement for sqlite3 --- configure.ac | 26 ++++-- coreapi/callbacks.c | 5 +- coreapi/chat.c | 95 +++++++++++++-------- coreapi/linphonecore.c | 26 +++++- coreapi/linphonecore.h | 13 ++- coreapi/message_storage.c | 151 ++++++++++++++++++--------------- coreapi/private.h | 27 +++--- coreapi/sal.h | 4 +- coreapi/sal_eXosip2_presence.c | 23 ++++- gtk/chat.c | 68 ++++++++++----- gtk/friendlist.c | 4 +- gtk/linphone.h | 2 + gtk/main.c | 7 +- 13 files changed, 294 insertions(+), 157 deletions(-) diff --git a/configure.ac b/configure.ac index 9cb828e82..ae2d59386 100644 --- a/configure.ac +++ b/configure.ac @@ -670,21 +670,31 @@ if test x$enable_tunnel = xtrue; then fi AC_ARG_ENABLE(msg-storage, - [AS_HELP_STRING([--enable-msg-storage=[yes/no]], [Turn on compilation of message storage (default=yes)])], + [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=true] + [enable_msg_storage=auto] ) + +echo "enable_msg_storage = $enable_msg_storage" + AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue) -if test x$enable_msg_storage = xtrue; then - PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.7.0],[],[ - AC_MSG_ERROR([sqlite3 required for message storage not found.])] ) - SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED" - AC_SUBST(SQLITE3_CFLAGS) - AC_SUBST(SQLITE3_LIBS) +if test x$enable_msg_storage != xfalse; then + PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.7.0],[ + SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED" + AC_SUBST(SQLITE3_CFLAGS) + AC_SUBST(SQLITE3_LIBS) + enable_msg_storage=true + ],[ + if test x$enable_msg_storage = xtrue; then + AC_MSG_ERROR([sqlite3 required for message storage not found.]) + fi + enable_msg_storage=false + ] ) + fi diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index d65e53674..dd5ab7edc 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -934,10 +934,11 @@ 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); - linphone_core_set_message_state(chat_msg->chat_room,chat_msg->message,chatStatusSal2Linphone(status),chat_msg->time); + chat_msg->state=chatStatusSal2Linphone(status); + linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { chat_msg->cb(chat_msg - ,chatStatusSal2Linphone(status) + ,chat_msg->state ,chat_msg->cb_ud); } linphone_chat_message_destroy(chat_msg); diff --git a/coreapi/chat.c b/coreapi/chat.c index 046c34733..69893217d 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -62,16 +62,7 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ ms_free(cr->peer); } -#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 static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){ const char *route=NULL; @@ -80,8 +71,6 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM LinphoneCall *call; char* content_type; time_t t=time(NULL); - char buf[26]; - char *to; 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){ @@ -109,15 +98,14 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } 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,my_ctime_r(&t,buf)); + sal_message_send(op,identity,cr->peer,content_type, NULL); ms_free(content_type); } else { - sal_text_send(op, identity, cr->peer,msg->message,my_ctime_r(&t,buf)); + sal_text_send(op, identity, cr->peer,msg->message); } - to=linphone_address_as_string_uri_only (cr->peer_url); - linphone_core_set_history_message(cr,identity,to,OUTGOING,msg->message, - my_ctime_r(&t,buf),READ,LinphoneChatMessageStateInProgress); - ms_free(to); + msg->dir=LinphoneChatMessageOutgoing; + msg->from=linphone_address_new(identity); + linphone_chat_message_store(msg); } /** @@ -144,19 +132,15 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, } -void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){ - MSList *elem; +/** + * Retrieve an existing chat room whose peer is the supplied address, if exists. + * @param lc the linphone core + * @param add a linphone address. + * @returns the matching chatroom, or NULL if no such chatroom exists. +**/ +LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){ LinphoneChatRoom *cr=NULL; - LinphoneAddress *addr; - char *cleanfrom; - const char *to; - char *from; - LinphoneChatMessage* msg; - const SalCustomHeader *ch; - char buf[26]; - - addr=linphone_address_new(sal_msg->from); - linphone_address_clean(addr); + MSList *elem; for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ cr=(LinphoneChatRoom*)elem->data; if (linphone_chat_room_matches(cr,addr)){ @@ -164,7 +148,21 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag } cr=NULL; } - to=linphone_core_get_identity(lc); + return cr; +} + +void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){ + + LinphoneChatRoom *cr=NULL; + LinphoneAddress *addr; + char *cleanfrom; + char *from; + LinphoneChatMessage* msg; + const SalCustomHeader *ch; + + addr=linphone_address_new(sal_msg->from); + linphone_address_clean(addr); + cr=linphone_core_get_chat_room(lc,addr); cleanfrom=linphone_address_as_string(addr); from=linphone_address_as_string_uri_only(addr); if (cr==NULL){ @@ -173,8 +171,16 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag } 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; msg->state=LinphoneChatMessageStateDelivered; + msg->is_read=FALSE; ch=sal_op_get_custom_header(op); if (ch) msg->custom_headers=sal_custom_header_clone(ch); @@ -182,9 +188,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_chat_message_set_external_body_url(msg, sal_msg->url); } linphone_address_destroy(addr); - linphone_core_set_history_message(cr,to,from,INCOMING, - msg->message,my_ctime_r(&msg->time,buf),NOT_READ, - LinphoneChatMessageStateDelivered); + linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); ms_free(from); @@ -230,6 +234,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); msg->chat_room=(LinphoneChatRoom*)cr; msg->message=message?ms_strdup(message):NULL; + msg->is_read=TRUE; return msg; } @@ -327,10 +332,32 @@ void linphone_chat_message_set_from(LinphoneChatMessage* message, const Linphone *@param message #LinphoneChatMessage obj *@return #LinphoneAddress */ -LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) { +const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) { return message->from; } +/** + * Get destination of the message + *@param message #LinphoneChatMessage obj + *@return #LinphoneAddress + */ +const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message){ + if (message->to) return message->to; + if (message->dir==LinphoneChatMessageOutgoing){ + return message->chat_room->peer_url; + } + return NULL; +} + +/** + * Returns the origin address of a message if it was a outgoing message, or the destination address if it was an incoming message. + *@param message #LinphoneChatMessage obj + *@return #LinphoneAddress + */ +LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message){ + return message->dir==LinphoneChatMessageOutgoing ? message->from : message->to; +} + /** * Get the time the message was sent. */ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bdf2193c1..2bb9fab32 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1306,9 +1306,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #ifdef TUNNEL_ENABLED lc->tunnel=linphone_core_tunnel_new(lc); if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); -#endif -#ifdef MSG_STORAGE_ENABLED - lc->db=linphone_message_storage_init(); #endif if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); @@ -5265,6 +5262,8 @@ static void linphone_core_uninit(LinphoneCore *lc) } linphone_core_free_payload_types(lc); + + linphone_core_message_storage_close(lc); ortp_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); #ifdef TUNNEL_ENABLED @@ -5795,3 +5794,24 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ int linphone_core_get_video_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e); } + + +/** + * 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); + } +} + + diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 49074db3e..7212f26c4 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -663,12 +663,17 @@ typedef enum _LinphoneChatMessageStates { */ typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); +void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path); LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); +LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); void linphone_chat_room_destroy(LinphoneChatRoom *cr); LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); +void linphone_chat_room_delete_history(LinphoneChatRoom *cr); LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); @@ -677,7 +682,8 @@ LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessa const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); -LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); +const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); +const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); @@ -686,6 +692,7 @@ void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); +LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); @@ -1418,9 +1425,7 @@ 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); -MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message); -void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read); -void linphone_core_delete_history(LinphoneCore *lc,const char *from); + #ifdef __cplusplus } diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 3d6c45d93..c62fa1ddb 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -38,44 +38,22 @@ static inline char *my_ctime_r(const time_t *t, char *buf){ 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"}; -#define CONFIG_FILE ".linphone-history.db" -char *linphone_message_storage_get_config_file(const char *filename){ - const int path_max=1024; - char *config_file=(char *)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(config_file,path_max,"%s",filename); - }else{ -#ifdef WIN32 - const char *appdata=getenv("APPDATA"); - if (appdata){ - snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR); - CreateDirectory(config_file,NULL); - snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename); - } -#else - const char *home=getenv("HOME"); - if (home==NULL) home="."; - snprintf(config_file,path_max,"%s/%s",home,filename); -#endif - } - return config_file; -} - -void create_chat_message(char **argv, void *data){ +static void create_chat_message(char **argv, void *data){ LinphoneChatRoom *cr = (LinphoneChatRoom *)data; LinphoneChatMessage* new_message = linphone_chat_room_create_message(cr,argv[4]); + LinphoneAddress *from; struct tm ret={0}; char tmp1[80]={0}; char tmp2[80]={0}; - if(atoi(argv[3])==INCOMING){ - linphone_chat_message_set_from(new_message,linphone_address_new(argv[2])); + if(atoi(argv[3])==LinphoneChatMessageIncoming){ + from=linphone_address_new(argv[2]); } else { - linphone_chat_message_set_from(new_message,linphone_address_new(argv[1])); + from=linphone_address_new(argv[1]); } + linphone_chat_message_set_from(new_message,from); + linphone_address_destroy(from); if(argv[5]!=NULL){ int i,j; @@ -91,7 +69,7 @@ void create_chat_message(char **argv, void *data){ } new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); new_message->state=atoi(argv[7]); - cr->messages_hist=ms_list_prepend(cr->messages_hist,(void *)new_message); + cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } static int callback(void *data, int argc, char **argv, char **colName){ @@ -99,58 +77,84 @@ static int callback(void *data, int argc, char **argv, char **colName){ return 0; } -void linphone_sql_request_message(sqlite3 *db,const char *stmt,void *data){ +void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ char* errmsg; int ret; - ret=sqlite3_exec(db,stmt,callback,data,&errmsg); + ret=sqlite3_exec(db,stmt,callback,cr,&errmsg); if(ret != SQLITE_OK) { printf("Error in creation: %s.\n", errmsg); } } void linphone_sql_request(sqlite3* db,const char *stmt){ - char* errmsg; + char* errmsg=NULL; int ret; ret=sqlite3_exec(db,stmt,0,0,&errmsg); if(ret != SQLITE_OK) { - printf("Error in creation: %s.\n", errmsg); + ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); + sqlite3_free(errmsg); } } -void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, - int direction, const char *message,const char *date, int read, int state){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", - local_contact,remote_contact,direction,message,date,read,state); - linphone_sql_request(lc->db,buf); +void linphone_chat_message_store(LinphoneChatMessage *msg){ + LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); + if (lc->db){ + const char *peer=msg->chat_room->peer; + char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); + char datebuf[26]; + char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", + local_contact,peer,msg->dir,msg->message,my_ctime_r(&msg->time,datebuf),msg->is_read,msg->state); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(local_contact); + } } -void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - char time_str[26]; - char *buf=sqlite3_mprintf("update history set status=%i where message = %Q and time = %Q;", - state,message,my_ctime_r(&date,time_str)); - linphone_sql_request(lc->db,buf); +void linphone_chat_message_store_state(LinphoneChatMessage *msg){ + LinphoneCore *lc=msg->chat_room->lc; + if (lc->db){ + char time_str[26]; + char *buf=sqlite3_mprintf("update history set status=%i where message = %Q and time = %Q;", + msg->state,msg->message,my_ctime_r(&msg->time,time_str)); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + } } -void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int read=1; + + if (lc->db==NULL) return ; + char *buf=sqlite3_mprintf("update history set read=%i where remoteContact = %Q;", - read,from); + read,cr->peer); linphone_sql_request(lc->db,buf); + sqlite3_free(buf); } -void linphone_core_delete_history(LinphoneCore *lc,const char *from){ - char *buf=sqlite3_mprintf("delete from history where remoteContact = %Q;",from); +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ + LinphoneCore *lc=cr->lc; + + if (lc->db==NULL) return ; + char *buf=sqlite3_mprintf("delete from history where remoteContact = %Q;",cr->peer); linphone_sql_request(lc->db,buf); + sqlite3_free(buf); } -MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); + MSList *ret; + + if (lc->db==NULL) return NULL; + cr->messages_hist = NULL; - char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",to,nb_message); - linphone_sql_request_message(lc->db,buf,(void *)cr); - return cr->messages_hist; + char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",cr->peer,nb_message); + linphone_sql_request_message(lc->db,buf,cr); + sqlite3_free(buf); + ret=cr->messages_hist; + cr->messages_hist=NULL; + return ret; } void linphone_close_storage(sqlite3* db){ @@ -167,36 +171,49 @@ void linphone_create_table(sqlite3* db){ } } -sqlite3 * linphone_message_storage_init(){ +void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; - char *errmsg; + char *errmsg=NULL; sqlite3 *db; - char *filename; - filename=linphone_message_storage_get_config_file(NULL); - ret=sqlite3_open(filename,&db); + ret=sqlite3_open(lc->chat_db_file,&db); if(ret != SQLITE_OK) { printf("Error in the opening: %s.\n", errmsg); sqlite3_close(db); + sqlite3_free(errmsg); } linphone_create_table(db); - return db; + lc->db=db; } + +void linphone_core_message_storage_close(LinphoneCore *lc){ + if (lc->db){ + sqlite3_close(lc->db); + lc->db=NULL; + } +} + #else -void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, - int direction, const char *message,const char *date, int read, int state){ +void linphone_chat_message_store(LinphoneChatMessage *cr){ } -void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state, time_t date){ +void linphone_chat_message_store_state(LinphoneChatMessage *cr){ } -void linphone_core_set_messages_flag_read(LinphoneChatRoom *cr,const char *from, int read){ +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ } -MSList *linphone_chat_room_get_history(const char *to,LinphoneChatRoom *cr,int nb_message){ +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ return NULL; } -void linphone_core_delete_history(LinphoneCore *lc,const char *from){ +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ } -#endif \ No newline at end of file + +void linphone_core_message_storage_init(LinphoneCore *lc){ +} + +void linphone_core_message_storage_close(LinphoneCore *lc){ +} + +#endif diff --git a/coreapi/private.h b/coreapi/private.h index 35578604f..78344ee70 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -119,17 +119,25 @@ typedef struct _CallCallbackObj static const int linphone_call_magic=0x3343; +typedef enum _LinphoneChatMessageDir{ + LinphoneChatMessageIncoming, + LinphoneChatMessageOutgoing +} LinphoneChatMessageDir; + struct _LinphoneChatMessage { - char* message; LinphoneChatRoom* chat_room; + LinphoneChatMessageDir dir; + char* message; LinphoneChatMessageStateChangeCb cb; void* cb_ud; void* message_userdata; char* external_body_url; - LinphoneAddress* from; + LinphoneAddress *from; + LinphoneAddress *to; time_t time; SalCustomHeader *custom_headers; LinphoneChatMessageState state; + bool_t is_read; }; typedef struct StunCandidate{ @@ -616,6 +624,7 @@ struct _LinphoneCore LinphoneTunnel *tunnel; char* device_id; MSList *last_recv_msg_ids; + char *chat_db_file; #ifdef MSG_STORAGE_ENABLED sqlite3 *db; #endif @@ -700,19 +709,13 @@ void linphone_call_params_uninit(LinphoneCallParams *params); int linphone_upnp_init(LinphoneCore *lc); void linphone_upnp_destroy(LinphoneCore *lc); -#define OUTGOING 0 -#define INCOMING 1 - -#define NOT_READ 0 -#define READ 1 - #ifdef MSG_STORAGE_ENABLED sqlite3 * linphone_message_storage_init(); #endif -void linphone_core_set_history_message(LinphoneChatRoom *cr,const char *local_contact,const char *remote_contact, - int direction, const char *message,const char *date, int read, int state); -void linphone_core_set_message_state(LinphoneChatRoom *cr,const char *message, int state,time_t date); - +void linphone_chat_message_store(LinphoneChatMessage *msg); +void linphone_chat_message_store_state(LinphoneChatMessage *msg); +void linphone_core_message_storage_init(LinphoneCore *lc); +void linphone_core_message_storage_close(LinphoneCore *lc); #ifdef __cplusplus } diff --git a/coreapi/sal.h b/coreapi/sal.h index ba232cca3..25d8d20bc 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -430,8 +430,8 @@ int sal_register_refresh(SalOp *op, int expires); int sal_unregister(SalOp *h); /*Messaging */ -int sal_text_send(SalOp *op, const char *from, const char *to, const char *text, const char*t); -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char*t); +int sal_text_send(SalOp *op, const char *from, const char *to, const char *text); +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg); /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 2670af472..356d2a9fb 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -81,8 +81,23 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); } -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *t){ +#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; + char t[26]; + time_t curtime=time(NULL); + + my_ctime_r(&curtime,t); if(op->cid == -1) { @@ -120,6 +135,8 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co eXosip_unlock(); return -1; } + sal_exosip_add_custom_headers(sip,op->base.custom_headers); + osip_message_set_date(sip,t); 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); @@ -128,8 +145,8 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co return 0; } -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg,const char *t) { - return sal_message_send(op,from,to,"text/plain",msg,t); +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){ diff --git a/gtk/chat.c b/gtk/chat.c index b3a5ecfdc..6a65cd9fc 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -25,6 +25,37 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define NB_MSG_HIST 250 +#define CONFIG_FILE ".linphone-history.db" + +const char *linphone_gtk_message_storage_get_db_file(const char *filename){ + const int path_max=1024; + static char *db_file=NULL; + + if (db_file) return db_file; + + db_file=(char *)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"); @@ -92,16 +123,16 @@ void udpate_tab_chat_header(GtkWidget *chat_view,const LinphoneAddress *uri,Linp 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,begin; + GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview")); + GtkTextBuffer *buffer=gtk_text_view_get_buffer(text); + GtkTextIter iter,begin; int off; char *from_str=linphone_address_as_string_uri_only(from); char *from_message=(char *)g_object_get_data(G_OBJECT(w),"from_message"); GList *list=g_object_get_data(G_OBJECT(w),"list"); time_t t; - gtk_text_buffer_get_start_iter(buffer,&begin); + gtk_text_buffer_get_start_iter(buffer,&begin); gtk_text_buffer_get_end_iter(buffer,&iter); off=gtk_text_iter_get_offset(&iter); if(g_strcmp0(from_message,from_str)!=0){ @@ -148,7 +179,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, gtk_text_buffer_get_end_iter(buffer,&iter); 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_view_scroll_mark_onscreen(text,mark); } const LinphoneAddress* linphone_gtk_get_used_identity(){ @@ -160,8 +191,8 @@ const LinphoneAddress* linphone_gtk_get_used_identity(){ } 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"); @@ -277,7 +308,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.blue = 61952; with_str=linphone_address_as_string_uri_only(with); - linphone_core_set_messages_flag_read(cr,with_str,1); + linphone_chat_room_mark_as_read(cr); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); gtk_notebook_append_page(notebook,chat_view,create_tab_chat_header(cr,with)); @@ -304,7 +335,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres "margin","indent",10,NULL); gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), "bg","paragraph-background-gdk",&colorb,NULL); - messages = linphone_chat_room_get_history(with_str,cr,NB_MSG_HIST); + 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); @@ -325,23 +356,22 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, LinphoneChatRoom *cr2=(LinphoneChatRoom *)g_object_get_data(G_OBJECT(chat_view),"cr"); char *from_str=linphone_address_as_string(linphone_chat_room_get_peer_address (cr2)); char *uri_str=linphone_address_as_string(uri); - char *uri_only=linphone_address_as_string_uri_only(uri); MSList *messages=NULL; - linphone_core_set_messages_flag_read(cr,uri_only,1); - if(g_strcmp0(from_str,uri_str)!=0){ - GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); - GtkTextIter start; - GtkTextIter end; + linphone_chat_room_mark_as_read(cr); + if(g_strcmp0(from_str,uri_str)!=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); + 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(linphone_gtk_get_widget(main_window,"contact_list")),"chatview",(gpointer)chat_view); - messages = linphone_chat_room_get_history(uri_only,cr,NB_MSG_HIST); + messages = linphone_chat_room_get_history(cr,NB_MSG_HIST); g_object_set_data(G_OBJECT(chat_view),"from_message",uri_str); display_history_message(chat_view,messages,uri); } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 4ae86dfab..fc2c2f4b5 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -174,8 +174,10 @@ void linphone_gtk_delete_history(GtkWidget *button){ 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)) { + LinphoneChatRoom *cr; gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - linphone_core_delete_history(linphone_gtk_get_core(),linphone_address_as_string_uri_only(linphone_friend_get_address(lf))); + cr=linphone_core_get_chat_room(linphone_gtk_get_core(),linphone_friend_get_address(lf)); + linphone_chat_room_delete_history(cr); linphone_gtk_show_friends(); } } diff --git a/gtk/linphone.h b/gtk/linphone.h index f9597849d..aaa021a28 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -58,6 +58,8 @@ 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); + +const char *linphone_gtk_message_storage_get_db_file(const char *filename); void linphone_gtk_show_assistant(void); void linphone_gtk_close_assistant(void); diff --git a/gtk/main.c b/gtk/main.c index b1dab3d65..c6065241c 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -216,7 +216,7 @@ static const char *linphone_gtk_get_factory_config_file(){ } 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); @@ -248,6 +248,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, _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){ @@ -1840,6 +1841,7 @@ int main(int argc, char *argv[]){ GdkPixbuf *pbuf; const char *app_name="Linphone"; LpConfig *factory; + const char *db_file; #if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); @@ -1946,7 +1948,8 @@ int main(int argc, char *argv[]){ linphone_gtk_create_log_window(); linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); - linphone_gtk_init_liblinphone(config_file, factory_config_file); + db_file=linphone_gtk_message_storage_get_db_file(NULL); + linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); g_set_application_name(app_name); pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON)); From d450bab4f8b7b73ec39d45f99a248e09fcf00434 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 11 Mar 2013 12:03:19 +0100 Subject: [PATCH 113/909] fix android makefile. --- build/android/common.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/android/common.mk b/build/android/common.mk index 9fd68d779..543a9dc19 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -44,7 +44,8 @@ LOCAL_SRC_FILES := \ linphonecall.c \ conference.c \ ec-calibrator.c \ - linphone_tunnel_config.c + linphone_tunnel_config.c \ + message_storage.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" From 275d7c10a75075c0ad9538b4b87068bdb1636f29 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 11 Mar 2013 12:26:02 +0100 Subject: [PATCH 114/909] implement enable rport --- coreapi/bellesip_sal/sal_impl.c | 9 +++++---- coreapi/linphonecore.c | 6 +++--- coreapi/proxy.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 0ef2250df..49f6fa792 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -517,22 +517,23 @@ void sal_use_session_timers(Sal *ctx, int expires){ return ; } void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ms_error("sal_use_double_registrations not implemented yet"); + ms_warning("sal_use_double_registrations is deprecated"); return ; } void sal_reuse_authorization(Sal *ctx, bool_t enabled){ - ms_error("sal_reuse_authorization not implemented yet"); + ms_warning("sal_reuse_authorization is deprecated"); 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){ - ms_error("sal_use_rport not implemented yet"); + belle_sip_provider_enable_rport(ctx->prov,use_rports); + ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled"); return ; } void sal_use_101(Sal *ctx, bool_t use_101){ - ms_error("sal_use_101 not implemented yet"); + ms_warning("sal_use_101 is deprecated"); return ; } void sal_set_root_ca(Sal* ctx, const char* rootCa){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8691f0a31..a43b36362 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -470,8 +470,6 @@ static void net_config_read (LinphoneCore *lc) linphone_core_set_mtu(lc,tmp); tmp=lp_config_get_int(lc->config,"net","download_ptime",0); linphone_core_set_download_ptime(lc,tmp); - /*only set at setup*/ - sal_nat_helper_enable(lc->sal,lp_config_get_int(lc->config,"net","enable_nat_helper",1)); } static void build_sound_devices_table(LinphoneCore *lc){ @@ -4351,9 +4349,11 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy switch(pol) { case LinphonePolicyUseUpnp: sal_nat_helper_enable(lc->sal, FALSE); + sal_use_rport(lc->sal, FALSE); break; default: - sal_nat_helper_enable(lc->sal, TRUE); + sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config,"net","enable_nat_helper",1)); + 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); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 54fe50aa9..2917d14b7 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -286,7 +286,7 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_destroy(contact); contact=linphone_address_new(tmp); if (!contact) { - ms_error("No valid contact_params for [%p]",linphone_address_get_domain(proxy)); + ms_error("No valid contact_params for [%s]",linphone_address_get_domain(proxy)); return NULL; } From f1928d246f85e0d6c1a0a4491b8d0f921ab346c4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Mar 2013 12:55:56 +0100 Subject: [PATCH 115/909] Fix dns timeout test issue + fix terminate call mhen state = OutgoingInit --- build/vsx/LibLinphone/LibLinphone.vcxproj | 1 + .../LibLinphoneTester-wp8.v11.suo | Bin 208921 -> 208917 bytes .../LibLinphoneTester-wp8/Assets/empty_rc | 5 +++++ .../LibLinphoneTester-wp8.csproj | 1 + coreapi/bellesip_sal/sal_op_call.c | 1 + coreapi/linphonecore.c | 8 +++++++- coreapi/linphonecore.h | 2 +- tester/call_tester.c | 4 ++-- tester/empty_rc | 5 +++++ tester/liblinphone_tester.c | 8 ++++++-- tester/liblinphone_tester.h | 2 +- tester/register_tester.c | 2 +- 12 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc create mode 100644 tester/empty_rc diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 3644e8e47..65ad06dc8 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -125,6 +125,7 @@ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false false + Sync
Console diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo index 56db99fd17d8eb3bd1ae463d65cd2286d15a2eef..88762f6d7aaabcff0c5251ff41bbd500301bcc36 100644 GIT binary patch delta 10878 zcmdT~dsvlKy5DQ<&Hdu$A|N7ewy21RfT(!i+ysrAVC4nmDj;%`iwc&2ne$Xy$(mZ# z*p$?y-9}}nyBbH(VVuTCOKrxn#wP1jPp6#JhGxv;!1=x3w>JU;Q)lL%^YQ#x_jj%L zw$}TtZ$Ew6^@+=_kIxUBq0wmUfu7#pUL+bVunb58rZAC_=xu3U&Rbb4FL#ePzg?3S z_%6#to9TJc$QxO+_>QORrlLYde#`wyY@28cJ3A_5vw*aF-K+z)I8nt*12 zRGin@p#L!{7TpfsP5u~6%cRFCxT(K}2Pl|` z{ZIvyG5lBs6aDEVzYOcj7b6``!S|r;ZlJ${$Duq}!DQlOIU^}J7vu7Pe4s!)m^6M! zZI2sC+dY;I%lRv8clF(^&X-oq=kPyZE-(+E1uQ_i5Lg75fLI_7hzF=W5$R$e2}lN( z084?pfD~W_AfjEuny7PsfF#bK~UW9}JiR8W7j^S?%H2II zTGou#j;S*%UP4-c1 zX1o(CM8|cu&h}ZDJBo?Mm=Mu6)#zA)hGJWzT{arORhVm=J4sh+tGCZX{Z|^%7!e|j zp_4?i?=%=hAf*y~>l7ca*FRH)hikK~)?h^sAsiubto`ucgEa@j=|<3{F& zvC4B^u)BUCJNEGaW0j^_lM69bAXSGydiYn*cJIhaZ=ba5wENC4>}hyF>xw$YMg592 zGEc_DcPpCgvq0_x8doPr051IRgn2n)-VZvm1L!NQf zrpZxLd5>yYPiEScg88$mWsNgBuEl6Nj};1bQK6f zo_IuW`C-pejemj5$IG@&c5FDI+4#h!%w}4;kGSL?%-TiE@)p^dz>Ff}mR|py&l%@! zP6uv0_MLd5!L959b@Ub&$A+*jTSvY8^*@-=SfN>~sl{KurUbcgO{vDKBfuePPRP`% zH+@#DIo7>JnPhY-SX}@t1Qr1%;0`etDmqfdtiLen)o1p2hmJ4b`CZ|&SG$xY?5=if zOVfGVwgyVcU+8EQ-iznEQiTr+6aP5;{}J zd+4m7sD^?8@}$ARK!`0EAn&Gtpc1G8h!CO1nir>&qQ$3Y!^~mJ|DbJ6uH(?}#^kO1 zBPRZyoa)4AEbWhq9@!(Jeo2$dLns#kc;umbSfn{()mb}v-Ay}MnwD}8*)&D#Bu;dA zGL1|>$rrj(!~;1hk38@Io8@pV-ib=$T>Bh$dZ4O8>ohfxZ>6HFLQNfvx(X#y+2?jM zYRB|!Irh-92K|=H+VP64-K#WZnj`U3W6nNY>iGM*wgUVAKXT9fI$0!_-jFTbEL8sE zE9S#4i=&SZ;FDFiAA3uHSZIi;axwz~Z)>h41TN4~Z zAxVlWRA&uBZmdo;R-ST%ntLf!QyVCrJYg>ytI~87vnrLMdrFuv_`N{efw|kym5HEV zdx?V`^X0xKwnAnzP^PAnrk*cs%_0P zD7O7Dx{{HJu)H^PzePcOmKUM>mNI_%U&`2SW)i06cl1G<@1AgRrpNiZ@+Dk zkq+7~+sltIeRk@Cqn9r27jZj(B@Uc=)kR@id{{9_-?eE@{NLW{e&xOM4~#l>==n^U z|2(guEx|9i7Pe9iyQzcy6e1L+UG%G(k~c!{m2U_C?&xzTo?WgdLbC$i1~Uo75T3yV zg?{%nVf%w=k_B~z9k=~lfH)}P9!?f)Pn z>KOw`Ex=x7(R_2fj_CtTsh4_xdHs)Xt=iVQKkc)V)MK=m5cHAU+rxt8vw_-6``l)7 zX4FCmWQg?WkhcTu0SCYl7^S>(?yj~^)}!PLsC{q$_d%T>WHA+KDpFfZ0LtS4_kMNM zCU<-CfQ($U*xpgXke>#G1Ji*BAQFfIW&qIu+3PH%vw;|3u9fOMnhsp!@XE)O_gR8AwK z<;*N@Vr_f4z6E5q0S^G%0in+e7STJqbRATcwb@wmA7tc=Hgav}QF^8Z@8=k&xcFVv z-eu4CRgDSP)Wg-+;;;yhITGuNM$n3PhRa;%Y;+UWfrn1qVstFW-z4M{@CqM?m$D>W z2Q1fQYGM(cCnBE(|4zZ-nuxj-Bwavz{)^aGvT54noPF?<=CzYl*6t@(?Il;hr+uM*3^rYahn>~0-2IcJQit8b>-CJi z^2$$tWA)T&AKkH)TK3lR2!wYBI)#yYIwZxVEWy=`G(5_K?5Lnhzjek|yS~NA*gf2T zObOPtPT6j2p}CYLY5mvVlnqg?RU*@>K5mmxQ>kb#AKUd>aJ3i|%8|>3+-Bg#JRWHr zE;{0H0~3iGmKgk>hI9sQV`d;11GPk<59Jo4Uo6V;=uNE&xLS&`t;Ze!SJM8zEW|^~ns>C$&N;lq$8F8@n}iFI669^OOhS#tmLtm`Q$8G9R;YF&{8ezvmV+k zRPx!Fvl@SQwuFNk^dRZFZcTL0Jcf#6giX-2iK)yib{Z9W@?lv zWaJutL8Vir(2)z)aYuQ*j2o3&nV!SY7{nxr^@x{k6sci@Lcdo2)E91z*8LL(aRcgWHJg=P zjfASazNli|sxkzDC94eWwHjHboVI~id(bga(og1-<#RfQs~J)FFzhg2k`Zl&i9_%9Z-n*a+q+Yt=5% zq^o^Om9kelWU8LJ8wbi)HD1*i?#<@zDuekd$BHRhO@!P;was(uxxd=&LF%?eWWMur zVOVc4ANw$l$?GsH;?*e}FS}&x;Ue~`*VJ$INatA!C&Y6?{WY*$%<^7P}#Ug*@K6TMn-pBfObI+P5_;geOq6i-x4 z+DHB=m+RHq5^@uZ)E3*^q>@N0${Wb6eA<@>vvtbEqe=2*n3HynLHetw9@c3rc|1Uw zM&=grE9!&|3Wb?uy@Pfih4l)ooP2`BSpu`FL#(mZmRFfqR(RN{&&xy;-u0y~pTw+A zN@7tq0orGdkQwM@e35l2>^6gA`&llg93V(_sv>2vE_7^IMXJ`TTWC-M7DoGCB}7ke zdL(o@N=d(@lp6WCFJB;YbNEZ@rnFh1ry6F-Dw__{WJCpjK+dbSnV`C94ojYvQvlB| zQ5RF8s_^|{9^6mUiVCs6_W35(MM9^yQCcZ%OdYOHHhwr>mV=inIH$4~S19Wrm!Q~U zJ{*}iCc5HuD(VT$8b7r4ExlEr ztecSBP{_Yg+m%CFS(O`EOcsniAM3AHrPVmhntfF}t%k(OO-MWS&_Ss>O5J3wQom=l z?J&3QmqYkmzsU~I9-(?Qe6?I2k!&f$k>;~hU@prEOhTT9iB15Trqb!z2^j{bOo+KJAp zKc`CXB#}6xy~7B@Ezu=Y((m6hO?!hVQdMiRtG9a z;Si29`$rsn{njx|z!kEFADaFH;+B4tR4*JqgctVfq&maIkq_H``Z}CAa@P^h>U#1C^Gse23*UFwXyyFL)8Psj+a8#|k zeLpGYkZT@xQ04T4_J253$An?S^*)Bxpw10JU0;sYf#K+SIzr(AcO8@uzfiIcg6yw!SiR+f+@T0dQJoY04V_J<8jaltmiO-&v z?KP}Xo^jDSi=I>VmWLOzjSHj)UX(0|+1_-Joer$tvUxju#A)C70@-{D;bIk$;L zTW+;8*HJR)EDM)ceR-ffP{d0uh|E%${KSdRwk+ymXPo4rb-cjRQp$hM_PL#9I?MPn z{*6{t-*lFbRq$X70>Oh!E;x^SN%~mJR+?FRFB6adeus#7H`ILa%`_)`f{ZmxR&H{{ zqfIq(=>(Q-S$04F0&m$jd8g&fHD+SMc-+sDzJq`1L3jQ8Er)e{#qB$Ax{n_54m^0M zJ8=3rQ~x_~k+&^C`L;usu>YCMZu-VE8$rQ;?6P|q2+~iqhPv!tf%=s|G$yoNc6+02 zyX?+G9=`~3))XQ`*U+}h?k6*t(X#R>e#1eu|Di`5dr)r)S;>wvi$fc(Ph=3&wpk8% z^EEDF+r=3A?i*#<^#XrVEBAiSXIbKd`6(CqNe$m)!6)+~#=rlFu0p*n6QcN66QxH3 zHN4Dkx>$)j$~{%g9XH~!2b$zp)vVm|iz9rg&hl4;%uLqIVoSxbLvb?VHGJ-f*u=h+ zTQ{@QGW94gmP;F0z6`=Ow58dO9p(~-tCw3(aKpIV#mV$BLizcGJHDGW>^`0>XEg5n z^u(22-16QDK9|WwJ6M;D*uqDR{1NVm3p-B1-66A=eCA$ zX>wz~3`DF-7pq11M7$9@icaC|Qo9mic zYwe@*U=SRbd`|AYz{;L{gXv`IdFD($?I_QjV{P)l=ZH9Woo7Wd@(UJVIrC@M%tc<7 zpM38IhIU+MX(G>HqTi!LTT*-YP9{$LB~(@$FjK{Uv(GF~+~V7rxcs{iaqaCG3##&% z+0@+0+DlDrz;|3${enyl;GQ!6QeF<8u}x?Yh}JmR%vdnTcitzL@d)-*UFVxy~98LwYru%Z%|A!?M^##m$UQESsS(G)eY33Q)tKy5XvE9-XM z{?W7earSw9=e5t-`<&U(tKZnGUzZVWl_bfB=pPsuph%L5bRwG=1$^Brl{?E*pqVWV zlKRs+^yXtQlS-r)c{Qts41SGG(-|nOC7K_N4;aTJNhc~u5^uT~&ezL!jXx!D^8iZ> z>;)cG-0*W>p(Q6?k9w79*m8HaR9}EL^u&cJV1#4h7+O0K|*{NPjL>RA!3O< zB9ibW{D`T^Nq;6>tm$|v%WpoecNiZ2Asqx6Y-B)K!;xUPs&-zVq*bLRsMoGrI< zcW4~XTb;Ed4&;w`AgM8BJF`nyA>L<>o5o7nn$DIOR=d^mPrhf2P z*Y{GrpY|JmviIq_s59-8FLn<59gCUrEXIb&MsEAr*?adR7F!IYPjo!_cE{WqIgP*V z922mJRAnV7a9DRuD~@@%%)eT9Q#*^q-h5u;jQ3cxHiMrukuro?pa!*%(l=V*H^)}9 zkAbg9eU6<3em%87M`Irl8(5wGxCZYOa?aA|xA%Mc6B!Bh*?y83%M@=l&x-m6XpcG! zn)%)g{Zvw5mUmDR?vH1w_$P}z(laOdRcJSsgW)48Qxz*;#zTPxshoX}v%7N&>NFx2X6S`&7REr$n7hzsh^2&;5T{?wT=(#fwCR+1n0SPkLChqCzQk4( zm4p!%Moq{9FP3kLAuJipc#>ki%g4?yEiyM3IoanDUs3cNdt2hyi>C5}Yz!>r z%V*d6ET($%F~}fK#vQX^o~L!`Txd>l!d$*QWdMr#^0Cu&!i5O8LaNt`6Cmu62<`$6 zt*?b!?8E)kqc2k?Rq}a+7C9M1{AdUF##)F-o)gnxhtL+)T%7GHW2$^W|(`tzi{4T1TuV)TxHH+IVWscJ(;%OEq?{V0!j4?Bc6z zU$;Nbe6S^yMm;&n@0&EqYY`yf~i`aL~??kNjQH?;GI zRrnsQ61oicEGpXw9_HE&!GH8=u1IhE(0O&_GoFI5O}Jmf!ugq1ahz4sb{8gGI6-lA zY!n-Pcui%uPIv`!oND%m6gwh$&9Va3mIR17P?iWDCWn)aaY0( z50EsD=px=Geou(jMRcCxM~s>G9cr zd9&~J_j*%0Q|L;Acvw#xU?kcv!Asb370jsH#|+pT z!;C!Zxx*OhVP9xPmww{P7M&3Ql4|>eF$p9&h1zz?T#S7UKzw$N~Rx(F$8)WR4rbC@SWb`v6XjQKOfcl zdH%Y=mvPqM)Yj9dWwE@bp&F)oZZrhYfEt|au*9nxo`WJa$HRWq1^m$JjAr9fo!IgM z?li`G*SE!JhtK#4<4Vm*S_)nmZm|g`C>+zrgm?;^BhC{Sh>L{U!20l|-@-8d-R0xf zh*aO`wp%sgIyiXGNiWn0ljcqJrO)7pWxCx=m@(vVEy65ZB1E9UsG}L0mO8S3v#-M$ zHfC)qkND5EpkIq)9vLQ{SYmsNkTo@T2Du}?>fn7?AcILf-Bj&Oq5^&*b~K%^0N+X3 zj}%fq|M8abzD4i(lPKg^tZRcPUbiLQD;(I;3A2^V0sz2uXJ8_pJPp5sP7Yf#wW5VP z8ob@e_*>umiLL{Pd3f$8Y#J_D0b6~<4ToAd{kB4lrNXOhmj*)LK z6FhLxdlj-Xoh2>sBi;Xg7?-;{aMuS*9u3I~XjwluZ)a9P-I|6SpZRS_L1hhCa7iVL zVdOgUD_I^j|Lj^AiRUU=sSHvCX4XRlezg{|=rJuk*pM#IbC~rO@0k}Bk|eF5J8+d$ zE>%iTNsA@G-nC%T&|R{fubNqlC8Hok`PFh32)OnIn2wvOSQ6${k=hHa3xz@7M~disL2L$nf}OwvA`Kk%m*A zX0!d%$fyX*>LV%V-UJuJ+E3VdEbRakOSD$`;Tl-!$165PV(?zbN2>F_93bVW0v7Iv zh_E(BpAUw1lIiiP9DSJ`0fmP2g+;m94*Fo-{L=Z!-zj}I2OHjkU#lM~&2W0|0Ped_o`vphY~iimla%f& z-~jgJN9rp|u_UwCVZ%8&4Ufw5_prdo=HlgHY#zKpW2r^U4_G?ycsUmxcGie5rLsyi zL^C7yUIm@9U@z+e%uZw$@3sH_IN5~RH&|%f^EP^*I!1S*e-}G~=X~T8oX%vI$Cc&+ z+-#L2add>dmskEF6svV$c<~_fZ}ZP&pssru{&zfE$@7y#`0JBrVQ;9MplrEc9?iHT zrWHSZh?(!&U2Xn8)M4Gr$ynYGp-Mq6s{xE1$INt3WwCrt@^G}YFbiy_No~Z>;^YNb z5hhQ<(JAb=SP~}B#Qz${_9{QL$j2C7NM|Lm1gEF4Iec4m47QnN7q;vLvoEPg(q@!l z_cZ1}eT4j7xgN5Wyh7Fqw=b2ZiQ-0jugh*Q?J5IdrDpDR*^Q*K9Es13Gu?gF4H~-Y zK0uZH)!#sy%6svIEaxbsw2lCbjwU_m_t8NZx`E$w$9~fbZD=1QDh?a#4#0KkY%KoK zBFEG31yj8{>CR2_$%wn(3Goqf*WEg8{_|qxu^QOw%Pkj{DrJqZUdEy*Xy==HjmnV& zkPf_L|2$rPN{d=8Y~?K{gLuoKD0I9B-TdS=qY`}*PRlqZl6K9Uc)1E^PhmHJerC*L z&tUlnki`8zH7Sl$@FMW(vek#|?rraO%13FnKoThH&x2FGmutHe@-K8|Jl+&_>)qWO zE8gOFV<(e17}zhPubB`2nt# zS$kHNE?oSxlv)g~Wa9S#A3U`N63C+{ + diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f2ec4e883..2b484ac18 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -453,6 +453,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ sal_op_set_from(op,from); sal_op_set_to(op,to); + ms_message("[%s] calling [%s] on op [%p]", from, to, op); invite=sal_op_build_request(op,"INVITE"); sal_op_fill_invite(op,invite); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a43b36362..30dc49637 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3313,7 +3313,13 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) call = the_call; } - sal_call_terminate(call->op); + if (call->state != LinphoneCallOutgoingInit) + sal_call_terminate(call->op); + else { + /* In state OutgoingInit, op has to be destroyed */ + sal_op_release(call->op); + call->op = NULL; + } terminate_call(lc,call); return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ab56e6b29..1cba2ac3b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1323,7 +1323,7 @@ LINPHONE_PUBLIC void linphone_core_set_user_data(LinphoneCore *lc, void *userdat /* 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 struct _LpConfig *linphone_core_get_config(LinphoneCore *lc); /*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); diff --git a/tester/call_tester.c b/tester/call_tester.c index 188f08b77..8e3b9f630 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -19,6 +19,7 @@ #include #include "CUnit/Basic.h" #include "linphonecore.h" +#include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" @@ -200,12 +201,11 @@ static void cancelled_call(void) { } static void call_with_dns_time_out(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(NULL, NULL); + LinphoneCoreManager* marie = linphone_core_manager_new2(liblinphone_tester_file_prefix, "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; linphone_core_set_sip_transports(marie->lc,&transport); linphone_core_iterate(marie->lc); sal_set_dns_timeout(marie->lc->sal,0); - linphone_core_set_mtu(marie->lc, 1300); linphone_core_invite(marie->lc,"sip:toto@toto.com"); linphone_core_iterate(marie->lc); linphone_core_iterate(marie->lc); diff --git a/tester/empty_rc b/tester/empty_rc new file mode 100644 index 000000000..e8de43fa4 --- /dev/null +++ b/tester/empty_rc @@ -0,0 +1,5 @@ +[net] +mtu=1300 + +[sip] +ping_with_options=0 \ No newline at end of file diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 703ba318f..f495b3c42 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -162,7 +162,7 @@ static void enable_codec(LinphoneCore* lc,const char* type,int rate) { } } -LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_file) { +LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies) { LinphoneCoreManager* mgr= malloc(sizeof(LinphoneCoreManager)); LinphoneProxyConfig* proxy; memset (mgr,0,sizeof(LinphoneCoreManager)); @@ -173,7 +173,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_ mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; - mgr->lc=configure_lc_from(&mgr->v_table, path, rc_file, rc_file?1:0); + mgr->lc=configure_lc_from(&mgr->v_table, path, rc_file, check_for_proxies?(rc_file?1:0):0); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); linphone_core_get_default_proxy(mgr->lc,&proxy); @@ -184,6 +184,10 @@ LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_ return mgr; } +LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_file) { + return linphone_core_manager_new2(path, rc_file, TRUE); +} + void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); if (mgr->identity) linphone_address_destroy(mgr->identity); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 2efc1a23c..82aa5181b 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -130,7 +130,7 @@ typedef struct _LinphoneCoreManager { LinphoneAddress* identity; } LinphoneCoreManager; - +LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies); LinphoneCoreManager* linphone_core_manager_new(const char * path, const char* rc_file); void linphone_core_manager_destroy(LinphoneCoreManager* mgr); diff --git a/tester/register_tester.c b/tester/register_tester.c index 94fd37ec5..0ff192682 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -313,7 +313,7 @@ static void io_recv_error(){ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, -#ifndef ANDROID +#ifndef ANDROID { "TLS register", simple_tls_register }, #endif { "Simple authenticated register", simple_authenticated_register }, From 9f730356ca2b1800a81a435d71ac24e7424bf97e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Mar 2013 16:27:23 +0100 Subject: [PATCH 116/909] Disable srtp test if not defined --- tester/call_tester.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 8e3b9f630..ea96e611e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -611,7 +611,9 @@ test_t call_tests[] = { { "Call terminated by caller", call_terminated_by_caller }, { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, +#ifdef SRTP_ENABLED { "SRTP call", srtp_call }, +#endif #ifdef VIDEO_ENABLED { "Call with video added", call_with_video_added }, #endif From 8176edfa2866d9e07519d4f1149fcef4f6e946ca Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Mar 2013 16:45:01 +0100 Subject: [PATCH 117/909] Added linphonerc for early media test --- .../Assets/marie_early_rc | 48 +++++++++++++++++++ .../LibLinphoneTester-wp8.csproj | 1 + 2 files changed, 49 insertions(+) create mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc new file mode 100644 index 000000000..cf7fd383c --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc @@ -0,0 +1,48 @@ +[net] +mtu=1300 + +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +incoming_calls_early_media=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj index 89ef910f3..be5ee44f0 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -136,6 +136,7 @@ + Designer From d8612c0bc7ef1916a2e5fc5e874c1a2db4534ddd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 5 Mar 2013 16:35:40 +0100 Subject: [PATCH 118/909] full LinphoneAuthInfo impl for Android --- coreapi/authentication.c | 28 +++ coreapi/linphonecore.h | 4 + coreapi/linphonecore_jni.cc | 159 +++++++++++++++--- .../org/linphone/core/LinphoneAuthInfo.java | 20 +++ .../linphone/core/LinphoneCoreFactory.java | 10 ++ .../linphone/core/LinphoneAuthInfoImpl.java | 58 +++++-- .../core/LinphoneCoreFactoryImpl.java | 6 + 7 files changed, 250 insertions(+), 35 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 4b5d10fa8..8ab1c21ff 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -80,6 +80,13 @@ const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){ return i->userid; } +const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i){ + return i->realm; +} +const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i){ + return i->ha1; +} + /** * Sets the password. **/ @@ -113,6 +120,27 @@ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){ if (userid && strlen(userid)>0) info->userid=ms_strdup(userid); } +/** + * Sets realm. +**/ +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); +} +/** + * Sets ha1. +**/ +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. **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7212f26c4..de8a05afa 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -617,10 +617,14 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); +void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); +void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); +const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); +const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); /* you don't need those function*/ void linphone_auth_info_destroy(LinphoneAuthInfo *info); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 57ab7c4ca..6b6c3f5ce 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1187,33 +1187,150 @@ extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_publishEnable //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); } 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: 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: 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 diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index 6590dafeb..ed8a84017 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -63,6 +63,26 @@ 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); + } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 399b9ec8d..ea325057e 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -49,10 +49,20 @@ 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 + * @param ha1 + * @param realm + * */ + abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1,String realm); abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException; abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException; + /** * Constructs a LinphoneAddress object * @param username diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java index 45fd8a45e..dee96fe5d 100644 --- a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java @@ -20,36 +20,66 @@ 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); + 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); + protected LinphoneAuthInfoImpl(String username,String password, String realm) { - nativePtr = newLinphoneAuthInfo(username,"",password,"",""); + this(username,null,password,null,null); + } + protected LinphoneAuthInfoImpl(String username, String userid, String passwd, String ha1,String realm) { + nativePtr = newLinphoneAuthInfo(); + this.setUsername(username); + this.setUserId(userid); + this.setPassword(passwd); + this.setHa1(ha1); } protected void finalize() throws Throwable { 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); + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 2e5c4cf59..7b21ecaae 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -166,4 +166,10 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { { return System.getProperty("os.arch").contains("armv7"); } + + @Override + public LinphoneAuthInfo createAuthInfo(String username, String userid, + String passwd, String ha1, String realm) { + return new LinphoneAuthInfoImpl(username,userid,passwd,ha1,realm); + } } From 8d9cb2fd7d171fcea0b537af44d4e8449b66aa23 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Mar 2013 17:18:22 +0100 Subject: [PATCH 119/909] Fix null pointer exception --- coreapi/linphonecall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 86a5540aa..8cdb9c5b4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1916,8 +1916,10 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { void linphone_call_stop_media_streams(LinphoneCall *call){ linphone_call_stop_audio_stream(call); linphone_call_stop_video_stream(call); - ms_event_queue_skip(call->core->msevq); + if (call->core->msevq != NULL) { + ms_event_queue_skip(call->core->msevq); + } if (call->audio_profile){ rtp_profile_clear_all(call->audio_profile); rtp_profile_destroy(call->audio_profile); From 572f297862a0338d8f683d97f6005c41aa5f25ad Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 12 Mar 2013 10:18:50 +0100 Subject: [PATCH 120/909] Add some upnp in tester --- tester/Makefile.am | 2 +- tester/liblinphone_tester.c | 1 + tester/liblinphone_tester.h | 1 + tester/upnp_rc | 2 ++ tester/upnp_tester.c | 63 +++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tester/upnp_rc create mode 100644 tester/upnp_tester.c diff --git a/tester/Makefile.am b/tester/Makefile.am index 801d20ca0..24523893f 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -4,7 +4,7 @@ if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester TESTS=$(noinst_PROGRAMS) -liblinphone_tester_SOURCES= liblinphone_tester.c setup_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c +liblinphone_tester_SOURCES= liblinphone_tester.c setup_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c upnp_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f495b3c42..54f00a698 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -260,6 +260,7 @@ void liblinphone_tester_init(void) { add_test_suite(&call_test_suite); add_test_suite(&message_test_suite); add_test_suite(&presence_test_suite); + add_test_suite(&upnp_test_suite); } void liblinphone_tester_uninit(void) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 82aa5181b..f9d73765b 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -50,6 +50,7 @@ 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 int liblinphone_tester_nb_test_suites(void); diff --git a/tester/upnp_rc b/tester/upnp_rc new file mode 100644 index 000000000..3b04fd077 --- /dev/null +++ b/tester/upnp_rc @@ -0,0 +1,2 @@ + [net] + firewall_policy=4 diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c new file mode 100644 index 000000000..95a132e62 --- /dev/null +++ b/tester/upnp_tester.c @@ -0,0 +1,63 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static void upnp_start_n_stop(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + CU_ASSERT_TRUE(lc_upnp->lc->upnp != NULL); + linphone_core_manager_destroy(lc_upnp); +} + +static void upnp_check_state(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + CU_ASSERT_TRUE(linphone_core_get_upnp_state(lc_upnp->lc) == LinphoneUpnpStateOk); + linphone_core_manager_destroy(lc_upnp); +} + +static void upnp_check_ipaddress(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + const char *addr = linphone_core_get_upnp_external_ipaddress(lc_upnp->lc); + CU_ASSERT_TRUE(addr != NULL && strlen(addr)>=7); + linphone_core_manager_destroy(lc_upnp); +} + +test_t upnp_tests[] = { + { "Start and stop", upnp_start_n_stop }, + { "Check state", upnp_check_state }, + { "Check ip address", upnp_check_ipaddress }, +}; + +test_suite_t upnp_test_suite = { + "Upnp", + NULL, + NULL, + sizeof(upnp_tests) / sizeof(upnp_tests[0]), + upnp_tests +}; From be455ac57f02b0f152a9b6ed041d336a92f3c679 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 12 Mar 2013 12:49:19 +0100 Subject: [PATCH 121/909] Fix bug in upnp string compare function --- coreapi/upnp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 596afe333..e8841c2d6 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -111,22 +111,24 @@ void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPort 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(*str1 != '\0' && *str2 != '\0' && i < len) { + while(true) { + if(i >= len) { + return 0; + } char1 = toupper(*str1); char2 = toupper(*str2); - if(char1 != char2) { + if(char1 == '\0' || char2 == '\0' || char1 != char2) { return char1 - char2; } str1++; str2++; - len++; + i++; } - return 0; } + static int linphone_upnp_str_min(const char *str1, const char *str2) { int len1 = strlen(str1); int len2 = strlen(str2); @@ -135,6 +137,7 @@ static int linphone_upnp_str_min(const char *str1, const char *str2) { } return len1; } + char * linphone_upnp_format_device_id(const char *device_id) { char *ret = NULL; char *tmp; From 62e58cd961378fd6079ff23ea65dc1d90bf7e983 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 12 Mar 2013 12:59:43 +0100 Subject: [PATCH 122/909] Fix previous commit --- coreapi/upnp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index e8841c2d6..2dfd7f39c 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -114,19 +114,17 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind static int linphone_upnp_strncmpi(const char *str1, const char *str2, int len) { int i = 0; char char1, char2; - while(true) { - if(i >= len) { - return 0; - } + while(i < len) { char1 = toupper(*str1); char2 = toupper(*str2); - if(char1 == '\0' || char2 == '\0' || char1 != char2) { + 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) { From cb2d469a564885275830cc09cb0ffe9c53dd5a29 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 12 Mar 2013 13:27:59 +0100 Subject: [PATCH 123/909] Add some checks in the tester --- tester/call_tester.c | 2 + tester/liblinphone_tester.c | 101 +++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index ea96e611e..1bcc30968 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -437,6 +437,7 @@ static void simple_conference(void) { ms_list_free(lcs); } +#ifdef SRTP_ENABLED static void srtp_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -457,6 +458,7 @@ static void srtp_call(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +#endif //SRTP_ENABLED static void early_media_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_early_rc"); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 54f00a698..b7ffea485 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -232,6 +232,21 @@ static int test_suite_index(const char *suite_name) { return -1; } +static int test_index(const char *suite_name, const char *test_name) { + int j,i; + + j = test_suite_index(suite_name); + if(j != -1) { + for (i = 0; i < test_suite[j]->nb_tests; i++) { + if ((strcmp(test_name, test_suite[j]->tests[i].name) == 0) && (strlen(test_name) == strlen(test_suite[j]->tests[i].name))) { + return i; + } + } + } + + return -1; +} + int liblinphone_tester_nb_test_suites(void) { return nb_test_suites; } @@ -352,6 +367,30 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, } #endif +void helper(const char *name) { + fprintf(stderr,"%s \t--help\n" + "\t\t\t--verbose\n" + "\t\t\t--list-suites\n" + "\t\t\t--list-tests \n" + "\t\t\t--config \n" + "\t\t\t--domain \n" + "\t\t\t---auth-domain \n" +#if HAVE_CU_GET_SUITE + "\t\t\t--suite \n" + "\t\t\t--test \n" +#endif +#if HAVE_CU_CURSES + "\t\t\t--curses\n" +#endif + , name); +} + +#define CHECK_ARG(argument, index, argc) \ + if(index >= argc) { \ + fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ + return -1; \ + } \ + #ifndef WINAPI_FAMILY_PHONE_APP int main (int argc, char *argv[]) { int i,j; @@ -363,56 +402,60 @@ int main (int argc, char *argv[]) { for(i=1;i\n" - "\t\t\t--config \n" - "\t\t\t--domain \n" - "\t\t\t---auth-domain \n" -#if HAVE_CU_GET_SUITE - "\t\t\t--suite \n" - "\t\t\t--test \n" -#endif -#if HAVE_CU_CURSES - "\t\t\t--curses\n" -#endif - , argv[0]); + helper(argv[0]); return 0; - }else if (strcmp(argv[i],"--verbose")==0){ + } else if (strcmp(argv[i],"--verbose")==0){ #ifndef ANDROID linphone_core_enable_logs(NULL); #else linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); #endif - }else if (strcmp(argv[i],"--domain")==0){ - i++; + } else if (strcmp(argv[i],"--domain")==0){ + CHECK_ARG("--domain", ++i, argc); test_domain=argv[i]; - }else if (strcmp(argv[i],"--auth-domain")==0){ - i++; + } else if (strcmp(argv[i],"--auth-domain")==0){ + CHECK_ARG("--auth-domain", ++i, argc); auth_domain=argv[i]; - }else if (strcmp(argv[i],"--test")==0){ - i++; + } else if (strcmp(argv[i],"--test")==0){ + CHECK_ARG("--test", ++i, argc); test_name=argv[i]; - }else if (strcmp(argv[i],"--config")==0){ - i++; + } else if (strcmp(argv[i],"--config")==0){ + CHECK_ARG("--config", ++i, argc); liblinphone_tester_file_prefix=argv[i]; - }else if (strcmp(argv[i],"--suite")==0){ - 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){ + } else if (strcmp(argv[i],"--list-suites")==0){ for(j=0;j Date: Tue, 12 Mar 2013 14:45:27 +0100 Subject: [PATCH 124/909] Fix sal_text_send api for bellesip --- coreapi/bellesip_sal/sal_op_message.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 0055a11e2..826246a28 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -123,7 +123,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_op_release(op); } -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg,const char*t){ +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ /*FIXME impement time*/ belle_sip_request_t* req; char content_type_raw[256]; @@ -142,8 +142,8 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co return sal_op_send_request(op,req); } -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg, const char*t) { - return sal_message_send(op,from,to,"text/plain",msg,t); +int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { + return sal_message_send(op,from,to,"text/plain",msg); } void sal_op_message_fill_cbs(SalOp*op) { From 10a18463d51c68e436267fe6154f1216b0351918 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 12 Mar 2013 14:54:39 +0100 Subject: [PATCH 125/909] Add upnp_tester.c in liblinphone build for android --- build/android/liblinphone_tester.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 48e5d937c..0f621b35f 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -7,6 +7,7 @@ common_SRC_FILES := \ presence_tester.c \ register_tester.c \ setup_tester.c \ + upnp_tester.c \ # neon From 6d0a1f09ecfc7a84bb09c9ae3b28bfec2fe6ebc6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Mar 2013 16:10:08 +0100 Subject: [PATCH 126/909] Updated exports --- coreapi/linphonecore.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 59702929d..58b9179a5 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -522,9 +522,9 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char 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); +LINPHONE_PUBLIC 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_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); @@ -1021,7 +1021,7 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *@param lc #LinphoneCore object *@return #LinphoneProxyConfig with defualt value set */ -LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); From fa8135be0351dbaa115f72997886b2aa5258599c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Mar 2013 16:10:29 +0100 Subject: [PATCH 127/909] Updated wp projects --- build/vsx/LibLinphone/LibLinphone.vcxproj | 2 +- .../LibLinphone/LibLinphone.vcxproj.filters | 1 + .../LibLinphoneTester-wp8.v11.suo | Bin 208917 -> 201255 bytes .../LibLinphoneTester-wp8.csproj.user | 22 ------------------ .../LibLinphoneTester.vcxproj | 1 + 5 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 65ad06dc8..6d8974c3d 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -125,7 +125,7 @@ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false false - Sync + Async
Console diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters index 23a8a72b9..bc95616ad 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters @@ -35,6 +35,7 @@ + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo index 88762f6d7aaabcff0c5251ff41bbd500301bcc36..abd949b4c4ca1a801713480ec26a0d3094b7281d 100644 GIT binary patch delta 22160 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 KYqh+2nav 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

cn_hK=W?P%085dt04=o!Z^E~QZ(QvCvHI$P z@4a;68yC&7Z}DYBzZY_*;_&;OqR+YK&+PR}wGcaVSTS>wI$`C~iWVQ0r*ktiE<={_Np~uq4TBS!VeLKPKEByLKB^e9oqfjr?+*{& zZfH5Z^n0J&OG>4qINJsf%Z5o4%E{$hHw@ZQQ)o@97FH z%ClGbXi``9rm3lxoAS$Rlxs<+NujJYuBBzwZaP%`VihAg89w?fjZr(oT06$Hl)bvp z_FsA?_&pK&MQP@u)$Pba)rwnbg=7E9uX$8xds4CFjM&@tqh^JCPl!a~<9g>fX7Y t-rDdvv6n~PZW%m?>LlmXtaS%PH@bWH^@B&0v~}El_#-qL?Nid}{{tw%SOow8 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user deleted file mode 100644 index 96fe30de2..000000000 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj.user +++ /dev/null @@ -1,22 +0,0 @@ - - - - 256 - 30F105C9-681E-420b-A277-7C086EAD8A4E - - - 256 - 30F105C9-681E-420b-A277-7C086EAD8A4E - - - - - - False - Managed - False - - - - - \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj index 4e515921e..cf408958e 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -97,6 +97,7 @@ NotUsing $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false + Async Console From d6d10d60c7baf9c7e2a5a57f0b44c6063ebea1db Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 12 Mar 2013 21:33:40 +0100 Subject: [PATCH 128/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 06e505707..28c3383b5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 06e505707c31d11e056f2dad4de3ac617985333b +Subproject commit 28c3383b5e98196ab394f6616f11c195e6759d28 From 7a453c5935030fca1fdaa6b58ddbf641c82b348c Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 13 Mar 2013 10:20:41 +0100 Subject: [PATCH 129/909] Add rtp config for disabling upnp for rtp streams --- coreapi/linphonecall.c | 18 +++++++++++------- coreapi/linphonecore.c | 1 + coreapi/private.h | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a7cad386c..dba7381c7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -484,7 +484,9 @@ 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; @@ -558,12 +560,14 @@ 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) { + 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); + } } } #endif //BUILD_UPNP diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2bb9fab32..b704347da 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -751,6 +751,7 @@ 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); } static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ diff --git a/coreapi/private.h b/coreapi/private.h index 78344ee70..13087dc04 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -459,6 +459,7 @@ typedef struct rtp_config int audio_jitt_comp; /*jitter compensation*/ int video_jitt_comp; /*jitter compensation*/ int nortp_timeout; + int disable_upnp; bool_t rtp_no_xmit_on_audio_mute; /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; From c4863d8f8060ada6501bad31d72d3abc5d4d2f55 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 13 Mar 2013 12:05:45 +0100 Subject: [PATCH 130/909] Expand row in calllog --- gtk/calllogs.c | 46 ++++++++++++++++++++++++++-------------------- gtk/friendlist.c | 3 ++- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 9e703a8ff..45a616119 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -22,7 +22,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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); @@ -34,27 +35,27 @@ static void fill_renderers(GtkTreeView *v){ 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; - 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); 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"))); // 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); + 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); const char *display; - gchar *logtxt, *minutes, *seconds; + gchar *logtxt, *headtxt, *minutes, *seconds; gchar quality[20]; const char *status=NULL; gchar *start_date=NULL; @@ -99,28 +100,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); + gtk_tree_store_append (store,&iter,NULL); GdkPixbuf *incoming = create_pixbuf("call_status_incoming.png"); GdkPixbuf *outgoing = create_pixbuf("call_status_outgoing.png"); - gtk_list_store_set (store,&iter, + gtk_tree_store_set (store,&iter, 0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming, - 1, logtxt,2,la,-1); + 1, headtxt,2,la,-1); + gtk_tree_store_append (store,&iter2,&iter); + gtk_tree_store_set (store,&iter2,1,logtxt,2,la,-1); ms_free(addr); g_free(logtxt); + g_free(headtxt); } } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index fc2c2f4b5..be6a4c3ce 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -581,12 +581,13 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ gtk_tree_view_column_set_max_width(column,60); gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); + /* Call column*/ renderer = gtk_cell_renderer_pixbuf_new(); 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); From 2f80cd6ed1aa587183f63fcdd8f56f74b83d8f53 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Mar 2013 13:04:48 +0100 Subject: [PATCH 131/909] ad linphone_proxy_config_get_transport --- .gitignore | 2 +- Makefile.am | 4 ++-- coreapi/bellesip_sal/sal_address_impl.c | 2 +- coreapi/linphonecore.h | 7 +++++++ coreapi/proxy.c | 22 +++++++++++++++++++++ tester/register_tester.c | 26 ++++++++++++++++++++----- 6 files changed, 54 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index df1c80316..9dd415435 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,4 @@ coreapi/help/registration coreapi/test_ecc coreapi/test_lsd gtk/version_date.h - +specs.c diff --git a/Makefile.am b/Makefile.am index 37046726b..44ed0c07b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -230,6 +230,6 @@ bundle: $(LIBICONV_HACK) clean-local: rm -rf $(BUNDLEDIR) discovery: - touch specs.cpp + touch specs.c $(CC) --include $(top_builddir)/config.h \ - $(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS) -E -P -v -dD specs.cpp + $(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS) -E -P -v -dD specs.c diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 5c210878c..c7a2603ca 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -85,7 +85,7 @@ int sal_address_get_port_int(const SalAddress *addr){ SalTransport sal_address_get_transport(const SalAddress* addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - if (uri) { + if (uri && belle_sip_uri_get_transport_param(uri)) { return sal_transport_parse(belle_sip_uri_get_transport_param(uri)); } else return SalTransportUDP; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 58b9179a5..3de3ddae0 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -539,6 +539,13 @@ 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); +/* + * return the transport from either : service route, route, or addr + * @returns cfg object + * @return transport as string (I.E udp, tcp, tls, dtls)*/ + +LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg); + /* destruction is called automatically when removing the proxy config */ void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 2917d14b7..909500e59 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1322,3 +1322,25 @@ void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason err 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; +} diff --git a/tester/register_tester.c b/tester/register_tester.c index 0ff192682..68a287079 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -263,7 +263,17 @@ static void network_state_change(){ wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); linphone_core_destroy(lc); } - +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(){ LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -271,21 +281,25 @@ static void transport_change(){ stats* counters ; LCSipTransports sip_tr; LCSipTransports sip_tr_orig; - memset(&sip_tr,0,sizeof(sip_tr)); + int number_of_udp_proxy=0; + memset(&sip_tr,0,sizeof(sip_tr)); memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); counters = (stats*)linphone_core_get_user_data(lc); register_ok=counters->number_of_LinphoneRegistrationOk; + + number_of_udp_proxy=get_number_of_udp_proxy(lc); linphone_core_get_sip_transports(lc,&sip_tr_orig); + sip_tr.udp_port=sip_tr_orig.udp_port; /*keep only udp*/ linphone_core_set_sip_transports(lc,&sip_tr); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+2)); + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(ms_list_size(proxys)-number_of_udp_proxy))); linphone_core_destroy(lc); } @@ -295,15 +309,17 @@ static void io_recv_error(){ LinphoneCore* lc; int register_ok; stats* counters ; + int number_of_udp_proxy=0; memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); counters = (stats*)linphone_core_get_user_data(lc); register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); sal_set_recv_error(lc->sal, 0); - CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-1 /*because 1 udp*/)); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-number_of_udp_proxy /*because 1 udp*/)); sal_set_recv_error(lc->sal, 1); /*reset*/ linphone_core_destroy(lc); From afa3a843712e379aeba6af3493349e361956bcdf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Mar 2013 13:12:58 +0100 Subject: [PATCH 132/909] fix compilation issue --- tester/register_tester.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tester/register_tester.c b/tester/register_tester.c index 68a287079..cf735a183 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -282,7 +282,7 @@ static void transport_change(){ LCSipTransports sip_tr; LCSipTransports sip_tr_orig; int number_of_udp_proxy=0; - + int total_number_of_proxies; memset(&sip_tr,0,sizeof(sip_tr)); memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; @@ -291,6 +291,7 @@ static void transport_change(){ 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; @@ -299,7 +300,7 @@ static void transport_change(){ linphone_core_set_sip_transports(lc,&sip_tr); CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(ms_list_size(proxys)-number_of_udp_proxy))); + CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(total_number_of_proxies-number_of_udp_proxy))); linphone_core_destroy(lc); } From c87046dcdf1e610a32fbda83b7d52fec0ff3f8a3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Mar 2013 15:33:55 +0100 Subject: [PATCH 133/909] More exports --- coreapi/linphonecore.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 3de3ddae0..4753588b4 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -517,8 +517,8 @@ LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *obj); * */ 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); +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); @@ -529,10 +529,10 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphonePro 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); +LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC 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); @@ -555,7 +555,7 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); /** * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 */ -int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); +LINPHONE_PUBLIC int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); /* * attached a user data to a proxy config */ @@ -1032,9 +1032,9 @@ LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(Linphone LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -void linphone_core_clear_proxy_config(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc); -void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); @@ -1054,7 +1054,7 @@ const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const cha 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); From 1ded56464cf6fcd07b6f6d271a85264c78b67751 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 13 Mar 2013 15:45:13 +0100 Subject: [PATCH 134/909] un init sip early in linphone uninit --- coreapi/linphonecore.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6612bd2df..a971f38ff 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5339,15 +5339,14 @@ static void linphone_core_uninit(LinphoneCore *lc) 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); sound_config_uninit(lc); video_config_uninit(lc); codecs_config_uninit(lc); - ui_config_uninit(lc); - sip_config_uninit(lc); - sip_setup_unregister_all(); From 0c56e7c8eae0abc7a887e26606772c2e2403e6f5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 14 Mar 2013 08:33:48 +0100 Subject: [PATCH 135/909] betetr call tester tracing --- tester/call_tester.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 1bcc30968..6aaf388c8 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -28,7 +28,10 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState 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("call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(cstate)); + 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 = (stats*)linphone_core_get_user_data(lc); @@ -418,8 +421,8 @@ static void simple_conference(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000)); CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) From 02b05eede44d91ea46d04cb78814c85144aaf675 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 14 Mar 2013 12:47:29 +0100 Subject: [PATCH 136/909] More exports + disable upnp test suite for wp --- coreapi/linphonecore.h | 12 ++++++------ tester/liblinphone_tester.c | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4753588b4..a4a950488 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -559,11 +559,11 @@ LINPHONE_PUBLIC int linphone_proxy_config_normalize_number(LinphoneProxyConfig * /* * attached a user data to a proxy config */ -void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud); +LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud); /* * get user data to a proxy config. return null if any */ -void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); +LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); /** * @} @@ -697,11 +697,11 @@ LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const Linphone LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); -const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); -const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); -void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); -const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); +LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index b7ffea485..2b400c0f0 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -275,7 +275,9 @@ void liblinphone_tester_init(void) { add_test_suite(&call_test_suite); add_test_suite(&message_test_suite); add_test_suite(&presence_test_suite); +#ifdef UPNP add_test_suite(&upnp_test_suite); +#endif } void liblinphone_tester_uninit(void) { From e1552ee1eef40ca9efeb0e814223cff17e580462 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Mar 2013 13:27:53 +0100 Subject: [PATCH 137/909] add automatic tone user indications --- coreapi/callbacks.c | 8 +++-- coreapi/conference.c | 4 +-- coreapi/ec-calibrator.c | 11 ++++--- coreapi/linphonecall.c | 3 +- coreapi/linphonecore.c | 69 ++++++++++++++++++++++++++++++++++++----- coreapi/lpconfig.c | 5 ++- coreapi/misc.c | 3 ++ coreapi/private.h | 12 +++++++ mediastreamer2 | 2 +- 9 files changed, 98 insertions(+), 19 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index dd5ab7edc..8a6ea631c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -151,7 +151,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia 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*/ + /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ linphone_call_init_media_streams (call); } if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ @@ -163,6 +163,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia } linphone_call_start_media_streams(call,all_muted,send_ringbacktone); } + if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ + linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); + } } #if 0 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ @@ -654,6 +657,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } else if (sr == SalReasonBusy) { call->reason=LinphoneReasonBusy; linphone_call_set_state(call,LinphoneCallError,"User is busy."); + linphone_core_play_named_tone(lc,LinphoneToneBusy); } else { linphone_call_set_state(call,LinphoneCallError,msg); } @@ -809,7 +813,7 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ } if (call->state!=LinphoneCallPaused){ ms_message("Automatically pausing current call to accept transfer."); - linphone_core_pause_call(lc,call); + _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. diff --git a/coreapi/conference.c b/coreapi/conference.c index 16be62613..c9d51b151 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -240,7 +240,7 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a err=linphone_core_update_call(lc,call,&call->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; @@ -339,7 +339,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); } LinphoneConference *conf=&lc->conf_ctx; if (conf->local_participant==NULL) add_local_endpoint(conf,lc); diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 8efbabb1b..e19559fc4 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -133,6 +133,9 @@ 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); @@ -161,7 +164,7 @@ 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; @@ -172,17 +175,17 @@ static void ecc_play_tones(EcCalibrator *ecc){ /* 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); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dba7381c7..6c01c65bd 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2114,7 +2114,7 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ if (from) { snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from); - free(from); + ms_free(from); } else { @@ -2123,6 +2123,7 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ if (lc->vtable.display_warning!=NULL) lc->vtable.display_warning(lc,temp); linphone_core_terminate_call(lc,call); + linphone_core_play_named_tone(lc,LinphoneToneCallFailed); } static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b704347da..a2c910064 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2118,9 +2118,10 @@ void linphone_core_iterate(LinphoneCore *lc){ ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); + LinphoneReason decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; call->reason=LinphoneReasonNotAnswered; - linphone_core_terminate_call(lc,call); + linphone_core_decline_call(lc,call,decline_reason); } } if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { @@ -2754,7 +2755,7 @@ 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"); @@ -3305,8 +3306,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; } @@ -3316,7 +3316,14 @@ 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; @@ -3354,6 +3361,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) lc->vtable.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; } @@ -3367,7 +3375,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; @@ -3382,7 +3390,11 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ 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){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; } } @@ -4905,13 +4917,54 @@ void linphone_core_play_tone(LinphoneCore *lc){ ms_error("No dtmf generator at this time !"); return; } + memset(&def,0,sizeof(def)); def.duration=300; - def.frequency=500; + def.frequencies[0]=500; def.amplitude=1; def.interval=2000; ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); } +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ + if (linphone_core_tone_indications_enabled(lc)){ + 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 LinphoneToneCallFailed: + 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); + } +} + /** * @ingroup media_parameters * diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 4608beecf..db4e5de5c 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -190,6 +190,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ if (pos2-pos1>=0){ /* found a pair key,value */ + if (cur!=NULL){ LpItem *item=lp_section_find_item(cur,key); if (item==NULL){ @@ -198,7 +199,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ ms_free(item->value); item->value=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"); } @@ -212,6 +213,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ LpConfig * lp_config_new(const char *filename){ LpConfig *lpconfig=lp_new0(LpConfig,1); if (filename!=NULL){ + ms_message("Using (r/w) config information from %s", filename); lpconfig->filename=ortp_strdup(filename); lpconfig->file=fopen(filename,"rw"); if (lpconfig->file!=NULL){ @@ -237,6 +239,7 @@ LpConfig * lp_config_new(const char *filename){ int lp_config_read_file(LpConfig *lpconfig, const char *filename){ FILE* f=fopen(filename,"r"); if (f!=NULL){ + ms_message("Reading config information from %s", filename); lp_config_parse(lpconfig,f); fclose(f); return 0; diff --git a/coreapi/misc.c b/coreapi/misc.c index e84c8cce9..d101bb2c4 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1005,6 +1005,9 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){ 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 diff --git a/coreapi/private.h b/coreapi/private.h index 13087dc04..5e265c616 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -211,6 +211,7 @@ struct _LinphoneCall bool_t was_automatically_paused; bool_t ping_replied; bool_t record_active; + bool_t paused_by_app; }; @@ -678,6 +679,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. @@ -718,6 +721,15 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); +typedef enum _LinphoneToneID{ + LinphoneToneBusy, + LinphoneToneCallWaiting, + LinphoneToneCallOnHold, + LinphoneToneCallFailed +}LinphoneToneID; +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); +bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); + #ifdef __cplusplus } #endif diff --git a/mediastreamer2 b/mediastreamer2 index 28c3383b5..d1d3e1af5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 28c3383b5e98196ab394f6616f11c195e6759d28 +Subproject commit d1d3e1af51ab26ecb9808d6f83629e661c67af5f From e798d0dc6544ff27afaccc3d6de8d36712c6f229 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Mar 2013 14:32:28 +0100 Subject: [PATCH 138/909] fix uninitialized and unused variables --- coreapi/linphonecore.c | 2 +- coreapi/proxy.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a971f38ff..64baf7ef4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2328,7 +2328,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , #endif LinphoneAddress *ctt=NULL; #ifdef USE_BELLESIP - LinphoneAddress *ret; + LinphoneAddress *ret=NULL; #else char* ret; #endif diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 909500e59..aaf851e9f 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -272,7 +272,6 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ const char *localip = NULL; char *tmp; - LCSipTransports tr; LinphoneAddress *contact=linphone_address_new(obj->reg_identity); if (obj->contact_params) @@ -293,6 +292,7 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ #ifdef BUILD_UPNP if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp && linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) { + LCSipTransports tr; localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp); localport = linphone_upnp_context_get_external_port(obj->lc->upnp); linphone_core_get_sip_transports(obj->lc,&tr); @@ -316,12 +316,15 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ if(localport == -1) { localport = linphone_core_get_sip_port(obj->lc); } - 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"); + { + LCSipTransports tr; + linphone_core_get_sip_transports(obj->lc,&tr); + if (tr.udp_port <= 0) { + if (tr.tcp_port>0) { + sal_address_set_param(contact,"transport","tcp"); + } else if (tr.tls_port>0) { + sal_address_set_param(contact,"transport","tls"); + } } } #endif From 9c60087e5596935c2dbcf4072b710062977c1736 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Mar 2013 15:46:09 +0100 Subject: [PATCH 139/909] fix build issue and add a --silent option to tester (no warning, no errors, only fatal) --- tester/liblinphone_tester.c | 5 ++++- tester/upnp_tester.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 2b400c0f0..efe8f9a5e 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -372,11 +372,12 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, void helper(const char *name) { fprintf(stderr,"%s \t--help\n" "\t\t\t--verbose\n" + "\t\t\t--silent\n" "\t\t\t--list-suites\n" "\t\t\t--list-tests \n" "\t\t\t--config \n" "\t\t\t--domain \n" - "\t\t\t---auth-domain \n" + "\t\t\t--auth-domain \n" #if HAVE_CU_GET_SUITE "\t\t\t--suite \n" "\t\t\t--test \n" @@ -412,6 +413,8 @@ int main (int argc, char *argv[]) { #else linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); #endif + } else if (strcmp(argv[i],"--silent")==0){ + ortp_set_log_level_mask(ORTP_FATAL); } else if (strcmp(argv[i],"--domain")==0){ CHECK_ARG("--domain", ++i, argc); test_domain=argv[i]; diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c index 95a132e62..f407808ac 100644 --- a/tester/upnp_tester.c +++ b/tester/upnp_tester.c @@ -27,7 +27,9 @@ static void upnp_start_n_stop(void) { int tmp = 0; LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); +#ifdef BUILD_UPNP CU_ASSERT_TRUE(lc_upnp->lc->upnp != NULL); +#endif linphone_core_manager_destroy(lc_upnp); } From 4ee33b2459883210b6ea53aded805483ec3c50a8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 14 Mar 2013 18:01:26 +0100 Subject: [PATCH 140/909] Added missing export --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a4a950488..d3d417c7b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -404,7 +404,7 @@ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); LINPHONE_PUBLIC void linphone_call_send_vfu_request(LinphoneCall *call); LINPHONE_PUBLIC void *linphone_call_get_user_pointer(LinphoneCall *call); -void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); +LINPHONE_PUBLIC void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); @@ -1365,7 +1365,7 @@ 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); From 992ff8dd1dfae7acca43569fa5034960b81c1fed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Mar 2013 10:19:41 +0100 Subject: [PATCH 141/909] Fix bug with the keywordcmp macro. This macro was supposed to be passed a string literal as first argument but was used with a string pointer sometimes. --- coreapi/sal_eXosip2_sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 9297077e6..debd8550f 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal.h" #include -#define keywordcmp(key,b) strncmp(key,b,sizeof(key)) +#define keywordcmp(key,b) strcmp(key,b) #ifdef FOR_LATER From 3fcbf5340cdf96ea5aae414359e20ebabb41fce2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 15 Mar 2013 11:28:03 +0100 Subject: [PATCH 142/909] add libiconv patch and document it. --- README.macos | 16 ++++++++++++++++ build/macos/libiconv-macos.patch | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 build/macos/libiconv-macos.patch diff --git a/README.macos b/README.macos index bb78575bf..dd39c2f6e 100644 --- a/README.macos +++ b/README.macos @@ -99,4 +99,20 @@ For a better appearance, you can install the gtk-quartz-engine (a gtk theme) tha Generate a new bundle to have it included. +libiconv hack +************* + +The Makefile.am rules used to generate the bundle fetch a libiconv.2.dylib from a linphone download page. +This library adds some additional symbols so that dependencies requiring the iconv from /usr/lib and the ones requiring from the bundle are both satisfied. +In case this library needs to generated, here are the commands: + $ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz + $ cd libiconv-1.14 + $ patch -p1 < ../linphone/build/macos/libiconv-macos.patch + $ ./configure --prefix=/opt/local --disable-static 'CFLAGS=-arch i386 -arch x86_64 -mmacosx-version-min=10.5' 'LDFLAGS=-arch i386 -arch x86_64 -mmacosx-version-min=10.5' CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" && make + $ make install DESTDIR=/tmp + +The resulted library can be found in /tmp/opt/local/lib + + + 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 From 0666c4e41f1d0d940f7ab826454a973833a593a5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Mar 2013 12:14:50 +0100 Subject: [PATCH 143/909] More linphonecore exports --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 64baf7ef4..d979c8700 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4993,7 +4993,7 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ return; } - if (duration_ms>0) + if (duration_ms > 0) ms_filter_call_method(f, MS_DTMF_GEN_PLAY, &dtmf); else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d3d417c7b..84aa16932 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -394,7 +394,7 @@ bool_t linphone_call_camera_enabled(const LinphoneCall *lc); int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); const char *linphone_call_get_remote_user_agent(LinphoneCall *call); -const char *linphone_call_get_remote_contact(LinphoneCall *call); +LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call); float linphone_call_get_play_volume(LinphoneCall *call); float linphone_call_get_record_volume(LinphoneCall *call); float linphone_call_get_current_quality(LinphoneCall *call); @@ -1299,8 +1299,8 @@ 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); -void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); -void linphone_core_stop_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); +LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); int linphone_core_get_current_call_duration(const LinphoneCore *lc); From bd0d64193ca5506eb8c8e386c4cf205236288829 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 15 Mar 2013 14:16:23 +0100 Subject: [PATCH 144/909] Check upnp version --- configure.ac | 7 ++++++- mediastreamer2 | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index ae2d59386..4957eeb58 100644 --- a/configure.ac +++ b/configure.ac @@ -183,7 +183,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 diff --git a/mediastreamer2 b/mediastreamer2 index d1d3e1af5..f223705f2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d1d3e1af51ab26ecb9808d6f83629e661c67af5f +Subproject commit f223705f2853e62f0fb5340b994cd40665b9e854 From c073694686234d7261b3fb2461c7f31fd7d17177 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 15 Mar 2013 14:31:12 +0100 Subject: [PATCH 145/909] Add upnp notice in README --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 05b0b1dcb..658f07ae0 100644 --- a/README +++ b/README @@ -16,7 +16,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - libswscale (part of ffmpeg too) for better scaling performance - theora (optional) + if you want uPnP support: - - libupnp + - libupnp (version 1.6 branch (not patched with 18-url-upnpstrings.patch)) with their corresponding -dev or -devel package if you don't use source packages. From 4c3cbd750ff86c9686c3e6dc29a1f4916f3d94b7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Mar 2013 14:45:15 +0100 Subject: [PATCH 146/909] More exports --- coreapi/linphonecore.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 84aa16932..d317c2679 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -948,7 +948,7 @@ LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *l LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); -void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); +LINPHONE_PUBLIC void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); @@ -1221,13 +1221,13 @@ 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); +LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); /** * return mic state. * * @ingroup media_parameters **/ -bool_t linphone_core_is_mic_muted(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_is_mic_muted(LinphoneCore *lc); bool_t linphone_core_is_rtp_muted(LinphoneCore *lc); @@ -1319,7 +1319,7 @@ 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 From d819cf6b36468687dee85b24499368388e26a58f Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 15 Mar 2013 15:52:03 +0100 Subject: [PATCH 147/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f223705f2..07824fcf3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f223705f2853e62f0fb5340b994cd40665b9e854 +Subproject commit 07824fcf3879d265c59beaf970d833b5859f3691 From 42f23a4d6c6a349335185ad38ab1c8eadadc898a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Mar 2013 16:02:35 +0100 Subject: [PATCH 148/909] Do not create ICE check list for non-active streams. It may lead to some crashes if a check list exists for a non-active stream. --- coreapi/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index d101bb2c4..35a58e200 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -876,7 +876,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, 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) { + 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) { From 3614a46aa052e053959229c85b6a66c7236d7a48 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Mar 2013 16:51:48 +0100 Subject: [PATCH 149/909] Exports again --- coreapi/linphonecore.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d317c2679..5a327b7c1 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -104,7 +104,7 @@ 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 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); @@ -160,23 +160,23 @@ enum LinphoneMediaEncryption { 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); -LinphoneCallStatus linphone_call_log_video_enabled(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); +LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl); +LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_video_enabled(LinphoneCallLog *cl); +LINPHONE_PUBLIC time_t linphone_call_log_get_start_date(LinphoneCallLog *cl); +LINPHONE_PUBLIC int linphone_call_log_get_duration(LinphoneCallLog *cl); +LINPHONE_PUBLIC float linphone_call_log_get_quality(LinphoneCallLog *cl); +LINPHONE_PUBLIC void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up); +LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl); +LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl); struct _LinphoneCallParams; @@ -377,16 +377,16 @@ LinphoneCore *linphone_call_get_core(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call); bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); -const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); -char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); -LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); +LINPHONE_PUBLIC char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCall * linphone_call_ref(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_unref(LinphoneCall *call); LINPHONE_PUBLIC LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); const char *linphone_call_get_refer_to(const LinphoneCall *call); bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); -int linphone_call_get_duration(const LinphoneCall *call); +LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); From dc827a4bfd6c5bdf4b2e42036f72c8dea01673ea Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 18 Mar 2013 09:01:44 +0100 Subject: [PATCH 150/909] update ms2 with compilation fix for upnp --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 07824fcf3..45c9c6516 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 07824fcf3879d265c59beaf970d833b5859f3691 +Subproject commit 45c9c65168a9912bd2aa97344b396771ff1cdaf0 From 1b7ed3a9c42b9d35413caa66b375cb230478e6e4 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Mon, 18 Mar 2013 15:58:05 +0100 Subject: [PATCH 151/909] Send ZRTP hello hash in SIP SDP. --- coreapi/linphonecall.c | 41 ++++++++++++++++++++++++++++++--------- coreapi/linphonecore.c | 8 +++++++- coreapi/offeranswer.c | 1 + coreapi/sal.h | 3 ++- coreapi/sal_eXosip2_sdp.c | 28 +++++++++++++++++++++++--- mediastreamer2 | 2 +- oRTP | 2 +- 7 files changed, 69 insertions(+), 16 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6c01c65bd..e9640701f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -254,6 +254,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * l=ms_list_append(l,pt); md->streams[0].payloads=l; + // if ZRTP is enabled, put the hello hash into the audiostream's desc + if (call->audiostream && call->audiostream->ms.zrtp_context!=NULL){ + ortp_zrtp_get_hello_hash(call->audiostream->ms.zrtp_context, + md->streams[0].zrtp_hello_hash, + sizeof(md->streams[0].zrtp_hello_hash)); + ms_message("Audio stream zrtp hash: %s", md->streams[0].zrtp_hello_hash); + } + if (call->params.has_video){ md->n_active_streams++; md->streams[1].rtp_port=call->video_port; @@ -262,6 +270,13 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; + // if ZRTP is enabled, put the hello hash into the audiostream's desc + if (call->videostream->ms.zrtp_context!=NULL){ + ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context, + md->streams[1].zrtp_hello_hash, + sizeof(md->streams[1].zrtp_hello_hash)); + ms_message("Video stream zrtp hash: %s", md->streams[1].zrtp_hello_hash); + } } if (md->n_total_streams < md->n_active_streams) md->n_total_streams = md->n_active_streams; @@ -1294,6 +1309,20 @@ void linphone_call_init_video_stream(LinphoneCall *call){ void linphone_call_init_media_streams(LinphoneCall *call){ linphone_call_init_audio_stream(call); linphone_call_init_video_stream(call); + + // moved from linphone_call_start_media_streams, because ZRTP needs to be + // at least partially initialized so that the SDP can contain 'zrtp-hash' + if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { + OrtpZrtpParams params; + /*will be set later when zrtp is activated*/ + call->current_params.media_encryption=LinphoneMediaEncryptionNone; + + params.zid_file=call->core->zrtp_secrets_cache; + 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; + } } @@ -1736,16 +1765,10 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut call->playing_ringbacktone=send_ringbacktone; call->up_bw=linphone_core_get_upload_bandwidth(lc); + // ZRTP was initialized in linphone_call_init_media_streams with a + // partially iniitalized RtpSession, and now needs to get an update if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { - OrtpZrtpParams params; - /*will be set later when zrtp is activated*/ - call->current_params.media_encryption=LinphoneMediaEncryptionNone; - - params.zid_file=lc->zrtp_secrets_cache; - 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; + ortp_zrtp_start_engine(call->audiostream->ms.zrtp_context,call->audiostream->ms.session); } /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a2c910064..431d3e37c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3125,8 +3125,14 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, sal_call_set_local_media_description(call->op,call->localdesc); } - if (call->audiostream==NULL) + if (call->audiostream==NULL){ linphone_call_init_media_streams(call); + // the local media description must be regenerated after the audiostream + // is initialized, otherwise the ZRTP hello hash will not be available + linphone_call_make_local_media_description(lc,call); + sal_call_set_local_media_description(call->op,call->localdesc); + } + if (!was_ringing && call->audiostream->ms.ticker==NULL){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 9823c24a6..eefe34d45 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -261,6 +261,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->ice_completed = local_cap->ice_completed; memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); + memcpy(result->zrtp_hello_hash,local_cap->zrtp_hello_hash, sizeof(result->zrtp_hello_hash)); } /** diff --git a/coreapi/sal.h b/coreapi/sal.h index 25d8d20bc..5f38c15ab 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -140,7 +140,7 @@ typedef struct SalIceRemoteCandidate { } SalIceRemoteCandidate; #define SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES 2 - +#define SAL_MEDIA_DESCRIPTION_MAX_ZRTP_HELLO_HASH 128 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 @@ -172,6 +172,7 @@ typedef struct SalStreamDescription{ SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES]; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; + char zrtp_hello_hash[SAL_MEDIA_DESCRIPTION_MAX_ZRTP_HELLO_HASH]; bool_t ice_mismatch; bool_t ice_completed; } SalStreamDescription; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index debd8550f..139446448 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -108,6 +108,17 @@ static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ return 0; } +static char * _sdp_message_get_a_zrtp_hash(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("zrtp-hash",attr->a_att_field)==0){ + return attr->a_att_value; + } + } + return NULL; +} + static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ int i; sdp_attribute_t *attr; @@ -337,6 +348,11 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription int_2char(desc->bandwidth)); if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), int_2char(desc->ptime)); + + // if the ZRTP hello hash is available, create an a attribute for it + if (desc->zrtp_hello_hash[0]) + sdp_message_a_attribute_add(msg,lineno,osip_strdup("zrtp-hash"), osip_strdup(desc->zrtp_hello_hash)); + strip_well_known_rtpmaps=ms_list_size(desc->payloads)>5; if (desc->payloads){ for(elem=desc->payloads;elem!=NULL;elem=elem->next){ @@ -433,7 +449,7 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ 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 *mtype,*proto,*rtp_port,*rtp_addr,*number,*zrtp_info; const char *sess; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; @@ -490,7 +506,12 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ stream->rtp_port=atoi(rtp_port); if (stream->rtp_port > 0) desc->n_active_streams++; - + + // if the SDP contains a zrtp-hash, add it to the StreamDesc + zrtp_info = _sdp_message_get_a_zrtp_hash(msg, i); + if (zrtp_info != NULL) + strncpy(stream->zrtp_hello_hash, zrtp_info, sizeof(stream->zrtp_hello_hash)); + stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ stream->type=SalAudio; @@ -528,7 +549,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ 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); + // added bounds check + int nb = sscanf(attr->a_att_value, "%d IN IP4 %256s", &stream->rtcp_port, tmp); if (nb == 1) { /* SDP rtcp attribute only contains the port */ } else if (nb == 2) { diff --git a/mediastreamer2 b/mediastreamer2 index 07824fcf3..45c9c6516 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 07824fcf3879d265c59beaf970d833b5859f3691 +Subproject commit 45c9c65168a9912bd2aa97344b396771ff1cdaf0 diff --git a/oRTP b/oRTP index 20b527144..c702c0ea0 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 20b527144f9850dd9065d96db7a20244e8a8b227 +Subproject commit c702c0ea0e66bbe1f27c79690003d9748b01560f From c5f239101b2d2b0c480fdca8f3d37a7d7840bc65 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 18 Mar 2013 19:32:38 +0100 Subject: [PATCH 152/909] implement minimal prack support --- coreapi/bellesip_sal/sal_op_call.c | 16 ++++- coreapi/linphonecall.c | 80 ++++++++++++++++++++++++ coreapi/linphonecore.c | 99 ++---------------------------- coreapi/linphonecore.h | 6 +- coreapi/private.h | 3 +- coreapi/proxy.c | 40 +++++++++++- 6 files changed, 143 insertions(+), 101 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2b484ac18..061fe1d87 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -352,6 +352,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_server_transaction_send_response(server_transaction ,belle_sip_response_create_from_request(req,481)); } + } else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) { + resp=belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); } else { belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); unsupported_method(server_transaction,req); @@ -495,10 +498,21 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon } int sal_call_notify_ringing(SalOp *op, bool_t early_media){ int status_code =early_media?183:180; - belle_sip_response_t* ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status_code); + belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); + belle_sip_response_t* ringing_response = belle_sip_response_create_from_request(req,status_code); if (early_media){ handle_offer_answer_response(op,ringing_response); } + /*fixme it should support PRACK in the right way*/ + if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require")) { + belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); + belle_sip_header_contact_t* contact_header; + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_message_get_header((belle_sip_message_t*)req,"Require")); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1"))); + 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; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index fd92ba42e..1f8a288b0 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2420,3 +2420,83 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } +#ifndef USE_BELLESIP +static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ +#else +static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ +#endif + LinphoneAddress *ctt=NULL; +#ifdef USE_BELLESIP + LinphoneAddress *ret=NULL; +#else + char* ret; +#endif + const char *localip=call->localip; + + /* first use user's supplied ip address if asked*/ + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ + ctt=linphone_core_get_primary_contact_parsed(lc); + linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); + #ifdef USE_BELLESIP + ret=ctt; + #else + ret=linphone_adress_as_string(ctt); + #endif + } else if (call->op && sal_op_get_contact(call->op)!=NULL){ + /* if already choosed, don't change it */ + return NULL; + } else if (call->ping_op && sal_op_get_contact(call->ping_op)) { + /* if the ping OPTIONS request succeeded use the contact guessed from the + received, rport*/ + ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; +#else + ret=ms_strdup(sal_op_get_contact(call->ping_op)); +#endif + } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(dest_proxy->op)){ + /*if using a proxy, use the contact address as guessed with the REGISTERs*/ + ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); +#else + ret=ms_strdup(sal_op_get_contact(dest_proxy->op)); +#endif + } else { + ctt=linphone_core_get_primary_contact_parsed(lc); + if (ctt!=NULL){ + /*otherwise use supllied localip*/ + linphone_address_set_domain(ctt,localip); + linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); + ms_message("Contact has been fixed using local ip"/* to %s",ret*/); +#ifdef USE_BELLESIP + ret=ctt; +#else + ret=linphone_address_as_string_uri_only(ctt); +#endif + } + } +#ifndef USE_BELLESIP + if (ctt) linphone_address_destroy(ctt); +#endif + return ret; + + +} + +void linphone_call_set_contact_op(LinphoneCall* call) { +#ifndef USE_BELLESIP + char *contact; +#else + LinphoneAddress *contact; +#endif + contact=get_fixed_contact(call->core,call,call->dest_proxy); + if (contact){ + sal_op_set_contact(call->op, contact); +#ifndef USE_BELLESIP + ms_free(contact); +#else + linphone_address_destroy(contact); +#endif +} +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5ea3fb763..36ac9eed2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2323,69 +2323,7 @@ const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAdd } return linphone_core_get_primary_contact (lc); } -#ifndef USE_BELLESIP -static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#else -static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#endif - LinphoneAddress *ctt=NULL; -#ifdef USE_BELLESIP - LinphoneAddress *ret=NULL; -#else - char* ret; -#endif - const char *localip=call->localip; - /* first use user's supplied ip address if asked*/ - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ - ctt=linphone_core_get_primary_contact_parsed(lc); - linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); - #ifdef USE_BELLESIP - ret=ctt; - #else - ret=linphone_adress_as_string(ctt); - #endif - } else if (call->op && sal_op_get_contact(call->op)!=NULL){ - /* if already choosed, don't change it */ - return NULL; - } else if (call->ping_op && sal_op_get_contact(call->ping_op)) { - /* if the ping OPTIONS request succeeded use the contact guessed from the - received, rport*/ - ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); -#ifdef USE_BELLESIP - ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; -#else - ret=ms_strdup(sal_op_get_contact(call->ping_op)); -#endif - } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(dest_proxy->op)){ - /*if using a proxy, use the contact address as guessed with the REGISTERs*/ - ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); -#ifdef USE_BELLESIP - ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); -#else - ret=ms_strdup(sal_op_get_contact(dest_proxy->op)); -#endif - } else { - ctt=linphone_core_get_primary_contact_parsed(lc); - if (ctt!=NULL){ - /*otherwise use supllied localip*/ - linphone_address_set_domain(ctt,localip); - linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); - ms_message("Contact has been fixed using local ip"/* to %s",ret*/); -#ifdef USE_BELLESIP - ret=ctt; -#else - ret=linphone_address_as_string_uri_only(ctt); -#endif - } - } -#ifndef USE_BELLESIP - if (ctt) linphone_address_destroy(ctt); -#endif - return ret; - - -} int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ bool_t ice_ready = FALSE; @@ -2420,27 +2358,11 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ int err; -#ifndef USE_BELLESIP - char *contact; -#else - LinphoneAddress *contact; -#endif - 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); -#ifndef USE_BELLESIP - ms_free(contact); -#else - linphone_address_destroy(contact); -#endif + linphone_call_set_contact_op(call); - } linphone_core_stop_dtmf_stream(lc); linphone_call_init_media_streams(call); if (lc->ringstream==NULL) @@ -2838,6 +2760,8 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); if (call->state==LinphoneCallIncomingReceived){ + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ + linphone_call_set_contact_op(call); sal_call_notify_ringing(call->op,propose_early_media || ringback_tone!=NULL); if (propose_early_media || ringback_tone!=NULL){ @@ -3132,11 +3056,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { LinphoneProxyConfig *cfg=NULL; -#ifndef USE_BELLESIP - char *contact=NULL; -#else - LinphoneAddress *contact=NULL; -#endif SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; @@ -3190,16 +3109,8 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, 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); -#ifdef USE_BELLESIP - linphone_address_destroy(contact); -#else - ms_free(contact); -#endif - } + /*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); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5a327b7c1..0b547c52a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -51,14 +51,14 @@ typedef struct _LinphoneCore LinphoneCore; struct _LpConfig; -struct _LCSipTransports{ +typedef struct _LCSipTransports{ int udp_port; int tcp_port; int dtls_port; int tls_port; -}; +} LCSipTransports; + -typedef struct _LCSipTransports LCSipTransports; /** * Object that represents a SIP address. diff --git a/coreapi/private.h b/coreapi/private.h index dfa061c51..8645edbff 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -218,7 +218,7 @@ struct _LinphoneCall LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); - +void linphone_call_set_contact_op(LinphoneCall* call); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); void linphone_call_log_completed(LinphoneCall *call); @@ -230,6 +230,7 @@ void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo void linphone_core_update_proxy_register(LinphoneCore *lc); void linphone_core_refresh_subscribes(LinphoneCore *lc); int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error); +const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index aaf851e9f..1094f10f4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -344,14 +344,49 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ } return ret; } - +/*use for compatibility with linphone supporting only 1 transport at a time*/ +const char* guess_transport(const LinphoneProxyConfig *obj) { + LCSipTransports transports; + const char* transport_name; + unsigned char transports_count=0; + linphone_core_get_sip_transports(obj->lc,&transports); + if (transports.udp_port>0) { + transports_count++; + transport_name="udp"; + } + if (transports.tcp_port>0) { + transports_count++; + transport_name="tcp"; + } + if (transports.tls_port>0) { + transports_count++; + transport_name="tls"; + } + if (transports.dtls_port>0) { + transports_count++; + transport_name="dtls"; + } + if (transports_count==1) { + return transport_name; + } else { + /*cannot guess transport*/ + return NULL; + } +} static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ + LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); + char* proxy_string; #ifndef USE_BELLESIP char *contact; #else LinphoneAddress *contact; + if (guess_transport(obj) && !sal_address_get_transport((SalAddress*)proxy)) { + sal_address_set_transport((SalAddress*)proxy,sal_transport_parse(guess_transport(obj))); + } #endif + proxy_string=linphone_address_as_string_uri_only(proxy); + linphone_address_destroy(proxy); if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); @@ -364,11 +399,12 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ #endif } sal_op_set_user_pointer(obj->op,obj); - if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { + if (sal_register(obj->op,proxy_string,obj->reg_identity,obj->expires)==0) { linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress"); } else { linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed"); } + ms_free(proxy_string); } } From 84035140310f19d99ac5e39827c0cba9f10bbcb7 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 19 Mar 2013 08:52:36 +0100 Subject: [PATCH 153/909] better handling of test error --- tester/call_tester.c | 143 ++++++++++++++++++++------------------- tester/register_tester.c | 11 +-- 2 files changed, 81 insertions(+), 73 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 6aaf388c8..6dae94405 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -22,7 +22,7 @@ #include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" - +#define DEFAULT_WAIT 2 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); @@ -100,14 +100,14 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m LinphoneAddress* identity; linphone_core_get_default_proxy(callee_mgr->lc,&proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + CU_ASSERT_PTR_NOT_NULL(proxy); + if (!proxy) return -1; - - CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); /*linphone_core_invite(caller_mgr->lc,"pauline");*/ - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc + CU_ASSERT_TRUE(wait_for(callee_mgr->lc ,caller_mgr->lc ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived ,initial_callee.number_of_LinphoneCallIncomingReceived+1)); @@ -124,19 +124,23 @@ static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_m } - CU_ASSERT_TRUE_FATAL((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) + CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) |(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); linphone_core_get_default_proxy(caller_mgr->lc,&proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + CU_ASSERT_PTR_NOT_NULL(proxy); + if (!proxy) return 0; identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + if (!linphone_core_get_current_call_remote_address(callee_mgr->lc)) + return 0; CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); linphone_address_destroy(identity); linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); - CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); /*just to sleep*/ return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1) && @@ -158,29 +162,31 @@ static void simple_call(void) { linphone_core_invite(lc_marie,"pauline"); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,DEFAULT_WAIT); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,DEFAULT_WAIT)); linphone_core_get_default_proxy(lc_marie,&proxy); - CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + CU_ASSERT_PTR_NOT_NULL (proxy); identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); - linphone_address_destroy(identity); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(lc_pauline)); + if (linphone_core_get_current_call_remote_address(lc_pauline)) { + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); - linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); - /*just to sleep*/ - wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); - linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,DEFAULT_WAIT)); + /*just to sleep*/ + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,DEFAULT_WAIT)); + } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -191,12 +197,12 @@ static void cancelled_call(void) { LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,DEFAULT_WAIT)); linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); linphone_call_unref(out_call); linphone_core_manager_destroy(marie); @@ -212,9 +218,9 @@ static void call_with_dns_time_out(void) { linphone_core_invite(marie->lc,"sip:toto@toto.com"); linphone_core_iterate(marie->lc); linphone_core_iterate(marie->lc); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,DEFAULT_WAIT); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,DEFAULT_WAIT); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,DEFAULT_WAIT); linphone_core_manager_destroy(marie); } @@ -224,11 +230,11 @@ static void cancelled_ringing_call(void) { LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); linphone_call_unref(out_call); @@ -243,16 +249,17 @@ static void early_declined_call(void) { LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); - in_call=linphone_core_get_current_call(marie->lc); - linphone_call_ref(in_call); - - linphone_core_terminate_call(marie->lc,in_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); - CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); - linphone_call_unref(in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); + CU_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(marie->lc)); + if (in_call) { + linphone_call_ref(in_call); + linphone_core_terminate_call(marie->lc,in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(in_call); + } linphone_call_unref(out_call); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -265,8 +272,8 @@ static void call_terminated_by_caller(void) { CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -281,9 +288,9 @@ static void call_paused_resumed(void) { call_obj = linphone_core_get_current_call(pauline->lc); linphone_core_pause_call(pauline->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,DEFAULT_WAIT)); linphone_core_resume_call(pauline->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -291,8 +298,8 @@ static void call_paused_resumed(void) { /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -319,9 +326,9 @@ static void call_paused_resumed_from_callee(void) { call_obj = linphone_core_get_current_call(marie->lc); linphone_core_pause_call(marie->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,DEFAULT_WAIT)); linphone_core_resume_call(marie->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -329,8 +336,8 @@ static void call_paused_resumed_from_callee(void) { /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -359,8 +366,8 @@ static void call_with_video_added(void) { linphone_call_params_enable_video(marie_params,TRUE); linphone_core_update_call(marie->lc,call_obj,marie_params); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,DEFAULT_WAIT)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -370,12 +377,12 @@ static void call_with_video_added(void) { linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,marie->lc); /*send vfu*/ linphone_call_send_vfu_request(call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,DEFAULT_WAIT)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -455,8 +462,8 @@ static void srtp_call(void) { /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -469,12 +476,12 @@ static void early_media_call(void) { CU_ASSERT_TRUE(call(pauline,marie)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,DEFAULT_WAIT); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,DEFAULT_WAIT); /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); diff --git a/tester/register_tester.c b/tester/register_tester.c index cf735a183..f60ebe4a5 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -57,7 +57,8 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const const char* server_addr; LinphoneAuthInfo *info; - CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + CU_ASSERT_PTR_NOT_NULL(lc); + if (!lc) return; counters = (stats*)linphone_core_get_user_data(lc); reset_counters(counters); linphone_core_set_sip_transports(lc,&transport); @@ -91,7 +92,7 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const } ms_usleep(100000); } - CU_ASSERT_TRUE_FATAL(linphone_proxy_config_is_registered(proxy_cfg)); + CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); @@ -258,7 +259,7 @@ static void network_state_change(){ counters = (stats*)linphone_core_get_user_data(lc); register_ok=counters->number_of_LinphoneRegistrationOk; linphone_core_set_network_reachable(lc,FALSE); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); linphone_core_set_network_reachable(lc,TRUE); wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); linphone_core_destroy(lc); @@ -298,9 +299,9 @@ static void transport_change(){ /*keep only udp*/ linphone_core_set_sip_transports(lc,&sip_tr); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); - CU_ASSERT_TRUE_FATAL(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(total_number_of_proxies-number_of_udp_proxy))); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(total_number_of_proxies-number_of_udp_proxy))); linphone_core_destroy(lc); } From ff2563b24413a364ee1ce57d4aff260761f19771 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 19 Mar 2013 09:55:06 +0100 Subject: [PATCH 154/909] fix call tester --- coreapi/bellesip_sal/sal_op_call.c | 3 + tester/call_tester.c | 90 +++++++++++++++--------------- tester/flexisip.conf | 2 +- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 061fe1d87..7fef629cb 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -411,6 +411,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_op_process_refer(op,event); } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { sal_op_call_process_notify(op,event); + } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { + resp=belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); diff --git a/tester/call_tester.c b/tester/call_tester.c index 6dae94405..2131789ea 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -22,7 +22,7 @@ #include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" -#define DEFAULT_WAIT 2 + 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); @@ -162,10 +162,10 @@ static void simple_call(void) { linphone_core_invite(lc_marie,"pauline"); - CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); + CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,DEFAULT_WAIT); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,DEFAULT_WAIT)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); linphone_core_get_default_proxy(lc_marie,&proxy); CU_ASSERT_PTR_NOT_NULL (proxy); @@ -177,15 +177,15 @@ static void simple_call(void) { linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); /*just to sleep*/ wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -197,12 +197,12 @@ static void cancelled_call(void) { LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); linphone_call_unref(out_call); linphone_core_manager_destroy(marie); @@ -218,9 +218,9 @@ static void call_with_dns_time_out(void) { linphone_core_invite(marie->lc,"sip:toto@toto.com"); linphone_core_iterate(marie->lc); linphone_core_iterate(marie->lc); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,DEFAULT_WAIT); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,DEFAULT_WAIT); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,DEFAULT_WAIT); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); linphone_core_manager_destroy(marie); } @@ -230,11 +230,11 @@ static void cancelled_ringing_call(void) { LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); linphone_call_unref(out_call); @@ -249,13 +249,13 @@ static void early_declined_call(void) { LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(marie->lc)); if (in_call) { linphone_call_ref(in_call); linphone_core_terminate_call(marie->lc,in_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); linphone_call_unref(in_call); @@ -272,8 +272,8 @@ static void call_terminated_by_caller(void) { CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -288,9 +288,9 @@ static void call_paused_resumed(void) { call_obj = linphone_core_get_current_call(pauline->lc); linphone_core_pause_call(pauline->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); linphone_core_resume_call(pauline->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -298,8 +298,8 @@ static void call_paused_resumed(void) { /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -326,9 +326,9 @@ static void call_paused_resumed_from_callee(void) { call_obj = linphone_core_get_current_call(marie->lc); linphone_core_pause_call(marie->lc,call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); linphone_core_resume_call(marie->lc,call_obj); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -336,8 +336,8 @@ static void call_paused_resumed_from_callee(void) { /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -366,8 +366,8 @@ static void call_with_video_added(void) { linphone_call_params_enable_video(marie_params,TRUE); linphone_core_update_call(marie->lc,call_obj,marie_params); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -377,12 +377,12 @@ static void call_with_video_added(void) { linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,marie->lc); /*send vfu*/ linphone_call_send_vfu_request(call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -462,8 +462,8 @@ static void srtp_call(void) { /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -476,12 +476,12 @@ static void early_media_call(void) { CU_ASSERT_TRUE(call(pauline,marie)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,DEFAULT_WAIT); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,DEFAULT_WAIT); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,DEFAULT_WAIT)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); diff --git a/tester/flexisip.conf b/tester/flexisip.conf index de5809da9..4a4715730 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -261,7 +261,7 @@ 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 +reg-domains=localhost sip.example.org sipopen.example.org auth1.example.org sip2.linphone.org # Maximum number of registered contacts of an address of record. # Default value: 15 From da9ed56491b6de99dc0ce4b406750e484f93c8ba Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 19 Mar 2013 12:19:01 +0100 Subject: [PATCH 155/909] fix mis-use of update_call in linphonec. --- console/commands.c | 16 +++++++++------- coreapi/linphonecore.c | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/console/commands.c b/console/commands.c index 22b09a5a6..67b2446f4 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2510,13 +2510,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)) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 431d3e37c..93d0b8b80 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4711,7 +4711,7 @@ int linphone_core_get_device_rotation(LinphoneCore *lc ) { * **/ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { -ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); + ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); lc->device_rotation = rotation; #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call(lc); From 91ae44e4f9bd84a51c930fb8e95434333bdfc3c6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 19 Mar 2013 22:08:30 +0100 Subject: [PATCH 156/909] fix a bunch of memory leaks. --- coreapi/bellesip_sal/sal_impl.c | 24 ++++++++++++++---------- coreapi/bellesip_sal/sal_impl.h | 7 +++---- coreapi/proxy.c | 1 + coreapi/sal.c | 25 ++++++++++++++++++++++++- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 49f6fa792..7abf624b6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -347,6 +347,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } if (op) sal_op_unref(op); /*no longuer need to ref op*/ } + static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { SalAuthInfo auth_info; memset(&auth_info,0,sizeof(SalAuthInfo)); @@ -358,9 +359,10 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info.userid); return; } + Sal * sal_init(){ char stack_string[64]; - belle_sip_listener_t* listener; + belle_sip_listener_callbacks_t listener_callbacks; Sal * sal=ms_new0(Sal,1); sal->nat_helper_enabled=TRUE; snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); @@ -374,15 +376,16 @@ Sal * sal_init(){ belle_sip_set_log_handler(_belle_sip_log); sal->stack = belle_sip_stack_new(NULL); sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); - sal->listener_callbacks.process_dialog_terminated=process_dialog_terminated; - sal->listener_callbacks.process_io_error=process_io_error; - sal->listener_callbacks.process_request_event=process_request_event; - sal->listener_callbacks.process_response_event=process_response_event; - sal->listener_callbacks.process_timeout=process_timeout; - sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; - sal->listener_callbacks.process_auth_requested=process_auth_requested; - belle_sip_provider_add_sip_listener(sal->prov,listener=belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); - /* belle_sip_callbacks_t is unowned, why ?belle_sip_object_unref(listener);*/ + 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); return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ @@ -443,6 +446,7 @@ 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); ms_free(sal); return ; }; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index e7e22b9b2..13b04fe7f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -29,17 +29,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct Sal{ SalCallbacks callbacks; MSList *pending_auths;/*MSList of SalOp */ - belle_sip_listener_callbacks_t listener_callbacks; belle_sip_stack_t* stack; belle_sip_provider_t *prov; belle_sip_header_user_agent_t* user_agent; + belle_sip_listener_t *listener; void *up; /*user pointer*/ int session_expires; - bool_t one_matching_codec; unsigned int keep_alive; + bool_t one_matching_codec; bool_t use_tcp_tls_keep_alive; bool_t nat_helper_enabled; - }; typedef enum SalOpSate { @@ -74,7 +73,7 @@ struct SalOp{ SalOpSate_t state; SalOpDir_t dir; belle_sip_refresher_t* refresher; - unsigned int ref; + int ref; }; belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 1094f10f4..760f5961f 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -86,6 +86,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix); if (obj->op) sal_op_release(obj->op); if (obj->publish_op) sal_op_release(obj->publish_op); + ms_free(obj); } /** diff --git a/coreapi/sal.c b/coreapi/sal.c index 4685b0bc5..3a6a6b5c0 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -287,7 +287,7 @@ void sal_op_set_route(SalOp *op, const char *route){ route_string=sal_address_as_string((SalAddress*)op_base->route_addresses->data); \ } assign_string(&op_base->route,route_string); \ - if(route_string) ortp_free(route_string); + if(route_string) ms_free(route_string); } const MSList* sal_op_get_route_addresses(const SalOp *op) { return ((SalOpBase*)op)->route_addresses; @@ -395,6 +395,25 @@ void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){ 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; @@ -438,6 +457,10 @@ void __sal_op_free(SalOp *op){ 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->custom_headers) sal_custom_header_free(b->custom_headers); ms_free(op); From a4cc7689c6287546a7e495374123a35c54cc857c Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 20 Mar 2013 12:36:12 +0100 Subject: [PATCH 157/909] add number of unread messages --- coreapi/chat.c | 1 + coreapi/linphonecore.h | 3 +- coreapi/message_storage.c | 48 +++++++++++++++++--- gtk/calllogs.c | 18 ++++++++ gtk/chat.c | 47 +++++++++++++++----- gtk/friendlist.c | 93 +++++++++++++++++++++++---------------- gtk/linphone.h | 2 +- 7 files changed, 155 insertions(+), 57 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 69893217d..c12bb3398 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -436,6 +436,7 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); if (msg->from) linphone_address_destroy(msg->from); + if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); ms_free(msg); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index de8a05afa..ab8836a5d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -678,6 +678,7 @@ void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); void linphone_chat_room_delete_history(LinphoneChatRoom *cr); +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); @@ -685,6 +686,7 @@ void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); +void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); @@ -1430,7 +1432,6 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); int linphone_core_get_video_dscp(const LinphoneCore *lc); - #ifdef __cplusplus } #endif diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index c62fa1ddb..0c41c20d0 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -78,11 +78,12 @@ static int callback(void *data, int argc, char **argv, char **colName){ } void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ - char* errmsg; + char* errmsg=NULL; int ret; ret=sqlite3_exec(db,stmt,callback,cr,&errmsg); if(ret != SQLITE_OK) { printf("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); } } @@ -99,7 +100,7 @@ void linphone_sql_request(sqlite3* db,const char *stmt){ void linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); if (lc->db){ - const char *peer=msg->chat_room->peer; + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); char datebuf[26]; char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", @@ -107,6 +108,7 @@ void linphone_chat_message_store(LinphoneChatMessage *msg){ linphone_sql_request(lc->db,buf); sqlite3_free(buf); ms_free(local_contact); + ms_free(peer); } } @@ -127,19 +129,45 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ if (lc->db==NULL) return ; + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); char *buf=sqlite3_mprintf("update history set read=%i where remoteContact = %Q;", - read,cr->peer); + read,peer); linphone_sql_request(lc->db,buf); sqlite3_free(buf); + ms_free(peer); +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int numrows=0; + + if (lc->db==NULL) return 0; + + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + char *buf=sqlite3_mprintf("select count(*) from history where remoteContact = %Q and read = 0;",peer); + sqlite3_stmt *selectStatement; + int 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); + return numrows; } void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ LinphoneCore *lc=cr->lc; if (lc->db==NULL) return ; - char *buf=sqlite3_mprintf("delete from history where remoteContact = %Q;",cr->peer); + + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + char *buf=sqlite3_mprintf("delete from history where remoteContact = %Q;",peer); linphone_sql_request(lc->db,buf); sqlite3_free(buf); + ms_free(peer); } MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ @@ -147,13 +175,14 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ MSList *ret; if (lc->db==NULL) return NULL; - + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); cr->messages_hist = NULL; - char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",cr->peer,nb_message); + char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",peer,nb_message); linphone_sql_request_message(lc->db,buf,cr); sqlite3_free(buf); ret=cr->messages_hist; cr->messages_hist=NULL; + ms_free(peer); return ret; } @@ -162,12 +191,13 @@ void linphone_close_storage(sqlite3* db){ } void linphone_create_table(sqlite3* db){ - char* errmsg; + 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) { printf("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); } } @@ -216,4 +246,8 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ void linphone_core_message_storage_close(LinphoneCore *lc){ } +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + return 0; +} + #endif diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 45a616119..ce4695dd2 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -33,10 +33,25 @@ 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; + + select = gtk_tree_view_get_selection(v); + 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_update(GtkWidget *w){ GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view")); GtkTreeStore *store; const MSList *logs; + GtkTreeSelection *select; store=(GtkTreeStore*)gtk_tree_view_get_model(v); if (store==NULL){ @@ -44,6 +59,9 @@ void linphone_gtk_call_log_update(GtkWidget *w){ 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); // 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"))); } diff --git a/gtk/chat.c b/gtk/chat.c index 6a65cd9fc..7f7e26a56 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -65,7 +65,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),idx); - linphone_gtk_create_chat_picture(FALSE); + //linphone_gtk_create_chat_picture(FALSE); g_object_set_data(G_OBJECT(friendlist),"chatview",NULL); g_object_set_data(G_OBJECT(w),"from_message",NULL); g_object_set_data(G_OBJECT(w),"cr",NULL); @@ -265,6 +265,15 @@ void linphone_gtk_send_text(){ } } +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; @@ -282,6 +291,7 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); ms_free(from_str); ms_free(with_str); + linphone_gtk_free_list(messages); } } @@ -306,7 +316,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.red = 56832; colorb.green = 60928; colorb.blue = 61952; - + with_str=linphone_address_as_string_uri_only(with); linphone_chat_room_mark_as_read(cr); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); @@ -354,12 +364,14 @@ LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri,GtkWidget *chat_view){ GtkWidget *main_window=linphone_gtk_get_main_window (); LinphoneChatRoom *cr2=(LinphoneChatRoom *)g_object_get_data(G_OBJECT(chat_view),"cr"); - char *from_str=linphone_address_as_string(linphone_chat_room_get_peer_address (cr2)); + 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; linphone_chat_room_mark_as_read(cr); - if(g_strcmp0(from_str,uri_str)!=0){ + 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; @@ -371,7 +383,7 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, udpate_tab_chat_header(chat_view,uri,cr); g_object_set_data(G_OBJECT(chat_view),"cr",cr); 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); + messages=linphone_chat_room_get_history(cr,NB_MSG_HIST); g_object_set_data(G_OBJECT(chat_view),"from_message",uri_str); display_history_message(chat_view,messages,uri); } @@ -394,15 +406,22 @@ 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 *w; + gboolean send=TRUE; + char *from=linphone_address_as_string(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); + char *from_chatview=(char *)g_object_get_data(G_OBJECT(w),"from"); + if(g_strcmp0(from,from_chatview)==0){ + send=TRUE; + } else { + send=FALSE; + } + ms_free(from_chatview); } else { w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)w); - char *from=linphone_address_as_string(linphone_chat_message_get_from(msg)); g_object_set_data(G_OBJECT(friendlist),"from",from); } get_display_name(linphone_chat_message_get_from(msg)); @@ -419,9 +438,17 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } } #endif - linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), + if(send){ + linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), FALSE,room,msg,FALSE); - linphone_gtk_update_chat_picture(); + } else { + linphone_gtk_show_friends(); + //linphone_gtk_friend_list_update_message(msg); + } + ms_free(from); + //linphone_gtk_update_chat_picture(); + //TODO: update la zone de notification dans les contacts (problème : lors du refresh de la liste + //connaitre tous les contacts qui ont des messages non lus ... //gtk_window_present(GTK_WINDOW(w)); /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index be6a4c3ce..e1012f7cd 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -32,7 +32,7 @@ enum{ FRIEND_ICON, FRIEND_CALL, FRIEND_CHAT, - FRIEND_CHAT_CONVERSATION, + FRIEND_NB_UNREAD_MSG, FRIEND_LIST_NCOL }; @@ -253,9 +253,11 @@ 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",linphone_address_as_string(uri)); @@ -269,6 +271,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ linphone_gtk_create_chat_picture(FALSE); 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); + gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,"",-1); } } @@ -541,7 +544,8 @@ 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, + G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(friendlist),GTK_TREE_MODEL(store)); g_object_unref(G_OBJECT(store)); @@ -579,9 +583,13 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ gtk_tree_view_column_set_clickable(column,TRUE); gtk_tree_view_column_set_expand(column,TRUE); gtk_tree_view_column_set_max_width(column,60); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start(column,renderer,TRUE); + gtk_tree_view_column_add_attribute (column,renderer,"text",FRIEND_NB_UNREAD_MSG); + gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); - /* Call column*/ renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes (_("Call"),renderer,"pixbuf",FRIEND_CALL,NULL); @@ -669,6 +677,7 @@ void linphone_gtk_show_friends(void){ //const gchar *search=NULL; //gboolean lookup=FALSE; MSList *sorted; + LinphoneChatRoom *cr=NULL; linphone_gtk_show_directory_search(); @@ -693,6 +702,9 @@ 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; + /*if (lookup){ if (strstr(uri,search)==NULL){ ms_free(uri); @@ -709,9 +721,25 @@ void linphone_gtk_show_friends(void){ FRIEND_PRESENCE_IMG, send_subscribe ? create_status_picture(linphone_friend_get_status(lf)) : NULL, -1); + gtk_tree_model_get(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)),&iter,FRIEND_CHATROOM,&cr,-1); + if(cr!=NULL){ + nbmsg=linphone_chat_room_get_unread_messages_count(cr); + if(nbmsg != 0){ + sprintf(buf,"%i",nbmsg); + } + } else { + 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){ + sprintf(buf,"%i",nbmsg); + } + + } + gtk_list_store_set(store,&iter,FRIEND_CALL,create_call_picture(),-1); gtk_list_store_set(store,&iter,FRIEND_CHAT,create_chat_picture(),-1); - + gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,buf,-1); escaped=g_markup_escape_text(uri,-1); gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1); g_free(escaped); @@ -912,52 +940,41 @@ 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); + 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; + gint num = get_col_number_from_tree_view_column(col); return num; - } - else { - colx += checkcol->width; + } else { + colx += checkcol->width; } - } - g_list_free(columns); + } + } + g_list_free(columns); return 0; } diff --git a/gtk/linphone.h b/gtk/linphone.h index aaa021a28..a7d7da506 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -152,4 +152,4 @@ void linphone_gtk_monitor_usb(void); void linphone_gtk_unmonitor_usb(void); gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); - +void linphone_gtk_friend_list_update_message(LinphoneChatMessage *msg); From 00632eb0495ae26e8f8c2677717bd6cf19e2ba2b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 20 Mar 2013 12:36:13 +0100 Subject: [PATCH 158/909] fix exosip dscp api detection --- configure.ac | 14 -------------- m4/exosip.m4 | 13 +++++++++++++ mediastreamer2 | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 4957eeb58..7bc526bbb 100644 --- a/configure.ac +++ b/configure.ac @@ -444,19 +444,6 @@ 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 @@ -684,7 +671,6 @@ AC_ARG_ENABLE(msg-storage, [enable_msg_storage=auto] ) -echo "enable_msg_storage = $enable_msg_storage" AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue) if test x$enable_msg_storage != xfalse; then 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/mediastreamer2 b/mediastreamer2 index 45c9c6516..430cc1376 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 45c9c65168a9912bd2aa97344b396771ff1cdaf0 +Subproject commit 430cc1376d68b1a8d82799357abea9e3e1c536f8 From e518c6d0b9e721184f9389b3bdff7baf133d6bb3 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 20 Mar 2013 12:48:02 +0100 Subject: [PATCH 159/909] fix dispaly unread messages --- gtk/chat.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 7f7e26a56..38efc1011 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -412,13 +412,12 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, char *from=linphone_address_as_string(linphone_chat_message_get_from(msg)); w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); if(w!=NULL){ - char *from_chatview=(char *)g_object_get_data(G_OBJECT(w),"from"); + char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ send=TRUE; } else { send=FALSE; - } - ms_free(from_chatview); + } } else { w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)w); @@ -445,7 +444,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, linphone_gtk_show_friends(); //linphone_gtk_friend_list_update_message(msg); } - ms_free(from); //linphone_gtk_update_chat_picture(); //TODO: update la zone de notification dans les contacts (problème : lors du refresh de la liste //connaitre tous les contacts qui ont des messages non lus ... From 5c2ca7c2030a4ac39f3ab13b167e4818102004cf Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 20 Mar 2013 14:57:03 +0100 Subject: [PATCH 160/909] fix received messages in chat --- gtk/chat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 38efc1011..69c4e832f 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -65,7 +65,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),idx); - //linphone_gtk_create_chat_picture(FALSE); + linphone_gtk_create_chat_picture(FALSE); g_object_set_data(G_OBJECT(friendlist),"chatview",NULL); g_object_set_data(G_OBJECT(w),"from_message",NULL); g_object_set_data(G_OBJECT(w),"cr",NULL); @@ -419,6 +419,7 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, send=FALSE; } } else { + send=FALSE; w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)w); g_object_set_data(G_OBJECT(friendlist),"from",from); @@ -438,6 +439,7 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } #endif if(send){ + linphone_chat_room_mark_as_read(room); linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), FALSE,room,msg,FALSE); } else { @@ -445,8 +447,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, //linphone_gtk_friend_list_update_message(msg); } //linphone_gtk_update_chat_picture(); - //TODO: update la zone de notification dans les contacts (problème : lors du refresh de la liste - //connaitre tous les contacts qui ont des messages non lus ... //gtk_window_present(GTK_WINDOW(w)); /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ } From 3e21614fe234b85360f0ce33b9a2a55a8fbf2f07 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Mar 2013 15:39:05 +0100 Subject: [PATCH 161/909] Remove files that should not have been commited. --- .../LibLinphone/LibLinphone.vcxproj.filters | 51 ------------------ .../LibLinphoneTester-wp8.v11.suo | Bin 201255 -> 0 bytes .../LibLinphoneTester.vcxproj.filters | 22 -------- 3 files changed, 73 deletions(-) delete mode 100644 build/vsx/LibLinphone/LibLinphone.vcxproj.filters delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo delete mode 100644 build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj.filters diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters b/build/vsx/LibLinphone/LibLinphone.vcxproj.filters deleted file mode 100644 index bc95616ad..000000000 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.v11.suo deleted file mode 100644 index abd949b4c4ca1a801713480ec26a0d3094b7281d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201255 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

@^ki^V@|A9>#M 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 z - - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - - - - - - - - - - - - \ No newline at end of file From 0466c94986c5600c856851c8d4ce5047b26d5394 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Mar 2013 15:48:48 +0100 Subject: [PATCH 162/909] Do not define a variable in the middle of a block of code. --- coreapi/linphonecore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 93d0b8b80..542241262 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2117,8 +2117,9 @@ void linphone_core_iterate(LinphoneCore *lc){ if (call->state==LinphoneCallIncomingReceived){ 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); - LinphoneReason decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; + decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; call->reason=LinphoneReasonNotAnswered; linphone_core_decline_call(lc,call,decline_reason); From 7bbd2ebb54e305d13e11a69d4fb60cbd3d6e5c86 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 20 Mar 2013 16:12:58 +0100 Subject: [PATCH 163/909] Add WebRTC echo canceller dependency. --- .../LibLinphoneTester-wp8.sln | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index c5c7ed8db..f2d278134 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio Express 2012 for Windows Phone Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8\LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}" ProjectSection(ProjectDependencies) = postProject {5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534} @@ -39,6 +39,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\ {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcaecm", "..\..\..\..\webrtc\build\windows\webrtcaecm\webrtcaecm\webrtcaecm.vcxproj", "{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -281,6 +283,24 @@ Global {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.ActiveCfg = Debug|ARM + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.Build.0 = Debug|ARM + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.Build.0 = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.ActiveCfg = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.Build.0 = Debug|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Any CPU.ActiveCfg = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.ActiveCfg = Release|ARM + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.Build.0 = Release|ARM + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.Build.0 = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.ActiveCfg = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.Build.0 = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.ActiveCfg = Release|Win32 + {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 3cd2dac98fcac81288d1a86704b2ca792eeff607 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 20 Mar 2013 17:12:52 +0100 Subject: [PATCH 164/909] refactoring and memory leak bugfixing. --- coreapi/bellesip_sal/sal_impl.c | 52 ++++++++++++++---------------- coreapi/bellesip_sal/sal_impl.h | 5 ++- coreapi/bellesip_sal/sal_op_call.c | 8 +++-- coreapi/bellesip_sal/sal_op_impl.c | 7 ++-- coreapi/friend.c | 8 ++--- coreapi/proxy.c | 1 + 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7abf624b6..72ef57957 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -52,26 +52,33 @@ void sal_disable_logs() { belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); } static void sal_add_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_append(sal->pending_auths,op); + if (ms_list_find(sal->pending_auths,op)==NULL){ + sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op)); + } } void sal_remove_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_remove(sal->pending_auths,op); + if (ms_list_find(sal->pending_auths,op)){ + sal->pending_auths=ms_list_remove(sal->pending_auths,op); + sal_op_unref(op); + } } -void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { - belle_sip_request_t* request; +void sal_process_authentication(SalOp *op) { + belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction);; bool_t is_within_dialog=FALSE; belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; + belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); + + sal_add_pending_auth(op->base.root,op); + if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { - request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)op->request); + request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)request); is_within_dialog=TRUE; } else { - request=op->request; belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); - } if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) { if (is_within_dialog) { @@ -79,6 +86,7 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { } else { sal_op_resend_request(op,request); } + sal_remove_pending_auth(op->base.root,op); }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); if (is_within_dialog) { @@ -90,7 +98,6 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { op->auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(auth_event)) ; op->auth_info->username = ms_strdup(belle_sip_auth_event_get_username(auth_event)) ; belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); - sal_add_pending_auth(op->base.root,op); } } @@ -196,7 +203,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even 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 state less response [%i]",response_code); + ms_warning("Discarding stateless response [%i]",response_code); return; } else { SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); @@ -210,9 +217,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even int rport; bool_t contact_updated=FALSE; char* new_contact; - belle_sip_request_t* old_request=NULL; - belle_sip_response_t* old_response=NULL; - if (op->state == SalOpStateTerminated) { belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); @@ -279,33 +283,27 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } } } - /*update request/response - * maybe only the transaction should be kept*/ - old_request=op->request; - op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_object_ref(op->request); - if (old_request) belle_sip_object_unref(old_request); - - old_response=op->response; - op->response=response; /*kept for use at authorization time*/ - belle_sip_object_ref(op->response); - if (old_response) belle_sip_object_unref(old_response); - - /*handle authozation*/ + + /*handle authorization*/ switch (response_code) { case 200: { - sal_remove_pending_auth(op->base.root,op);/*just in case*/ break; } case 401: case 407:{ + /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ belle_sip_message("Op is in state terminating, nothing else to do "); return; } else { - sal_process_authentication(op,response); + if (op->pending_auth_transaction){ + belle_sip_object_unref(op->pending_auth_transaction); + op->pending_auth_transaction=NULL; + } + op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); + sal_process_authentication(op); return; } } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 13b04fe7f..c0e650f97 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -56,8 +56,7 @@ typedef enum SalOpDir { struct SalOp{ SalOpBase base; belle_sip_listener_callbacks_t callbacks; - belle_sip_request_t* request; - belle_sip_response_t* response; + belle_sip_client_transaction_t *pending_auth_transaction; belle_sip_server_transaction_t* pending_server_trans; belle_sip_client_transaction_t* pending_inv_client_trans; SalAuthInfo* auth_info; @@ -94,7 +93,7 @@ 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); void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); -void sal_process_authentication(SalOp *op, belle_sip_response_t *response); +void sal_process_authentication(SalOp *op); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 7fef629cb..2bcb0b89a 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -233,6 +233,11 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } + +static void call_set_released(SalOp* op){ + op->base.root->callbacks.call_released(op); +} + static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; if (!op->dialog) { @@ -259,8 +264,7 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ if (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->base.root->callbacks.call_released(op); - op->state=SalOpStateTerminated; + call_set_released(op); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 43ceb22ae..cf02d532c 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -32,7 +32,7 @@ void sal_op_release(SalOp *op){ } void sal_op_release_impl(SalOp *op){ ms_message("Destroying op [%p]",op); - if (op->request) belle_sip_object_unref(op->request); + if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); if (op->auth_info) sal_auth_info_delete(op->auth_info); if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); if (op->registration_refresher) { @@ -46,9 +46,10 @@ void sal_op_release_impl(SalOp *op){ __sal_op_free(op); return ; } + void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ /*for sure auth info will be accesible from the provider*/ - sal_process_authentication(op, NULL); + sal_process_authentication(op); return ; } @@ -120,7 +121,7 @@ void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { } 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(op->request),BELLE_SIP_CSEQ); + 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); } diff --git a/coreapi/friend.c b/coreapi/friend.c index e55deb75d..2a857de2d 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -155,10 +155,8 @@ 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_addr(fr,linphone_address); + linphone_address_destroy(linphone_address); return fr; } @@ -205,7 +203,7 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char int linphone_friend_set_addr(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; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 760f5961f..00f370c14 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -86,6 +86,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix); if (obj->op) sal_op_release(obj->op); if (obj->publish_op) sal_op_release(obj->publish_op); + if (obj->contact_params) ms_free(obj->contact_params); ms_free(obj); } From 5077b5e2362c2aab24c9a3f63eba71ce234d1abc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 21 Mar 2013 11:13:42 +0100 Subject: [PATCH 165/909] fix crash related to zrtp hello hash when adding video --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 701600aa0..611cb6f2f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -272,7 +272,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; // if ZRTP is enabled, put the hello hash into the audiostream's desc - if (call->videostream->ms.zrtp_context!=NULL){ + if (call->videostream && call->videostream->ms.zrtp_context!=NULL){ ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context, md->streams[1].zrtp_hello_hash, sizeof(md->streams[1].zrtp_hello_hash)); From 7fe41ec081bc41789d1d4bca4681ddf05af8bc07 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 21 Mar 2013 11:13:42 +0100 Subject: [PATCH 166/909] fix crash related to zrtp hello hash when adding video --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e9640701f..2770d4ada 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -271,7 +271,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; // if ZRTP is enabled, put the hello hash into the audiostream's desc - if (call->videostream->ms.zrtp_context!=NULL){ + if (call->videostream && call->videostream->ms.zrtp_context!=NULL){ ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context, md->streams[1].zrtp_hello_hash, sizeof(md->streams[1].zrtp_hello_hash)); From 235387ff17234d93b217ced1ea9e4a04b35e196c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Mar 2013 10:53:23 +0100 Subject: [PATCH 167/909] Remove useless semicolon. --- coreapi/bellesip_sal/sal_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 72ef57957..fce3582f9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -65,7 +65,7 @@ static void sal_add_pending_auth(Sal *sal, SalOp *op){ } void sal_process_authentication(SalOp *op) { - belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction);; + belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); bool_t is_within_dialog=FALSE; belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; From 2aba9114a4bd01ac823402793ccdbc6c6b1df075 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Mar 2013 10:56:44 +0100 Subject: [PATCH 168/909] change the way local interface is searched. --- coreapi/misc.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 35a58e200..158ab0add 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1110,7 +1110,18 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul } int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ + int err; strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); + + 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 if (dest==NULL) { /*we use getifaddrs for lookup of default interface */ @@ -1125,11 +1136,7 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ } } #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); + return 0; } #ifndef WIN32 From b37cdb67830e898ddde4228c87ef1514d31a32b9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Mar 2013 10:58:25 +0100 Subject: [PATCH 169/909] fix previous commit. --- coreapi/misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 158ab0add..738766746 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1113,9 +1113,11 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ int err; strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); - if (type==AF_INET) - dest="87.98.157.38"; /*a public IP address*/ - else dest="2a00:1450:8002::68"; + 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; From 606d3c0a25c0134836eae78ac142ddb05dc4be38 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Mar 2013 11:00:23 +0100 Subject: [PATCH 170/909] fix again --- coreapi/misc.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 738766746..26cdbe224 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1125,18 +1125,17 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ * try to find 'the' running interface with getifaddrs*/ #ifdef HAVE_GETIFADDRS - 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; - } - } + /*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 return 0; } From 7b8ccfc015ba83f7c3a353981a7937657d61df10 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Mar 2013 11:28:20 +0100 Subject: [PATCH 171/909] Enable disabling of verbose traces and improve traces display. --- .../linphone-tester-native.cpp | 34 ++++++++++++++++--- .../linphone-tester-native.h | 8 +++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp index 310db9984..941b50916 100644 --- a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp @@ -13,7 +13,7 @@ using namespace Platform; static OutputTraceListener^ sTraceListener; -static void nativeOutputTraceHandler(int lev, const char *fmt, va_list args) +static void nativeOutputTraceHandler(OutputTraceLevel lev, const char *fmt, va_list args) { if (sTraceListener) { wchar_t wstr[MAX_TRACE_SIZE]; @@ -26,11 +26,35 @@ static void nativeOutputTraceHandler(int lev, const char *fmt, va_list args) } } -static void LinphoneNativeOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +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); - nativeOutputTraceHandler((int)lev, fmt2, args); + 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() @@ -59,9 +83,11 @@ void LinphoneTesterNative::run(Platform::String^ suiteName, Platform::String^ ca 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(nativeOutputTraceHandler); + CU_set_trace_handler(CUnitNativeOutputTraceHandler); liblinphone_tester_run_tests(wssuitename == all ? 0 : csuitename, wscasename == all ? 0 : ccasename); } diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.h b/build/vsx/LibLinphoneTester/linphone-tester-native.h index a35658bf6..b46b57af0 100644 --- a/build/vsx/LibLinphoneTester/linphone-tester-native.h +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.h @@ -4,6 +4,14 @@ namespace linphone_tester_native { + enum OutputTraceLevel { + Debug, + Message, + Warning, + Error, + Raw + }; + public interface class OutputTraceListener { public: From d2e8f7d23903a26842e7d51f146648cff9544ce3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Mar 2013 12:05:48 +0100 Subject: [PATCH 172/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 430cc1376..dc277cd95 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 430cc1376d68b1a8d82799357abea9e3e1c536f8 +Subproject commit dc277cd95ec334066948c91dd9bf024c1ff1d933 From 381330255239a3ad5b73a8d4e46f34e057601466 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 22 Mar 2013 16:16:51 +0100 Subject: [PATCH 173/909] assign upnp local address --- coreapi/upnp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 2dfd7f39c..33a79375e 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -316,7 +316,12 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1); - + char address[LINPHONE_IPADDR_SIZE]; + const char*upnp_binding_address=address; + if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,address)) { + ms_warning("Linphone core [%p] cannot guess local address for upnp, let's choice the lib",lc); + upnp_binding_address=NULL; + } ms_mutex_init(&lupnp->mutex, NULL); ms_cond_init(&lupnp->empty_cond, NULL); @@ -328,7 +333,7 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { lupnp->adding_configs = NULL; lupnp->removing_configs = NULL; lupnp->state = LinphoneUpnpStateIdle; - ms_message("uPnP IGD: New %p for core %p", lupnp, lc); + ms_message("uPnP IGD: New %p for core %p bound to %s", lupnp, lc,upnp_binding_address); // Init ports lupnp->sip_udp = NULL; @@ -338,7 +343,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"); From 939c0f4ce0fe8c6a15ffc6de2fca43302e8876cc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 22 Mar 2013 16:34:09 +0100 Subject: [PATCH 174/909] Revert "Send ZRTP hello hash in SIP SDP." This reverts commit 71f31347fcddaa5f0e9e329a7320efe60bc7c281. Conflicts: coreapi/linphonecall.c mediastreamer2 --- coreapi/linphonecall.c | 41 +++++++++------------------------------ coreapi/linphonecore.c | 8 +------- coreapi/offeranswer.c | 1 - coreapi/sal.h | 3 +-- coreapi/sal_eXosip2_sdp.c | 28 +++----------------------- oRTP | 2 +- 6 files changed, 15 insertions(+), 68 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2770d4ada..6c01c65bd 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -254,14 +254,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * l=ms_list_append(l,pt); md->streams[0].payloads=l; - // if ZRTP is enabled, put the hello hash into the audiostream's desc - if (call->audiostream && call->audiostream->ms.zrtp_context!=NULL){ - ortp_zrtp_get_hello_hash(call->audiostream->ms.zrtp_context, - md->streams[0].zrtp_hello_hash, - sizeof(md->streams[0].zrtp_hello_hash)); - ms_message("Audio stream zrtp hash: %s", md->streams[0].zrtp_hello_hash); - } - if (call->params.has_video){ md->n_active_streams++; md->streams[1].rtp_port=call->video_port; @@ -270,13 +262,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; - // if ZRTP is enabled, put the hello hash into the audiostream's desc - if (call->videostream && call->videostream->ms.zrtp_context!=NULL){ - ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context, - md->streams[1].zrtp_hello_hash, - sizeof(md->streams[1].zrtp_hello_hash)); - ms_message("Video stream zrtp hash: %s", md->streams[1].zrtp_hello_hash); - } } if (md->n_total_streams < md->n_active_streams) md->n_total_streams = md->n_active_streams; @@ -1309,20 +1294,6 @@ void linphone_call_init_video_stream(LinphoneCall *call){ void linphone_call_init_media_streams(LinphoneCall *call){ linphone_call_init_audio_stream(call); linphone_call_init_video_stream(call); - - // moved from linphone_call_start_media_streams, because ZRTP needs to be - // at least partially initialized so that the SDP can contain 'zrtp-hash' - if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { - OrtpZrtpParams params; - /*will be set later when zrtp is activated*/ - call->current_params.media_encryption=LinphoneMediaEncryptionNone; - - params.zid_file=call->core->zrtp_secrets_cache; - 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; - } } @@ -1765,10 +1736,16 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut call->playing_ringbacktone=send_ringbacktone; call->up_bw=linphone_core_get_upload_bandwidth(lc); - // ZRTP was initialized in linphone_call_init_media_streams with a - // partially iniitalized RtpSession, and now needs to get an update if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { - ortp_zrtp_start_engine(call->audiostream->ms.zrtp_context,call->audiostream->ms.session); + OrtpZrtpParams params; + /*will be set later when zrtp is activated*/ + call->current_params.media_encryption=LinphoneMediaEncryptionNone; + + params.zid_file=lc->zrtp_secrets_cache; + 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; } /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 542241262..0089dd0fb 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3126,14 +3126,8 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, sal_call_set_local_media_description(call->op,call->localdesc); } - if (call->audiostream==NULL){ + if (call->audiostream==NULL) linphone_call_init_media_streams(call); - // the local media description must be regenerated after the audiostream - // is initialized, otherwise the ZRTP hello hash will not be available - linphone_call_make_local_media_description(lc,call); - sal_call_set_local_media_description(call->op,call->localdesc); - } - if (!was_ringing && call->audiostream->ms.ticker==NULL){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index eefe34d45..9823c24a6 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -261,7 +261,6 @@ 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)); - memcpy(result->zrtp_hello_hash,local_cap->zrtp_hello_hash, sizeof(result->zrtp_hello_hash)); } /** diff --git a/coreapi/sal.h b/coreapi/sal.h index 5f38c15ab..25d8d20bc 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -140,7 +140,7 @@ typedef struct SalIceRemoteCandidate { } SalIceRemoteCandidate; #define SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES 2 -#define SAL_MEDIA_DESCRIPTION_MAX_ZRTP_HELLO_HASH 128 + #define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 @@ -172,7 +172,6 @@ typedef struct SalStreamDescription{ SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES]; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; - char zrtp_hello_hash[SAL_MEDIA_DESCRIPTION_MAX_ZRTP_HELLO_HASH]; bool_t ice_mismatch; bool_t ice_completed; } SalStreamDescription; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 139446448..debd8550f 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -108,17 +108,6 @@ static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ return 0; } -static char * _sdp_message_get_a_zrtp_hash(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("zrtp-hash",attr->a_att_field)==0){ - return attr->a_att_value; - } - } - return NULL; -} - static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ int i; sdp_attribute_t *attr; @@ -348,11 +337,6 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription int_2char(desc->bandwidth)); if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), int_2char(desc->ptime)); - - // if the ZRTP hello hash is available, create an a attribute for it - if (desc->zrtp_hello_hash[0]) - sdp_message_a_attribute_add(msg,lineno,osip_strdup("zrtp-hash"), osip_strdup(desc->zrtp_hello_hash)); - strip_well_known_rtpmaps=ms_list_size(desc->payloads)>5; if (desc->payloads){ for(elem=desc->payloads;elem!=NULL;elem=elem->next){ @@ -449,7 +433,7 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int i,j; - const char *mtype,*proto,*rtp_port,*rtp_addr,*number,*zrtp_info; + const char *mtype,*proto,*rtp_port,*rtp_addr,*number; const char *sess; sdp_bandwidth_t *sbw=NULL; sdp_attribute_t *attr; @@ -506,12 +490,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ stream->rtp_port=atoi(rtp_port); if (stream->rtp_port > 0) desc->n_active_streams++; - - // if the SDP contains a zrtp-hash, add it to the StreamDesc - zrtp_info = _sdp_message_get_a_zrtp_hash(msg, i); - if (zrtp_info != NULL) - strncpy(stream->zrtp_hello_hash, zrtp_info, sizeof(stream->zrtp_hello_hash)); - + stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ stream->type=SalAudio; @@ -549,8 +528,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ 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]; - // added bounds check - int nb = sscanf(attr->a_att_value, "%d IN IP4 %256s", &stream->rtcp_port, tmp); + 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) { diff --git a/oRTP b/oRTP index c702c0ea0..dbb75fb00 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c702c0ea0e66bbe1f27c79690003d9748b01560f +Subproject commit dbb75fb00c65ce0102385f235c1da2873e9f6c2e From c0bed3eac97178e731bb698c3e2b2d00fc0a3919 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 22 Mar 2013 17:07:29 +0100 Subject: [PATCH 175/909] Add prefix path for sound files. --- coreapi/linphonecore.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8d2d826db..0b475e15f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -69,11 +69,16 @@ static void linphone_core_free_hooks(LinphoneCore *lc); const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); +#ifdef WINAPI_FAMILY_PHONE_APP +#define SOUNDS_PREFIX "Assets/Sounds/" +#else +#define SOUNDS_PREFIX +#endif /* relative path where is stored local ring*/ -#define LOCAL_RING "rings/oldphone.wav" +#define LOCAL_RING SOUNDS_PREFIX "rings/oldphone.wav" /* same for remote ring (ringback)*/ -#define REMOTE_RING "ringback.wav" -#define HOLD_MUSIC "rings/toy-mono.wav" +#define REMOTE_RING SOUNDS_PREFIX "ringback.wav" +#define HOLD_MUSIC SOUNDS_PREFIX "rings/toy-mono.wav" extern SalCallbacks linphone_sal_callbacks; From 4185245005f018b76b9b61b6650311d391fee713 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 22 Mar 2013 17:16:14 +0100 Subject: [PATCH 176/909] fix upnp compilation issue on ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 430cc1376..000ced416 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 430cc1376d68b1a8d82799357abea9e3e1c536f8 +Subproject commit 000ced416e943528e89f4569ee9d8d044d6b9126 From 26df3747465742eb797e809db8cc1f4138198654 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Mar 2013 22:54:27 +0100 Subject: [PATCH 177/909] update mediastreamer2 and oRTP for bugfix regarding adaptive rate control in audio only. The rate control algorithm had a bug preventing him to enhance the quality was the network returns fine, and even worse it was setting the worse quality for the rest of the call. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index dc277cd95..246292160 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit dc277cd95ec334066948c91dd9bf024c1ff1d933 +Subproject commit 2462921605f587a51f82bd439b85fea5bd759b0b diff --git a/oRTP b/oRTP index dbb75fb00..31d242e8c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit dbb75fb00c65ce0102385f235c1da2873e9f6c2e +Subproject commit 31d242e8c544ed197f60630593515aef2fb580e9 From 6bfc2d674fa156c6822e540a21b7bb1307a39946 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 25 Mar 2013 09:57:30 +0100 Subject: [PATCH 178/909] Updated factory to use new package for CpuUtils (org.linphone.mediastream) --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 7b21ecaae..0b799f33e 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -21,7 +21,7 @@ package org.linphone.core; import java.io.File; import java.io.IOException; -import org.linphone.CpuUtils; +import org.linphone.mediastream.CpuUtils; import org.linphone.mediastream.Version; import android.util.Log; From d9c2a41bd4199f0edc9451e5c3075d2fb55d1abf Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 25 Mar 2013 11:32:32 +0100 Subject: [PATCH 179/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 246292160..4b8d2b655 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2462921605f587a51f82bd439b85fea5bd759b0b +Subproject commit 4b8d2b655acc8a329464e7806653dceb04ade445 From 2fede18b16402eec3779599b46e21d742d85ee02 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 25 Mar 2013 21:45:34 +0100 Subject: [PATCH 180/909] implement compatibility mode with exosip when only one transport is available --- coreapi/bellesip_sal/sal_address_impl.c | 2 + coreapi/bellesip_sal/sal_op_impl.c | 11 +++++ coreapi/linphonecore.c | 17 ++++++- coreapi/misc.c | 3 +- coreapi/private.h | 5 +- coreapi/proxy.c | 6 +-- tester/call_tester.c | 65 +++++++++++++++++++++++++ tester/message_tester.c | 36 ++++++++++++++ tester/register_tester.c | 18 +++++-- 9 files changed, 152 insertions(+), 11 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index c7a2603ca..540aa701b 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -109,6 +109,8 @@ void sal_address_set_port_int(SalAddress *addr, int port){ } void sal_address_clean(SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri=belle_sip_header_address_get_uri(header_addr); + if (uri) belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(uri)); belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr)); return ; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index cf02d532c..b05517fad 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -146,6 +146,17 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); } } + if (!sal_op_get_route_addresses(op) && belle_sip_list_size(belle_sip_provider_get_listening_points(op->base.root->prov))==1) { + /*compatibility mode*/ + belle_sip_listening_point_t* lp = (belle_sip_listening_point_t*)belle_sip_provider_get_listening_points(op->base.root->prov)->data; + belle_sip_uri_t* to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header_by_type(request,belle_sip_header_to_t))); + belle_sip_header_address_t* route=belle_sip_header_address_create(NULL,belle_sip_uri_create(NULL,belle_sip_uri_get_host(to_uri))); + belle_sip_uri_set_transport_param(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(route)),belle_sip_listening_point_get_transport(lp)); + route_header = belle_sip_header_route_create(route); + belle_sip_object_unref(route); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + ms_message("Only one lp & no route, forcing transport to lp transport [%s]",belle_sip_listening_point_get_transport(lp)); + } } client_transaction = belle_sip_provider_create_client_transaction(prov,request); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0b475e15f..e443ae1b6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2566,14 +2566,27 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (sal_address_get_transport((SalAddress*)addr)) { sal_address_set_transport(route,sal_address_get_transport((SalAddress*)addr)); } else { + LinphoneProxyConfig* chosen_proxy=NULL; + if (dest_proxy) - proxy_addr=sal_address_new(linphone_proxy_config_get_addr(dest_proxy)); + chosen_proxy=dest_proxy; else if (proxy) - proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy)); + chosen_proxy=proxy; + else + chosen_proxy=NULL; + + if (chosen_proxy) + proxy_addr=sal_address_new(linphone_proxy_config_get_addr(chosen_proxy)); + if (proxy_addr && sal_address_get_transport(proxy_addr)) sal_address_set_transport(route,sal_address_get_transport(proxy_addr)); + else if (proxy_addr && linphone_proxy_config_guess_transport(chosen_proxy) && !sal_address_get_transport((SalAddress*)route)) { + /*compatibility mode*/ + sal_address_set_transport((SalAddress*)route,sal_transport_parse(linphone_proxy_config_guess_transport(chosen_proxy))); + } } + sal_op_add_route_address(call->op,route); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 85dd51d82..cd62a522f 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1115,7 +1115,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul ms_error("getnameinfo error: %s",strerror(errno)); } close_socket(sock); - ms_message("Local interface to reach %s is %s.",dest,result); + + return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index 8645edbff..19e84f9dc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -240,7 +240,10 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); * Can be NULL * */ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); - +/* + *guess the transport if only one trasport is configured at core level (for backward compatibility) + * */ +const char* linphone_proxy_config_guess_transport(const LinphoneProxyConfig *obj); int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 00f370c14..76f40eb99 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -347,7 +347,7 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ return ret; } /*use for compatibility with linphone supporting only 1 transport at a time*/ -const char* guess_transport(const LinphoneProxyConfig *obj) { +const char* linphone_proxy_config_guess_transport(const LinphoneProxyConfig *obj) { LCSipTransports transports; const char* transport_name; unsigned char transports_count=0; @@ -383,8 +383,8 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ char *contact; #else LinphoneAddress *contact; - if (guess_transport(obj) && !sal_address_get_transport((SalAddress*)proxy)) { - sal_address_set_transport((SalAddress*)proxy,sal_transport_parse(guess_transport(obj))); + if (linphone_proxy_config_guess_transport(obj) && !sal_address_get_transport((SalAddress*)proxy)) { + sal_address_set_transport((SalAddress*)proxy,sal_transport_parse(linphone_proxy_config_guess_transport(obj))); } #endif proxy_string=linphone_address_as_string_uri_only(proxy); diff --git a/tester/call_tester.c b/tester/call_tester.c index 2131789ea..9c98fa00d 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -190,6 +190,70 @@ static void simple_call(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void simple_call_compatibility_mode(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; + LinphoneProxyConfig* proxy; + LinphoneAddress* identity; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + + linphone_core_get_default_proxy(lc_marie,&proxy); + CU_ASSERT_PTR_NOT_NULL (proxy); + identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + + + proxy_address=linphone_address_new(linphone_proxy_config_get_addr(proxy)); + linphone_address_clean(proxy_address); + tmp=linphone_address_as_string_uri_only(proxy_address); + linphone_proxy_config_set_server_addr(proxy,tmp); + linphone_proxy_config_set_route(proxy,NULL); + ms_free(tmp); + linphone_address_destroy(proxy_address); + linphone_core_get_sip_transports(lc_marie,&transport); + transport.udp_port=0; + transport.tls_port=0; + transport.dtls_port=0; + /*only keep tcp*/ + linphone_core_set_sip_transports(lc_marie,&transport); + stat_marie->number_of_LinphoneRegistrationOk=0; + + CU_ASSERT_TRUE (wait_for(lc_marie,lc_marie,&stat_marie->number_of_LinphoneRegistrationOk,1)); + + linphone_core_invite(lc_marie,"pauline"); + + CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(lc_pauline)); + if (linphone_core_get_current_call_remote_address(lc_pauline)) { + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); + + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); + /*just to sleep*/ + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void cancelled_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); @@ -619,6 +683,7 @@ test_t call_tests[] = { { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, { "Simple call", simple_call }, + { "Simple call compatibility mode", simple_call_compatibility_mode }, { "Early-media call", early_media_call }, { "Call terminated by caller", call_terminated_by_caller }, { "Call paused resumed", call_paused_resumed }, diff --git a/tester/message_tester.c b/tester/message_tester.c index ad172e472..730546a7d 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -72,6 +72,41 @@ static void text_message(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void text_message_compatibility_mode(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneProxyConfig* proxy; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + char* to = linphone_address_as_string(pauline->identity); + + linphone_core_get_default_proxy(marie->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL (proxy); + proxy_address=linphone_address_new(linphone_proxy_config_get_addr(proxy)); + linphone_address_clean(proxy_address); + tmp=linphone_address_as_string_uri_only(proxy_address); + linphone_proxy_config_set_server_addr(proxy,tmp); + linphone_proxy_config_set_route(proxy,NULL); + ms_free(tmp); + linphone_address_destroy(proxy_address); + linphone_core_get_sip_transports(marie->lc,&transport); + transport.udp_port=0; + transport.tls_port=0; + transport.dtls_port=0; + /*only keep tcp*/ + linphone_core_set_sip_transports(marie->lc,&transport); + marie->stat.number_of_LinphoneRegistrationOk=0; + + CU_ASSERT_TRUE (wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,1)); + + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceivedLegacy,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} static void text_message_with_ack(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); @@ -126,6 +161,7 @@ static void text_message_with_send_error(void) { test_t message_tests[] = { { "Text message", text_message }, + { "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 } diff --git a/tester/register_tester.c b/tester/register_tester.c index f60ebe4a5..0b5483f43 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -47,9 +47,8 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } -static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route,bool_t late_auth_info) { +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) { int retry=0; - LCSipTransports transport = {5070,5070,0,5071}; char* addr; LinphoneProxyConfig* proxy_cfg; stats* counters; @@ -102,7 +101,8 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const } static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - register_with_refresh_base_2(lc,refresh,domain,route,FALSE); + LCSipTransports transport = {5070,5070,0,5071}; + register_with_refresh_base_2(lc,refresh,domain,route,FALSE,transport); } static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { @@ -169,6 +169,14 @@ static void simple_tcp_register(){ register_with_refresh(lc,FALSE,test_domain,route); } +static void simple_tcp_register_compatibility_mode(){ + LinphoneCore* lc; + LCSipTransports transport = {0,5070,0,0}; + lc = create_lc(); + register_with_refresh_base_2(lc,FALSE,test_domain,NULL,FALSE,transport); +} + + static void simple_tls_register(){ char route[256]; LinphoneCore* lc; @@ -221,6 +229,7 @@ static void authenticated_register_with_late_credentials(){ LinphoneCore* lc; stats stat; stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; char route[256]; sprintf(route,"sip:%s",test_route); memset (&v_table,0,sizeof(v_table)); @@ -229,7 +238,7 @@ static void authenticated_register_with_late_credentials(){ lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); counters = (stats*)linphone_core_get_user_data(lc); - register_with_refresh_base_2(lc,FALSE,auth_domain,route,TRUE); + register_with_refresh_base_2(lc,FALSE,auth_domain,route,TRUE,transport); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_destroy(lc); } @@ -331,6 +340,7 @@ static void io_recv_error(){ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, + { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, #ifndef ANDROID { "TLS register", simple_tls_register }, #endif From 5cff1fa5b119dc2bc6abe831ce584339f04b80e9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 26 Mar 2013 09:13:46 +0100 Subject: [PATCH 181/909] fix compilation issue with upnp --- coreapi/upnp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 2dfd7f39c..75d0ef9e2 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -338,7 +338,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, NULL, lupnp); if(lupnp->upnp_igd_ctxt == NULL) { lupnp->state = LinphoneUpnpStateKo; ms_error("Can't create uPnP IGD context"); From 87874f64373723390456a38821e5dc8e00c36120 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 21 Mar 2013 11:49:26 +0100 Subject: [PATCH 182/909] patch for gtk --- gtk/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gtk/main.c b/gtk/main.c index c6065241c..ae6c8a010 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -63,12 +63,15 @@ 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); +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); +static gint main_window_x=0; +static gint main_window_y=0; static gboolean verbose=0; static gboolean auto_answer = 0; static gchar * addr_to_call = NULL; @@ -1371,11 +1374,20 @@ static GtkWidget *create_icon_menu(){ return menu; } +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); +} + static void handle_icon_click() { 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); } } From 8aea715e6f3bdc18a0d7f4a4c852059fb94d0384 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 21 Mar 2013 17:12:16 +0100 Subject: [PATCH 183/909] menu in call log view with call, chat and add contact --- coreapi/linphonefriend.h | 7 ++ gtk/call_logs.ui | 2 + gtk/calllogs.c | 167 +++++++++++++++++++++++++++++++++------ gtk/friendlist.c | 113 +++++++++++++++++--------- gtk/linphone.h | 1 + gtk/main.ui | 2 - 6 files changed, 225 insertions(+), 67 deletions(-) diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index ab75b7bf7..6eb2ab2a2 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -132,6 +132,13 @@ void linphone_friend_destroy(LinphoneFriend *lf); */ int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneAddress* address); +/** + * set the display name for this friend + * @param lf #LinphoneFriend object + * @param name + */ +int linphone_friend_set_name(LinphoneFriend *lf, const char *name); + /** * get address of this friend * @param lf #LinphoneFriend object 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/calllogs.c b/gtk/calllogs.c index ce4695dd2..2ca86beab 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -47,6 +47,145 @@ void call_log_selection_changed(GtkTreeView *v){ } } +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 pla; + LinphoneAddress *la; + gtk_tree_model_get(model,&iter,2,&pla,-1); + la=(LinphoneAddress*)pla; + if (la!=NULL){ + linphone_gtk_tree_view_set_chat_conversation(la); + } + } + } +} + +void linphone_gtk_call_log_add_contact(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 pla; + LinphoneAddress *la; + LinphoneFriend *lf; + gtk_tree_model_get(model,&iter,2,&pla,-1); + la=(LinphoneAddress*)pla; + if (la!=NULL){ + char *uri=linphone_address_as_string(la); + lf=linphone_friend_new_with_addr(uri); + linphone_gtk_show_contact(lf); + 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)){ + 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; +} + +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 pla; + LinphoneAddress *la; + gtk_tree_model_get(model,&iter,2,&pla,-1); + la=(LinphoneAddress*)pla; + name=linphone_address_as_string(la); + call_label=g_strdup_printf(_("Call %s"),name); + text_label=g_strdup_printf(_("Send text to %s"),name); + g_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_update(GtkWidget *w){ GtkTreeView *v=GTK_TREE_VIEW(linphone_gtk_get_widget(w,"logs_view")); GtkTreeStore *store; @@ -62,6 +201,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){ 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(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"))); } @@ -149,28 +289,6 @@ void linphone_gtk_call_log_update(GtkWidget *w){ } -static bool_t put_selection_to_uribar(GtkWidget *treeview){ - GtkTreeSelection *sel; - - sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if (sel!=NULL){ - GtkTreeModel *model=NULL; - GtkTreeIter iter; - if (gtk_tree_selection_get_selected (sel,&model,&iter)){ - 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){ if (put_selection_to_uribar(treeview)){ GtkWidget *mw=linphone_gtk_get_main_window(); @@ -207,8 +325,6 @@ 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(); @@ -223,5 +339,4 @@ GtkWidget * linphone_gtk_show_call_logs(void){ linphone_gtk_call_log_update(w); }else gtk_window_present(GTK_WINDOW(w)); return w; -} - +} \ No newline at end of file diff --git a/gtk/friendlist.c b/gtk/friendlist.c index e1012f7cd..9f5a935b8 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -195,38 +195,11 @@ void linphone_gtk_create_chat_picture(gboolean active){ GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); if (gtk_tree_model_get_iter_first(model,&iter)) { do{ - if(!active){ + //if(!active){ gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); - } 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; - char *uri=(char *)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)), - 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); - } - } - } + //} 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)); } } @@ -236,6 +209,66 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } +void linphone_gtk_tree_view_set_chat_conversation(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"); + char *la_str=linphone_address_as_string(la); + + lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),la_str); + if(lf==NULL){ + cr=linphone_gtk_create_chatroom(la); + g_object_set_data(G_OBJECT(friendlist),"from",la_str); + 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_create_chat_picture(FALSE); + 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; + char *lf_str; + gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + uri=linphone_friend_get_address(lf); + lf_str=linphone_address_as_string(uri); + if( g_strcmp0(lf_str,la_str)==0){ + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + if(cr==NULL){ + cr=linphone_gtk_create_chatroom(uri); + gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); + } + g_object_set_data(G_OBJECT(friendlist),"from",linphone_address_as_string(uri)); + 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_create_chat_picture(FALSE); + g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); + gtk_list_store_set(store,&iter,FRIEND_CHAT,create_active_chat_picture(),-1); + gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,"",-1); + break; + } + }while(gtk_tree_model_iter_next(model,&iter)); + } + } + +} + void linphone_gtk_chat_selected(GtkWidget *item){ GtkWidget *w=gtk_widget_get_toplevel(item); GtkTreeSelection *select; @@ -734,7 +767,6 @@ void linphone_gtk_show_friends(void){ if(nbmsg != 0){ sprintf(buf,"%i",nbmsg); } - } gtk_list_store_set(store,&iter,FRIEND_CALL,create_call_picture(),-1); @@ -743,7 +775,7 @@ void linphone_gtk_show_friends(void){ 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(); + //linphone_gtk_update_chat_picture(); //bi=linphone_friend_get_info(lf); /*if (bi!=NULL && bi->image_data!=NULL){ GdkPixbuf *pbuf= @@ -787,6 +819,7 @@ 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"); + LinphoneFriend *lf2; char *fixed_uri=NULL; gboolean show_presence=FALSE,allow_presence=FALSE; const gchar *name,*uri; @@ -811,16 +844,20 @@ void linphone_gtk_contact_ok(GtkWidget *button){ 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_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 { + lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),fixed_uri); + if(lf2==NULL){ + linphone_friend_set_name(lf,name); + linphone_core_add_friend(linphone_gtk_get_core(),lf); + } } + ms_free(fixed_uri); linphone_gtk_show_friends(); gtk_widget_destroy(w); } @@ -997,6 +1034,4 @@ gboolean linphone_gtk_contact_list_button_pressed(GtkWidget *widget, GdkEventBut void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf){ /*refresh the entire list*/ linphone_gtk_show_friends(); -} - - +} \ No newline at end of file diff --git a/gtk/linphone.h b/gtk/linphone.h index a7d7da506..ccdebea69 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -153,3 +153,4 @@ void linphone_gtk_unmonitor_usb(void); gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); void linphone_gtk_friend_list_update_message(LinphoneChatMessage *msg); +void linphone_gtk_tree_view_set_chat_conversation(LinphoneAddress *la); diff --git a/gtk/main.ui b/gtk/main.ui index e1c8c9129..0b27240e7 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -313,7 +313,6 @@ True False - label center @@ -368,7 +367,6 @@ True False - label True From 7bf3cb7654d84c6166e5f6f2fbcaddf08ed5f861 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 27 Mar 2013 10:45:06 +0100 Subject: [PATCH 184/909] fix compilation issue --- gtk/main.c | 3 ++- mediastreamer2 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index ae6c8a010..b188782ab 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -69,9 +69,10 @@ void linphone_gtk_status_icon_set_blinking(gboolean val); void _linphone_gtk_enable_video(gboolean val); - +#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 gchar * addr_to_call = NULL; diff --git a/mediastreamer2 b/mediastreamer2 index 4b8d2b655..5a7ae95e0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4b8d2b655acc8a329464e7806653dceb04ade445 +Subproject commit 5a7ae95e0dbe5f485086d4635a655c893c9c44b1 From a9dee01c72bfa34c52a8bab61a24e413e166d2fc Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 27 Mar 2013 10:54:37 +0100 Subject: [PATCH 185/909] fix display name in call_log --- gtk/calllogs.c | 16 ++++++++++++---- po/README | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 2ca86beab..9d2714153 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -210,13 +210,14 @@ void linphone_gtk_call_log_update(GtkWidget *w){ for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){ LinphoneCallLog *cl=(LinphoneCallLog*)logs->data; GtkTreeIter iter, iter2; - 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); + const LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + char *addr= linphone_address_as_string(la); const char *display; gchar *logtxt, *headtxt, *minutes, *seconds; 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); @@ -229,12 +230,19 @@ void linphone_gtk_call_log_update(GtkWidget *w){ #else start_date=g_strdup(ctime(&start_date_time)); #endif + lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr); + if(lf != NULL){ + la=linphone_friend_get_address(lf); + display=linphone_address_get_display_name(la); + } else { + display=linphone_address_get_display_name(la); + } - 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)); diff --git a/po/README b/po/README index adec33171..19a1dbd53 100644 --- a/po/README +++ b/po/README @@ -5,7 +5,7 @@ To add a translation file in linphone project you should first : - then add the file .po in the directory /po - run ./autogen.sh -Update the tranlation files +Update the translation files *************************** To update all the translation files, in the directory /po run the following command $ make update-po From 84dc96eccbd7bd4d57acd4e944b0cf02233c8b9c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 27 Mar 2013 16:40:27 +0100 Subject: [PATCH 186/909] implement tls and dscp options --- coreapi/bellesip_sal/sal_impl.c | 55 +++++++++++++++++++++++++++------ coreapi/bellesip_sal/sal_impl.h | 3 ++ tester/register_tester.c | 2 +- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index fce3582f9..3bd0fc1eb 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -17,9 +17,14 @@ 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 + +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) { @@ -384,6 +389,8 @@ Sal * sal_init(){ 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; return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ @@ -445,6 +452,7 @@ void sal_uninit(Sal* sal){ belle_sip_object_unref(sal->prov); belle_sip_object_unref(sal->stack); belle_sip_object_unref(sal->listener); + if (sal->root_ca) ms_free(sal->root_ca); ms_free(sal); return ; }; @@ -458,11 +466,13 @@ int sal_add_listen_port(Sal *ctx, SalAddress* addr){ if (lp) { belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); result = belle_sip_provider_add_listening_point(ctx->prov,lp); + set_tls_properties(ctx); } else { return -1; } return result; } + int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure) { SalAddress* sal_addr = sal_address_new(NULL); int result; @@ -538,16 +548,41 @@ void sal_use_101(Sal *ctx, bool_t use_101){ ms_warning("sal_use_101 is deprecated"); 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); + belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions); + } +} + void sal_set_root_ca(Sal* ctx, const char* rootCa){ - ms_error("sal_set_root_ca not implemented yet"); + 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){ - ms_error("sal_verify_server_certificates not implemented yet"); + ctx->tls_verify=verify; + set_tls_properties(ctx); return ; } + void sal_verify_server_cn(Sal *ctx, bool_t verify){ - ms_error("sal_verify_server_cn not implemented yet"); + ctx->tls_verify_cn=verify; + set_tls_properties(ctx); return ; } @@ -569,21 +604,23 @@ MSList * sal_get_pending_auths(Sal *sal){ /*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("Could not find default routable ip address !"); + ms_error("sal_get_default_local_ip() is deprecated."); } const char *sal_get_root_ca(Sal* ctx) { - ms_fatal("sal_get_root_ca not implemented yet"); - return NULL; + return ctx->root_ca; } + int sal_reset_transports(Sal *ctx){ - ms_message("reseting transport"); + ms_message("reseting transports"); belle_sip_provider_clean_channels(ctx->prov); return 0; } + void sal_set_dscp(Sal *ctx, int dscp){ - ms_warning("sal_set_dscp not implemented"); + 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); } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index c0e650f97..56b5bd514 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -36,9 +36,12 @@ struct Sal{ void *up; /*user pointer*/ int session_expires; unsigned int keep_alive; + char *root_ca; 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; }; typedef enum SalOpSate { diff --git a/tester/register_tester.c b/tester/register_tester.c index 0b5483f43..3d2afa1d0 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -49,7 +49,7 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c 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) { int retry=0; - char* addr; + char* addr; LinphoneProxyConfig* proxy_cfg; stats* counters; LinphoneAddress *from; From 6d4297bb4632f315865f16b8bccc6d62fe9d8e91 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 27 Mar 2013 20:05:25 +0100 Subject: [PATCH 187/909] use git describe --always --- coreapi/Makefile.am | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index bef0613b5..91fc9bd22 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,6 +1,6 @@ GITVERSION_FILE=liblinphone_gitversion.h GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp -GITDESCRIBE=`git describe` +GITDESCRIBE=`git describe --always` GITREVISION=`git rev-parse HEAD` ECHO=/bin/echo diff --git a/mediastreamer2 b/mediastreamer2 index 5a7ae95e0..8596ed901 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5a7ae95e0dbe5f485086d4635a655c893c9c44b1 +Subproject commit 8596ed9017c0d9b9c63c758d7628bac1fc07efd7 From 73763d057d3fb331b796f4c1f9e7d0007a58627c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 27 Mar 2013 20:34:06 +0100 Subject: [PATCH 188/909] configure cosmetic fixes --- configure.ac | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b48c0ff64..e9835e1e5 100644 --- a/configure.ac +++ b/configure.ac @@ -862,7 +862,7 @@ fi if test $USE_BELLESIP_TRUE !='#' ; then printf "* bellesip stack\t\t\ttrue\n" else - printf "* eXosip stack\t\ttrue\n" + printf "* eXosip stack\t\t\ttrue\n" fi if test "$build_upnp" = "true" ; then printf "* upnp support\t\t\ttrue\n" diff --git a/oRTP b/oRTP index c702c0ea0..913661226 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c702c0ea0e66bbe1f27c79690003d9748b01560f +Subproject commit 9136612268a133eaf0b3ea2e7fd0869bdd0b6686 From 049436e8ea21820757dad39c1181db642623cdfe Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 28 Mar 2013 12:56:24 +0100 Subject: [PATCH 189/909] Added exports --- coreapi/linphonecore.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 934db0490..5e2c1f77e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1238,11 +1238,11 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val); /* returns a list of LinphoneCallLog */ -const MSList * linphone_core_get_call_logs(LinphoneCore *lc); -void linphone_core_clear_call_logs(LinphoneCore *lc); -int linphone_core_get_missed_calls_count(LinphoneCore *lc); -void linphone_core_reset_missed_calls_count(LinphoneCore *lc); -void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); +LINPHONE_PUBLIC const MSList * linphone_core_get_call_logs(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_clear_call_logs(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_missed_calls_count(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_reset_missed_calls_count(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); /* video support */ bool_t linphone_core_video_supported(LinphoneCore *lc); From ed9a9acb8c804ec26f9210cecf9dff6f0e55b9f0 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 28 Mar 2013 14:31:41 +0100 Subject: [PATCH 190/909] Updated Hungarian translation. --- po/hu.po | 846 ++++++++++++++++++++++++++----------------------------- 1 file changed, 392 insertions(+), 454 deletions(-) diff --git a/po/hu.po b/po/hu.po index 819bb2210..54f7821a5 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,53 +1,49 @@ -# 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. -# +# Hungarian translation for Linphone. +# Copyright 2013. +# This file is distributed under the same license as the linphone package. +# msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: Linphone\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-07 12:30+0100\n" -"PO-Revision-Date: 2007-12-14 11:12+0100\n" -"Last-Translator: \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"PO-Revision-Date: 2013-03-26 19:00+0100\n" +"Last-Translator: Viktor \n" +"Language-Team: \n" +"Language: Hungarian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" +"Plural-Forms: nplurals=1; plural=1 == 1 ? 0 : 1;\n" #: ../gtk/calllogs.c:82 msgid "n/a" -msgstr "" +msgstr "-" #: ../gtk/calllogs.c:85 -#, fuzzy msgid "Aborted" -msgstr "megszakítva" +msgstr "Megszakítva" #: ../gtk/calllogs.c:88 -#, fuzzy msgid "Missed" -msgstr "elhibázva" +msgstr "Nem fogadott" #: ../gtk/calllogs.c:91 -#, fuzzy msgid "Declined" -msgstr "line" +msgstr "Elutasítva" #: ../gtk/calllogs.c:97 #, c-format msgid "%i minute" msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i perc" #: ../gtk/calllogs.c:100 #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i másodperc" #: ../gtk/calllogs.c:103 #, c-format @@ -55,6 +51,8 @@ msgid "" "%s\t%s\tQuality: %s\n" "%s\t%s %s\t" msgstr "" +"%s\t%s\tMinőség: %s\n" +"%s\t%s %s\t" #: ../gtk/calllogs.c:108 #, c-format @@ -62,14 +60,16 @@ msgid "" "%s\t%s\t\n" "%s\t%s" msgstr "" +"%s\t%s\t\n" +"%s\t%s" #: ../gtk/conference.c:38 ../gtk/main.ui.h:14 msgid "Conference" -msgstr "" +msgstr "Konferencia" #: ../gtk/conference.c:46 msgid "Me" -msgstr "" +msgstr "én" #: ../gtk/support.c:49 ../gtk/support.c:73 ../gtk/support.c:102 #, c-format @@ -78,38 +78,40 @@ msgstr "Nemtalálható a pixmap fájl: %s" #: ../gtk/main.c:88 msgid "log to stdout some debug information while running." -msgstr "" +msgstr "Futás közben némi hibakeresési információ az stdout-ra naplózása." #: ../gtk/main.c:95 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:102 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Linphone indítása, videó kikpacsolva. " #: ../gtk/main.c:109 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:116 msgid "address to call right now" -msgstr "" +msgstr "Cím azonnali híváshoz" #: ../gtk/main.c:123 msgid "if set automatically answer incoming calls" -msgstr "" +msgstr "Bekapcsolva automatikusan válaszol a bejövő hívásokra" #: ../gtk/main.c:130 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:510 -#, fuzzy, c-format +#, c-format msgid "Call with %s" -msgstr "Chat-elés %s -el" +msgstr "Hívás %s -el" #: ../gtk/main.c:941 #, c-format @@ -119,6 +121,10 @@ msgid "" "list ?\n" "If you answer no, this person will be temporarily blacklisted." msgstr "" +"%s szeretné Önt hozzáadni partnerlistájához.\n" +"Szeretné megengedni neki, hogy lássa az Ön jelenlétét, illetve hozzá " +"szeretné adni a partnerlistához?\n" +"Ha nemmel válaszol, ez a személy átmenetileg tiltólistára kerül." #: ../gtk/main.c:1018 #, c-format @@ -126,11 +132,12 @@ msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" +"Kérem, adja meg jelszavát a következő felhasználónévhez: %s\n" +"tartomány %s:" #: ../gtk/main.c:1121 -#, fuzzy msgid "Call error" -msgstr "Linphone - Híváselőzmények" +msgstr "Hiba a hívás közben" #: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 msgid "Call ended" @@ -142,60 +149,59 @@ msgstr "Beérkező hívás" #: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 msgid "Answer" -msgstr "" +msgstr "Hívás fogadása" #: ../gtk/main.c:1131 ../gtk/main.ui.h:7 -#, fuzzy msgid "Decline" -msgstr "line" +msgstr "Elutasítás" #: ../gtk/main.c:1137 -#, fuzzy msgid "Call paused" -msgstr "megszakítva" +msgstr "Hívás várakoztatva" #: ../gtk/main.c:1137 -#, fuzzy, c-format +#, c-format msgid "by %s" -msgstr "Kapcsolatilista" +msgstr "a következő által: %s" #: ../gtk/main.c:1186 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "%s szerené elidítani a videót. Elfogadja?" #: ../gtk/main.c:1348 msgid "Website link" -msgstr "" +msgstr "Internetes oldal" #: ../gtk/main.c:1388 msgid "Linphone - a video internet phone" -msgstr "" +msgstr "Linphone - internetes videó telefon" #: ../gtk/main.c:1480 #, c-format msgid "%s (Default)" -msgstr "" +msgstr "%s (Alapértelmezett)" #: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 #, c-format msgid "We are transferred to %s" -msgstr "" +msgstr "Át vagyunk irányítva ide: %s" #: ../gtk/main.c:1792 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:1896 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" #: ../gtk/friendlist.c:366 -#, fuzzy msgid "Add to addressbook" -msgstr "Címjegyzék" +msgstr "Hozzáadás címjegyzékhez" #: ../gtk/friendlist.c:540 msgid "Presence status" @@ -206,48 +212,46 @@ msgid "Name" msgstr "Név" #: ../gtk/friendlist.c:569 -#, fuzzy msgid "Call" -msgstr "Hivás előzmények" +msgstr "Hivás" #: ../gtk/friendlist.c:574 -#, fuzzy msgid "Chat" -msgstr "Chat szoba" +msgstr "Csevegés" #: ../gtk/friendlist.c:604 #, c-format msgid "Search in %s directory" -msgstr "" +msgstr "Keresés ebben a könyvtárban: %s" #: ../gtk/friendlist.c:762 msgid "Invalid sip contact !" -msgstr "" +msgstr "Érvénytelen sip partner !" #: ../gtk/friendlist.c:807 -#, fuzzy, c-format +#, c-format msgid "Call %s" -msgstr "Hivás előzmények" +msgstr "%s hívása" #: ../gtk/friendlist.c:808 #, c-format msgid "Send text to %s" -msgstr "" +msgstr "Szöveg küldése a következőnek: %s" #: ../gtk/friendlist.c:809 -#, fuzzy, c-format +#, c-format msgid "Edit contact '%s'" -msgstr "Kapcsolatinformációk szerkesztése" +msgstr "Kapcsolatinformációk szerkesztése: '%s'" #: ../gtk/friendlist.c:810 #, c-format msgid "Delete contact '%s'" -msgstr "" +msgstr "'%s' partner törlése" #: ../gtk/friendlist.c:852 #, 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:373 msgid "Rate (Hz)" @@ -279,76 +283,78 @@ msgstr "Hozzáférés" #: ../gtk/propertybox.c:764 msgid "English" -msgstr "" +msgstr "angol" #: ../gtk/propertybox.c:765 msgid "French" -msgstr "" +msgstr "francia" #: ../gtk/propertybox.c:766 msgid "Swedish" -msgstr "" +msgstr "svéd" #: ../gtk/propertybox.c:767 msgid "Italian" -msgstr "" +msgstr "olasz" #: ../gtk/propertybox.c:768 msgid "Spanish" -msgstr "" +msgstr "spanyol" #: ../gtk/propertybox.c:769 msgid "Brazilian Portugese" -msgstr "" +msgstr "brazil-portugál" #: ../gtk/propertybox.c:770 msgid "Polish" -msgstr "" +msgstr "lengyel" #: ../gtk/propertybox.c:771 msgid "German" -msgstr "" +msgstr "német" #: ../gtk/propertybox.c:772 msgid "Russian" -msgstr "" +msgstr "orosz" #: ../gtk/propertybox.c:773 msgid "Japanese" -msgstr "" +msgstr "japán" #: ../gtk/propertybox.c:774 msgid "Dutch" -msgstr "" +msgstr "holland" #: ../gtk/propertybox.c:775 msgid "Hungarian" -msgstr "" +msgstr "magyar" #: ../gtk/propertybox.c:776 msgid "Czech" -msgstr "" +msgstr "cseh" #: ../gtk/propertybox.c:777 msgid "Chinese" -msgstr "" +msgstr "egyszerúsített kínai" #: ../gtk/propertybox.c:778 msgid "Traditional Chinese" -msgstr "" +msgstr "tradícionális kínai" #: ../gtk/propertybox.c:779 msgid "Norwegian" -msgstr "" +msgstr "norvég" #: ../gtk/propertybox.c:780 msgid "Hebrew" -msgstr "" +msgstr "héber" #: ../gtk/propertybox.c:847 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:933 msgid "None" @@ -356,11 +362,11 @@ msgstr "Nincs" #: ../gtk/propertybox.c:937 msgid "SRTP" -msgstr "" +msgstr "SRTP" #: ../gtk/propertybox.c:943 msgid "ZRTP" -msgstr "" +msgstr "ZRTP" #: ../gtk/update.c:80 #, c-format @@ -368,125 +374,123 @@ 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 msgid "Found %i contact" msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Találat: %i partner" #: ../gtk/setupwizard.c:34 msgid "" "Welcome !\n" "This assistant will help you to use a SIP account for your calls." msgstr "" +"Üdvözöljük !\n" +"Ez a varázsló segít Önnek, hogy sip fiókot használjon hívásaihoz." #: ../gtk/setupwizard.c:43 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Fiók létrehozása a linphone.org -on" #: ../gtk/setupwizard.c:44 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:45 msgid "I have already a sip account and I just want to use it" -msgstr "" +msgstr "Már rendelkezem sip fiókkal, azt szeretném használni" #: ../gtk/setupwizard.c:85 msgid "Enter your linphone.org username" -msgstr "" +msgstr "Adja meg linphone.org felhasználónevét" #: ../gtk/setupwizard.c:92 -#, fuzzy msgid "Username:" -msgstr "felhasználónév:" +msgstr "Felhasználónév:" #: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 -#, fuzzy msgid "Password:" -msgstr "jelszó:" +msgstr "Jelszó:" #: ../gtk/setupwizard.c:114 msgid "Enter your account informations" -msgstr "" +msgstr "Írja be fiókinformációit" #: ../gtk/setupwizard.c:121 -#, fuzzy msgid "Username*" -msgstr "felhasználónév:" +msgstr "Felhasználónév*" #: ../gtk/setupwizard.c:122 -#, fuzzy msgid "Password*" -msgstr "jelszó:" +msgstr "Jelszó*" #: ../gtk/setupwizard.c:125 msgid "Domain*" -msgstr "" +msgstr "Tartomány" #: ../gtk/setupwizard.c:126 msgid "Proxy" -msgstr "" +msgstr "Proxy" #: ../gtk/setupwizard.c:298 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Mező kitöltése szükséges" #: ../gtk/setupwizard.c:299 -#, fuzzy msgid "Username: (*)" -msgstr "felhasználónév:" +msgstr "Felhasználónév: (*)" #: ../gtk/setupwizard.c:301 -#, fuzzy msgid "Password: (*)" -msgstr "jelszó:" +msgstr "Jelszó: (*)" #: ../gtk/setupwizard.c:303 msgid "Email: (*)" -msgstr "" +msgstr "E-mail: (*)" #: ../gtk/setupwizard.c:305 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Jelszó megerősítése: (*)" #: ../gtk/setupwizard.c:369 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:380 msgid "Thank you. Your account is now configured and ready for use." -msgstr "" +msgstr "Köszönjük! Az Ön fiókját beállítottuk és használatra kész." #: ../gtk/setupwizard.c:388 msgid "" @@ -494,105 +498,103 @@ msgid "" "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:564 msgid "Welcome to the account setup assistant" -msgstr "" +msgstr "A fiók beállítása varázsló üdvözli Önt" #: ../gtk/setupwizard.c:569 msgid "Account setup assistant" -msgstr "" +msgstr "Fiók beállítása varázsló" #: ../gtk/setupwizard.c:575 msgid "Configure your account (step 1/1)" -msgstr "" +msgstr "Az Ön fiókjának beállítása (1/1 lépés)" #: ../gtk/setupwizard.c:580 msgid "Enter your sip username (step 1/1)" -msgstr "" +msgstr "Adja meg sip felhasználónevét (1/2 lépés)" #: ../gtk/setupwizard.c:584 msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "Adja meg a fiókinformációt (1/2 lépés)" #: ../gtk/setupwizard.c:593 msgid "Validation (step 2/2)" -msgstr "" +msgstr "Érvényesítés (2/2 lépés)" #: ../gtk/setupwizard.c:598 msgid "Error" -msgstr "" +msgstr "Hiba" #: ../gtk/setupwizard.c:602 msgid "Terminating" -msgstr "" +msgstr "Befejezés" #: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 -#, fuzzy, c-format +#, c-format msgid "Call #%i" -msgstr "Hivás előzmények" +msgstr "Hívás #%i" #: ../gtk/incall_view.c:154 #, 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:210 ../gtk/incall_view.c:213 msgid "Not used" -msgstr "" +msgstr "Nem használt" #: ../gtk/incall_view.c:220 msgid "ICE not activated" -msgstr "" +msgstr "ICE nincs aktiválva" #: ../gtk/incall_view.c:222 -#, fuzzy msgid "ICE failed" -msgstr "Hívás elutasítva" +msgstr "ICE nem sikerült" #: ../gtk/incall_view.c:224 msgid "ICE in progress" -msgstr "" +msgstr "ICE folyamatban" #: ../gtk/incall_view.c:226 msgid "Going through one or more NATs" -msgstr "" +msgstr "Átmegy egy vagy több NAT-on" #: ../gtk/incall_view.c:228 -#, fuzzy msgid "Direct" -msgstr "Átirányítva idw %s..." +msgstr "Közvetlen" #: ../gtk/incall_view.c:230 msgid "Through a relay server" -msgstr "" +msgstr "Közvetítő kiszolgálón keresztül" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" -msgstr "" +msgstr "uPnP nincs aktiválva" #: ../gtk/incall_view.c:240 -#, fuzzy msgid "uPnP in progress" -msgstr "Stun keresés folyamatban..." +msgstr "uPnP folyamatban" #: ../gtk/incall_view.c:242 -#, fuzzy msgid "uPnp not available" -msgstr "Nem érhető el információ" +msgstr "uPnP nem elérhető" #: ../gtk/incall_view.c:244 msgid "uPnP is running" -msgstr "" +msgstr "uPnP fut" #: ../gtk/incall_view.c:246 -#, fuzzy msgid "uPnP failed" -msgstr "Hívás elutasítva" +msgstr "uPnP nem sikerült" #: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 msgid "Direct or through server" -msgstr "" +msgstr "közvetlen vagy kiszolgálón keresztül" #: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 #, c-format @@ -600,115 +602,111 @@ msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"letöltés: %f\n" +"feltöltés: %f (kbit/mp)" #: ../gtk/incall_view.c:286 #, c-format msgid "%.3f seconds" -msgstr "" +msgstr "%.3f másodperc" #: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 msgid "Hang up" -msgstr "" +msgstr "Befejezés" #: ../gtk/incall_view.c:477 -#, fuzzy msgid "Calling..." -msgstr "Kapcsolatilista" +msgstr "Hívás folyamatban..." #: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 msgid "00::00::00" -msgstr "" +msgstr "00::00::00" #: ../gtk/incall_view.c:491 -#, fuzzy msgid "Incoming call" -msgstr "Beérkező hívás" +msgstr "Beérkező hívás" #: ../gtk/incall_view.c:528 msgid "good" -msgstr "" +msgstr "jó" #: ../gtk/incall_view.c:530 msgid "average" -msgstr "" +msgstr "közepes" #: ../gtk/incall_view.c:532 msgid "poor" -msgstr "" +msgstr "gyenge" #: ../gtk/incall_view.c:534 msgid "very poor" -msgstr "" +msgstr "nagyon gyenge" #: ../gtk/incall_view.c:536 msgid "too bad" -msgstr "" +msgstr "rossz" #: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 msgid "unavailable" -msgstr "" +msgstr "nem elérhető" #: ../gtk/incall_view.c:652 msgid "Secured by SRTP" -msgstr "" +msgstr "SRTP-vel titkosítva" #: ../gtk/incall_view.c:658 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" #: ../gtk/incall_view.c:664 msgid "Set unverified" -msgstr "" +msgstr "Beállítás ellenőrizetlenként" #: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 msgid "Set verified" -msgstr "" +msgstr "Beállítás ellenőrzöttként" #: ../gtk/incall_view.c:685 msgid "In conference" -msgstr "" +msgstr "Konferencián" #: ../gtk/incall_view.c:685 -#, fuzzy msgid "In call" -msgstr "Kapcsolatilista" +msgstr "vonalban" #: ../gtk/incall_view.c:719 -#, fuzzy msgid "Paused call" -msgstr "Kapcsolatilista" +msgstr "Várakoztatott hívás" #: ../gtk/incall_view.c:732 #, c-format msgid "%02i::%02i::%02i" -msgstr "" +msgstr "%02i::%02i::%02i" #: ../gtk/incall_view.c:749 -#, fuzzy msgid "Call ended." -msgstr "Hívás vége" +msgstr "Hívás vége." #: ../gtk/incall_view.c:779 msgid "Transfer in progress" -msgstr "" +msgstr "Átvitel folyamatban" #: ../gtk/incall_view.c:782 msgid "Transfer done." -msgstr "" +msgstr "Átvitel befejezve." #: ../gtk/incall_view.c:785 -#, fuzzy msgid "Transfer failed." -msgstr "Hívás elutasítva" +msgstr "Az átvitel sikertelen." #: ../gtk/incall_view.c:829 msgid "Resume" -msgstr "" +msgstr "Visszatérés" #: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 msgid "Pause" -msgstr "" +msgstr "Várakoztatás" #: ../gtk/incall_view.c:901 #, c-format @@ -716,115 +714,109 @@ msgid "" "Recording into\n" "%s %s" msgstr "" +"Felvétel a következőbe\n" +"%s %s" #: ../gtk/incall_view.c:901 msgid "(Paused)" -msgstr "" +msgstr "(Várakoztatva)" #: ../gtk/loginframe.c:93 #, c-format msgid "Please enter login information for %s" -msgstr "" +msgstr "Kérem, adja meg a bejelentkezési információt %s -hoz" #: ../gtk/main.ui.h:1 -#, fuzzy msgid "Callee name" -msgstr "Hívás vége" +msgstr "Hívott neve" #: ../gtk/main.ui.h:2 -#, fuzzy msgid "Send" -msgstr "Hang" +msgstr "Küld" #: ../gtk/main.ui.h:3 msgid "End conference" -msgstr "" +msgstr "Konferencia vége" #: ../gtk/main.ui.h:4 msgid "label" -msgstr "" +msgstr "címke" #: ../gtk/main.ui.h:8 msgid "Record this call to an audio file" -msgstr "" +msgstr "Beszélgetés felvétele hangfájlba" #: ../gtk/main.ui.h:9 msgid "Video" -msgstr "" +msgstr "Videó" #: ../gtk/main.ui.h:11 msgid "Mute" -msgstr "" +msgstr "Elnémítás" #: ../gtk/main.ui.h:12 msgid "Transfer" -msgstr "" +msgstr "Átvitel" #: ../gtk/main.ui.h:15 -#, fuzzy msgid "In call" -msgstr "Beérkező hívás" +msgstr "vonalban" #: ../gtk/main.ui.h:16 -#, fuzzy msgid "Duration" -msgstr "Információk" +msgstr "Időtartam" #: ../gtk/main.ui.h:17 msgid "Call quality rating" -msgstr "" +msgstr "Hívásminőség" #: ../gtk/main.ui.h:18 msgid "_Options" -msgstr "" +msgstr "_Beállítások" #: ../gtk/main.ui.h:19 msgid "Always start video" -msgstr "" +msgstr "Videó indítása mindig" #: ../gtk/main.ui.h:20 -#, fuzzy msgid "Enable self-view" -msgstr "Video engedélyezés" +msgstr "Saját nézet" #: ../gtk/main.ui.h:21 -#, fuzzy msgid "_Help" -msgstr "Help" +msgstr "_Segítség" #: ../gtk/main.ui.h:22 msgid "Show debug window" -msgstr "" +msgstr "Hibakeresési ablak mutatása" #: ../gtk/main.ui.h:23 msgid "_Homepage" -msgstr "" +msgstr "_Honlap" #: ../gtk/main.ui.h:24 msgid "Check _Updates" -msgstr "" +msgstr "Frissítések keresése" #: ../gtk/main.ui.h:25 msgid "Account assistant" -msgstr "" +msgstr "Fiók varázsló" #: ../gtk/main.ui.h:26 -#, fuzzy msgid "SIP address or phone number:" -msgstr "Gépeld ide a sip címet vagy a telefonszámot" +msgstr "Adja meg a SIP címet vagy a telefonszámot:" #: ../gtk/main.ui.h:27 msgid "Initiate a new call" -msgstr "" +msgstr "Új hívás kezdeményezése" #: ../gtk/main.ui.h:28 -#, fuzzy msgid "Contacts" -msgstr "Kapcsolódás" +msgstr "Partnerek" #: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 msgid "Add" -msgstr "" +msgstr "Hozzáadás" #: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 msgid "Edit" @@ -832,95 +824,85 @@ msgstr "Szerkesztés" #: ../gtk/main.ui.h:31 msgid "Search" -msgstr "" +msgstr "Keresés" #: ../gtk/main.ui.h:32 -#, fuzzy msgid "Add contacts from directory" -msgstr "Kapcsolatiinformáció" +msgstr "Partnerek hozzáadása könyvtárból" #: ../gtk/main.ui.h:33 -#, fuzzy msgid "Add contact" -msgstr "Kapcsolatinformációk szerkesztése" +msgstr "Partner hozzáadása" #: ../gtk/main.ui.h:34 -#, fuzzy msgid "Recent calls" -msgstr "Beérkező hívás" +msgstr "Legutóbbi hívások" #: ../gtk/main.ui.h:35 -#, fuzzy msgid "My current identity:" -msgstr "SIP azonosító:" +msgstr "Jelenlegi identitásom:" #: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 -#, fuzzy msgid "Username" -msgstr "felhasználónév:" +msgstr "Felhasználónév" #: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 -#, fuzzy msgid "Password" -msgstr "jelszó:" +msgstr "Jelszó" #: ../gtk/main.ui.h:38 msgid "Internet connection:" -msgstr "" +msgstr "Internet kapcsolat:" #: ../gtk/main.ui.h:39 -#, fuzzy msgid "Automatically log me in" -msgstr "Automatikus valós hostnév megállapítása" +msgstr "Jelentkeztessen be automatikusan" #: ../gtk/main.ui.h:40 -#, fuzzy msgid "Login information" -msgstr "Kapcsolatiinformáció" +msgstr "Bejelentkezési információ" #: ../gtk/main.ui.h:41 -#, fuzzy msgid "Welcome !" -msgstr "Kapcsolatilista" +msgstr "Üdvözöljük !" #: ../gtk/main.ui.h:42 msgid "All users" -msgstr "" +msgstr "Minden felhasználó" #: ../gtk/main.ui.h:43 -#, fuzzy msgid "Online users" msgstr "Elérhető" #: ../gtk/main.ui.h:44 msgid "ADSL" -msgstr "" +msgstr "ADSL" #: ../gtk/main.ui.h:45 msgid "Fiber Channel" -msgstr "" +msgstr "Fiber csatorna" #: ../gtk/main.ui.h:46 -#, fuzzy msgid "Default" -msgstr "SIP azonosító:" +msgstr "Alapértelmezett" #: ../gtk/main.ui.h:47 msgid "Delete" -msgstr "" +msgstr "Törlés" #: ../gtk/about.ui.h:1 -#, fuzzy msgid "About linphone" -msgstr "linphone" +msgstr "Linphone névjegy" #: ../gtk/about.ui.h:2 msgid "(C) Belledonne Communications,2010\n" -msgstr "" +msgstr "(C) Belledonne Communications,2010\n" #: ../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 "" @@ -936,342 +918,325 @@ msgid "" "cs: Petr Pisar \n" "hu: anonymous\n" msgstr "" +"francia: Simon Morlat\n" +"angol: Simon Morlat és Delphine Perreau\n" +"olasz: Alberto Zanoni \n" +"német: Jean-Jacques Sarton \n" +"svéd: Daniel Nylander \n" +"spanyol: Jesus Benitez \n" +"japán: YAMAGUCHI YOSHIYA \n" +"brazil-portugál: Rafael Caesar Lenzi \n" +"lengyel: Robert Nasiadek \n" +"cseh: Petr Pisar \n" +"magyar: anonymous és Barczi Viktor \n" #: ../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 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ő):" #: ../gtk/sip_account.ui.h:8 -#, fuzzy msgid "Registration duration (sec):" -msgstr "Regisztrálási Időköz:" +msgstr "Regisztrálási Időköz (mp):" #: ../gtk/sip_account.ui.h:9 msgid "Register" -msgstr "" +msgstr "Regisztráció" #: ../gtk/sip_account.ui.h:10 -#, fuzzy msgid "Publish presence information" -msgstr "Jelenléti információ közlése:" +msgstr "Jelenléti információ közlése" #: ../gtk/sip_account.ui.h:11 msgid "Configure a SIP account" -msgstr "" +msgstr "SIP fiók beállítása" #: ../gtk/parameters.ui.h:1 msgid "default soundcard" -msgstr "" +msgstr "alapértelmezett hangkártya" #: ../gtk/parameters.ui.h:2 msgid "a sound card" -msgstr "" +msgstr "egy hangkártya" #: ../gtk/parameters.ui.h:3 msgid "default camera" -msgstr "" +msgstr "alapértelmezett kamera" #: ../gtk/parameters.ui.h:4 msgid "CIF" -msgstr "" +msgstr "CIF" #: ../gtk/parameters.ui.h:5 -#, fuzzy msgid "Audio codecs" -msgstr "Audio kodekek" +msgstr "Audió kódekek" #: ../gtk/parameters.ui.h:6 -#, fuzzy msgid "Video codecs" -msgstr "Audio kodekek" +msgstr "Videó kódekek" #: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 msgid "C" -msgstr "" +msgstr "C" #: ../gtk/parameters.ui.h:8 msgid "SIP (UDP)" -msgstr "" +msgstr "SIP (UDP)" #: ../gtk/parameters.ui.h:9 msgid "SIP (TCP)" -msgstr "" +msgstr "SIP (TCP)" #: ../gtk/parameters.ui.h:10 msgid "SIP (TLS)" -msgstr "" +msgstr "SIP (TLS)" #: ../gtk/parameters.ui.h:11 msgid "Settings" -msgstr "" +msgstr "Beállítások" #: ../gtk/parameters.ui.h:12 msgid "Set Maximum Transmission Unit:" -msgstr "" +msgstr "Maximum Továbbítási Egység beállítása:" #: ../gtk/parameters.ui.h:13 msgid "Send DTMFs as SIP info" -msgstr "" +msgstr "DTMF küldése SIP infóként" #: ../gtk/parameters.ui.h:14 msgid "Use IPv6 instead of IPv4" -msgstr "" +msgstr "IPv6 használata IPv4 helyett" #: ../gtk/parameters.ui.h:15 -#, fuzzy msgid "Transport" -msgstr "Kapcsolatilista" +msgstr "Átvitel" #: ../gtk/parameters.ui.h:16 msgid "Media encryption type" -msgstr "" +msgstr "Média titkosítás típusa" #: ../gtk/parameters.ui.h:17 msgid "Video RTP/UDP:" -msgstr "" +msgstr "Videó RTP/UDP:" #: ../gtk/parameters.ui.h:18 msgid "Audio RTP/UDP:" -msgstr "" +msgstr "Audió RTP/UDP:" #: ../gtk/parameters.ui.h:19 msgid "DSCP fields" -msgstr "" +msgstr "DSCP mezők" #: ../gtk/parameters.ui.h:20 msgid "Fixed" -msgstr "" +msgstr "Javítva" #: ../gtk/parameters.ui.h:21 msgid "Tunnel" -msgstr "" +msgstr "Alagút" #: ../gtk/parameters.ui.h:22 msgid "Media encryption is mandatory" -msgstr "" +msgstr "Média titkosítás kötelező" #: ../gtk/parameters.ui.h:23 msgid "Network protocol and ports" -msgstr "" +msgstr "Hálózati protokoll és port" #: ../gtk/parameters.ui.h:24 msgid "Direct connection to the Internet" -msgstr "" +msgstr "Közvetlen Internet kapcsolat" #: ../gtk/parameters.ui.h:25 msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" +msgstr "NAT / tűzfal mögött (adja meg az átjáró IP címét)" #: ../gtk/parameters.ui.h:26 -#, fuzzy msgid "Public IP address:" -msgstr "Sip cím:" +msgstr "Publikus IP cím:" #: ../gtk/parameters.ui.h:27 msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" +msgstr "NAT / tűzfal mögött (STUN használata a feloldáshoz)" #: ../gtk/parameters.ui.h:28 msgid "Behind NAT / Firewall (use ICE)" -msgstr "" +msgstr "NAT / tűzfal mögött (ICE használata)" #: ../gtk/parameters.ui.h:29 msgid "Behind NAT / Firewall (use uPnP)" -msgstr "" +msgstr "NAT / tűzfal mögött (uPnP használata)" #: ../gtk/parameters.ui.h:30 -#, fuzzy msgid "Stun server:" -msgstr "Hang eszköz" +msgstr "STUN kiszolgáló:" #: ../gtk/parameters.ui.h:31 -#, fuzzy msgid "NAT and Firewall" -msgstr "Kapcsolatilista" +msgstr "NAT és tűzfal" #: ../gtk/parameters.ui.h:32 -#, fuzzy msgid "Network settings" -msgstr "Hálózat" +msgstr "Hálózati beállítások" #: ../gtk/parameters.ui.h:33 -#, fuzzy msgid "Ring sound:" msgstr "Csengőhang:" #: ../gtk/parameters.ui.h:34 msgid "ALSA special device (optional):" -msgstr "" +msgstr "Különleges ALSA eszköz (nem kötelező):" #: ../gtk/parameters.ui.h:35 -#, fuzzy msgid "Capture device:" msgstr "Felvevő hang eszköz:" #: ../gtk/parameters.ui.h:36 -#, fuzzy msgid "Ring device:" -msgstr "Csengőhang forrás:" +msgstr "Csengőhang eszköz:" #: ../gtk/parameters.ui.h:37 -#, fuzzy msgid "Playback device:" msgstr "Lejátszó hang eszköz:" #: ../gtk/parameters.ui.h:38 msgid "Enable echo cancellation" -msgstr "" +msgstr "Visszhang-elnyomás engedélyezése" #: ../gtk/parameters.ui.h:39 -#, fuzzy msgid "Audio" -msgstr "Kapcsolatilista" +msgstr "Audió" #: ../gtk/parameters.ui.h:40 -#, fuzzy msgid "Video input device:" -msgstr "Hang eszköz" +msgstr "Videó bemeneti eszköz:" #: ../gtk/parameters.ui.h:41 msgid "Prefered video resolution:" -msgstr "" +msgstr "Kívánt videó felbontás:" #: ../gtk/parameters.ui.h:42 -#, fuzzy msgid "Video" -msgstr "Kapcsolatilista" +msgstr "Videó" #: ../gtk/parameters.ui.h:43 msgid "Multimedia settings" -msgstr "" +msgstr "Multimédia beállítások" #: ../gtk/parameters.ui.h:44 msgid "This section defines your SIP address when not using a SIP account" -msgstr "" +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:45 msgid "Your display name (eg: John Doe):" -msgstr "" +msgstr "Az Ön megjelenített neve (pl. Kis József):" #: ../gtk/parameters.ui.h:46 -#, fuzzy msgid "Your username:" -msgstr "felhasználónév:" +msgstr "Az Ön felhasználóneve:" #: ../gtk/parameters.ui.h:47 -#, fuzzy msgid "Your resulting SIP address:" -msgstr "Saját sip cím:" +msgstr "Az Ön így keletkezett SIP címe:" #: ../gtk/parameters.ui.h:48 -#, fuzzy msgid "Default identity" -msgstr "SIP azonosító:" +msgstr "Alapértelmezett identitás" #: ../gtk/parameters.ui.h:49 msgid "Wizard" -msgstr "" +msgstr "Varázsló" #: ../gtk/parameters.ui.h:52 msgid "Remove" msgstr "Eltávolítás" #: ../gtk/parameters.ui.h:53 -#, fuzzy msgid "Proxy accounts" -msgstr "Kapcsolatilista" +msgstr "Proxy fiókok" #: ../gtk/parameters.ui.h:54 msgid "Erase all passwords" -msgstr "" +msgstr "Minden kulcsszó törlése" #: ../gtk/parameters.ui.h:55 -#, fuzzy msgid "Privacy" -msgstr "Kapcsolatilista" +msgstr "Titoktartás" #: ../gtk/parameters.ui.h:56 msgid "Manage SIP Accounts" -msgstr "" +msgstr "SIP fiókok beállítása" #: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 msgid "Enable" @@ -1282,80 +1247,72 @@ msgid "Disable" msgstr "Tiltás" #: ../gtk/parameters.ui.h:59 -#, fuzzy msgid "Codecs" -msgstr "Kapcsolatilista" +msgstr "Kódekek" #: ../gtk/parameters.ui.h:60 msgid "0 stands for \"unlimited\"" -msgstr "" +msgstr "A 0 jelentése \"végtelen\"" #: ../gtk/parameters.ui.h:61 -#, fuzzy msgid "Upload speed limit in Kbit/sec:" -msgstr "Feltöltési sávszélesség (kbit/sec):" +msgstr "Feltöltési sebesség korlát (kbit/mp):" #: ../gtk/parameters.ui.h:62 -#, fuzzy msgid "Download speed limit in Kbit/sec:" -msgstr "Letöltési sávszélesség (kbit/sec):" +msgstr "Letöltési sebesség korlát (kbit/mp):" #: ../gtk/parameters.ui.h:63 msgid "Enable adaptive rate control" -msgstr "" +msgstr "Alkalmazkodó mérték-szabályozás engedélyezése" #: ../gtk/parameters.ui.h:64 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:65 msgid "Bandwidth control" -msgstr "" +msgstr "Sávszélesség szabályozása" #: ../gtk/parameters.ui.h:66 -#, fuzzy msgid "Codecs" -msgstr "Kodekek" +msgstr "Kódekek" #: ../gtk/parameters.ui.h:67 -#, fuzzy msgid "Language" -msgstr "Kapcsolatilista" +msgstr "Nyelv" #: ../gtk/parameters.ui.h:68 msgid "Show advanced settings" -msgstr "" +msgstr "Haladó beállítások megjelenítése" #: ../gtk/parameters.ui.h:69 -#, fuzzy msgid "Level" -msgstr "Kapcsolatilista" +msgstr "Szint" #: ../gtk/parameters.ui.h:70 -#, fuzzy msgid "User interface" -msgstr "felhasználónév:" +msgstr "Felhasználói környezet" #: ../gtk/parameters.ui.h:71 -#, fuzzy 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" +msgstr "Keres valakit" #: ../gtk/waiting.ui.h:1 msgid "Linphone" @@ -1363,12 +1320,11 @@ msgstr "Linphone" #: ../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" +msgstr "DSCP beállítások" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1376,80 +1332,75 @@ 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 "Audio Media connectivity" -msgstr "" +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 msgid "Video Media connectivity" -msgstr "" +msgstr "Videó média kapcsolat" #: ../gtk/call_statistics.ui.h:8 -#, fuzzy msgid "Round trip time" -msgstr "Hang beállítások" +msgstr "Körbeérés ideje" #: ../gtk/call_statistics.ui.h:9 -#, fuzzy 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:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "http proxy beállítása (nem kötelező)" #: ../gtk/keypad.ui.h:1 msgid "D" -msgstr "" +msgstr "D" #: ../gtk/keypad.ui.h:2 msgid "#" @@ -1465,23 +1416,23 @@ msgstr "*" #: ../gtk/keypad.ui.h:6 msgid "9" -msgstr "" +msgstr "9" #: ../gtk/keypad.ui.h:7 msgid "8" -msgstr "" +msgstr "8" #: ../gtk/keypad.ui.h:8 msgid "7" -msgstr "" +msgstr "7" #: ../gtk/keypad.ui.h:9 msgid "B" -msgstr "" +msgstr "B" #: ../gtk/keypad.ui.h:10 msgid "6" -msgstr "" +msgstr "6" #: ../gtk/keypad.ui.h:11 msgid "5" @@ -1489,19 +1440,19 @@ msgstr "5" #: ../gtk/keypad.ui.h:12 msgid "4" -msgstr "" +msgstr "4" #: ../gtk/keypad.ui.h:13 msgid "A" -msgstr "" +msgstr "A" #: ../gtk/keypad.ui.h:14 msgid "3" -msgstr "" +msgstr "3" #: ../gtk/keypad.ui.h:15 msgid "2" -msgstr "" +msgstr "2" #: ../gtk/keypad.ui.h:16 msgid "1" @@ -1562,49 +1513,44 @@ msgid "Contacting" msgstr "Kapcsolódás" #: ../coreapi/linphonecore.c:2439 -#, fuzzy msgid "Could not call" -msgstr "nem sikerült hívni" +msgstr "Nem sikerült hívni" #: ../coreapi/linphonecore.c:2549 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:2731 -#, fuzzy msgid "is contacting you" -msgstr "kapcsolatba lép veled." +msgstr "kapcsolatba lépett veled." #: ../coreapi/linphonecore.c:2732 msgid " and asked autoanswer." -msgstr "" +msgstr "és automatikus választ kért." #: ../coreapi/linphonecore.c:2732 msgid "." -msgstr "" +msgstr "." #: ../coreapi/linphonecore.c:2799 msgid "Modifying call parameters..." -msgstr "" +msgstr "A hívási jellemzők módosítása..." #: ../coreapi/linphonecore.c:3138 msgid "Connected." msgstr "Kapcsolódva." #: ../coreapi/linphonecore.c:3166 -#, fuzzy msgid "Call aborted" -msgstr "megszakítva" +msgstr "Hívás megszakítva" #: ../coreapi/linphonecore.c:3351 -#, fuzzy 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:3356 -#, fuzzy 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 "" @@ -1636,7 +1582,7 @@ msgstr "Stun keresés folyamatban..." #: ../coreapi/misc.c:630 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "ICE helyi jelentkezők begyűjtése folyamatban..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1647,21 +1593,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" @@ -1670,95 +1613,94 @@ 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" -msgstr "" +msgstr "Ismeretlen programhiba" #: ../coreapi/proxy.c:204 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 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:1068 -#, fuzzy, c-format +#, 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:283 -#, fuzzy msgid "Remote ringing." -msgstr "Távoli szolgáltatások" +msgstr "Távoli csengés." #: ../coreapi/callbacks.c:303 -#, fuzzy msgid "Remote ringing..." -msgstr "Távoli szolgáltatások" +msgstr "Távoli csengés..." #: ../coreapi/callbacks.c:314 msgid "Early media." msgstr "Korai médiák." #: ../coreapi/callbacks.c:365 -#, fuzzy, c-format +#, 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:378 #, c-format msgid "Call answered by %s - on hold." -msgstr "" +msgstr "%s fogadta a hívást - várakoztatva." #: ../coreapi/callbacks.c:389 -#, fuzzy msgid "Call resumed." -msgstr "Hívás vége" +msgstr "Hívás visszatért" #: ../coreapi/callbacks.c:394 -#, fuzzy, c-format +#, 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:409 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:457 msgid "We have been resumed." -msgstr "" +msgstr "Visszatértünk." #: ../coreapi/callbacks.c:466 msgid "We are paused by other party." -msgstr "" +msgstr "Megállítva a másik fél által." #: ../coreapi/callbacks.c:472 msgid "Call is updated by remote." -msgstr "" +msgstr "A hívás távolról frissítve." #: ../coreapi/callbacks.c:541 msgid "Call terminated." @@ -1782,27 +1724,24 @@ msgid "Call declined." msgstr "Hívás elutasítva" #: ../coreapi/callbacks.c:568 -#, fuzzy msgid "No response." -msgstr "időtúllépés után nincs válasz" +msgstr "Nincs válasz." #: ../coreapi/callbacks.c:572 msgid "Protocol error." -msgstr "" +msgstr "Protokol hiba." #: ../coreapi/callbacks.c:588 -#, fuzzy msgid "Redirected" -msgstr "Átirányítva idw %s..." +msgstr "Átirányítva" #: ../coreapi/callbacks.c:624 msgid "Incompatible media parameters." -msgstr "" +msgstr "Nem kompatibilis médiajellemzők." #: ../coreapi/callbacks.c:630 -#, fuzzy msgid "Call failed." -msgstr "Hívás elutasítva" +msgstr "Nem sikerült a hívás." #: ../coreapi/callbacks.c:733 #, c-format @@ -1810,9 +1749,9 @@ msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." #: ../coreapi/callbacks.c:734 -#, fuzzy, c-format +#, 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:754 msgid "no response timeout" @@ -1824,16 +1763,15 @@ msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" #: ../coreapi/linphonecall.c:129 -#, fuzzy, c-format +#, c-format msgid "Authentication token is %s" -msgstr "Hitelesítési információ" +msgstr "Hitelesítési jel: %s" #: ../coreapi/linphonecall.c:2314 -#, fuzzy, c-format +#, 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." +msgstr[0] "Van %i nem fogadott hivás." #~ msgid "Chat with %s" #~ msgstr "Chat-elés %s -el" From e69170d3f3983670c2f6a6e61be85e70ff298c2f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Mar 2013 15:44:26 +0100 Subject: [PATCH 191/909] tls fixes --- coreapi/bellesip_sal/sal_op_impl.c | 46 ++++++++++++++++-------------- coreapi/linphonecore.c | 3 -- coreapi/proxy.c | 7 +++-- tester/liblinphone_tester.c | 9 ++++-- tester/setup_tester.c | 2 ++ 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index b05517fad..a9c99b5cd 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -130,32 +130,36 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { 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_header_route_t* route_header; belle_sip_uri_t* outbound_proxy=NULL; belle_sip_header_contact_t* contact; - MSList* iterator; + 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*/ - for(iterator=(MSList*)sal_op_get_route_addresses(op);iterator!=NULL;iterator=iterator->next) { - if(!outbound_proxy) { - /*first toute is outbound proxy*/ - outbound_proxy=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(iterator->data)); - } else { - /*next are Route headers*/ - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(iterator->data)); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); - } + const MSList *elem=sal_op_get_route_addresses(op); + belle_sip_uri_t *next_hop_uri; + const char *transport; + 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_request_get_uri(request); } - if (!sal_op_get_route_addresses(op) && belle_sip_list_size(belle_sip_provider_get_listening_points(op->base.root->prov))==1) { - /*compatibility mode*/ - belle_sip_listening_point_t* lp = (belle_sip_listening_point_t*)belle_sip_provider_get_listening_points(op->base.root->prov)->data; - belle_sip_uri_t* to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header_by_type(request,belle_sip_header_to_t))); - belle_sip_header_address_t* route=belle_sip_header_address_create(NULL,belle_sip_uri_create(NULL,belle_sip_uri_get_host(to_uri))); - belle_sip_uri_set_transport_param(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(route)),belle_sip_listening_point_get_transport(lp)); - route_header = belle_sip_header_route_create(route); - belle_sip_object_unref(route); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); - ms_message("Only one lp & no route, forcing transport to lp transport [%s]",belle_sip_listening_point_get_transport(lp)); + 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_provider_get_listening_point(prov,"UDP")==0){ + if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ + transport="tcp"; + }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL){ + transport="tls"; + } + } + if (transport){ + belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); + belle_sip_uri_set_transport_param(next_hop_uri,transport); + } + belle_sip_uri_fix(next_hop_uri); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5e0412316..9d9e69059 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2585,10 +2585,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const sal_address_set_transport((SalAddress*)route,sal_transport_parse(linphone_proxy_config_guess_transport(chosen_proxy))); } } - - sal_op_add_route_address(call->op,route); - } if(linphone_core_add_call(lc,call)!= 0) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 76f40eb99..7104174cc 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -377,12 +377,13 @@ const char* linphone_proxy_config_guess_transport(const LinphoneProxyConfig *obj } static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ - LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); - char* proxy_string; + LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); + char* proxy_string; #ifndef USE_BELLESIP char *contact; #else LinphoneAddress *contact; + if (linphone_proxy_config_guess_transport(obj) && !sal_address_get_transport((SalAddress*)proxy)) { sal_address_set_transport((SalAddress*)proxy,sal_transport_parse(linphone_proxy_config_guess_transport(obj))); } @@ -397,7 +398,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ #ifndef USE_BELLESIP ms_free(contact); #else - linphone_address_destroy(contact); + linphone_address_destroy(contact); #endif } sal_op_set_user_pointer(obj->op,obj); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index efe8f9a5e..4513fbf81 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -90,6 +90,8 @@ LinphoneCore* create_lc_with_auth(unsigned int with_auth) { } lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&global_stat); + /* until we have good certificates on our test server... */ + linphone_core_verify_server_certificates(lc,FALSE); return lc; } @@ -109,6 +111,9 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c linphone_core_set_user_data(lc,&global_stat); counters = (stats*)linphone_core_get_user_data(lc); + /* until we have good certificates on our test server... */ + linphone_core_verify_server_certificates(lc,FALSE); + sprintf(ringpath, "%s/%s", path, "oldphone.wav"); sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); linphone_core_set_ring(lc, ringpath); @@ -118,8 +123,8 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count); while (counters->number_of_LinphoneRegistrationOknumber_of_LinphoneRegistrationOk,proxy_count); return lc; diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 4fee989e9..f567ca2e2 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -29,6 +29,8 @@ static void core_init_test(void) { LinphoneCore* lc; memset (&v_table,0,sizeof(v_table)); lc = linphone_core_new(&v_table,NULL,NULL,NULL); + /* until we have good certificates on our test server... */ + linphone_core_verify_server_certificates(lc,FALSE); CU_ASSERT_PTR_NOT_NULL_FATAL(lc); linphone_core_destroy(lc); } From 0d15447140747b35c001fa83277ff8d5e6f3ed89 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 28 Mar 2013 18:29:26 +0100 Subject: [PATCH 192/909] better management of call state machine --- coreapi/bellesip_sal/sal_impl.c | 2 +- coreapi/bellesip_sal/sal_op_call.c | 192 ++++++++++++++++--------- coreapi/bellesip_sal/sal_op_impl.c | 9 +- coreapi/bellesip_sal/sal_op_presence.c | 8 +- coreapi/bellesip_sal/sal_sdp.c | 6 +- tester/call_tester.c | 25 +++- tester/liblinphone_tester.c | 3 +- 7 files changed, 161 insertions(+), 84 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 3bd0fc1eb..861615fda 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -301,7 +301,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even 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 "); - return; } else { if (op->pending_auth_transaction){ belle_sip_object_unref(op->pending_auth_transaction); @@ -349,6 +348,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans ms_error("Unhandled transaction terminated [%p]",trans); } if (op) sal_op_unref(op); /*no longuer need to ref op*/ + } static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2bcb0b89a..b9797ec12 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,6 +19,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" +static void call_set_released(SalOp* op){ + op->state=SalOpStateTerminated; + op->base.root->callbacks.call_released(op); +} +static void call_set_error(SalOp* op,belle_sip_response_t* response){ + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + char* reason=(char*)belle_sip_response_get_reason_phrase(response); + int code = belle_sip_response_get_status_code(response); + if (reason_header){ + reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); + } + sal_compute_sal_errors_from_code(code,&error,&sr); + op->base.root->callbacks.call_failure(op,error,sr,reason,code); + if (reason_header != NULL){ + ms_free(reason); + } + call_set_released(op); +} static void sdp_process(SalOp *h){ ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); @@ -85,7 +105,7 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event if (!op->dialog) { /*call terminated very early*/ op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); - op->state=SalOpStateTerminated; + call_set_released(op); } else { /*dialog will terminated shortly, nothing to do*/ } @@ -93,18 +113,51 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op=(SalOp*)ctx; - if (op->dialog) { - if (belle_sip_dialog_get_previous_state(op->dialog) == BELLE_SIP_DIALOG_CONFIRMED) { - /*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; - } else { - /*let the process response handle this case*/ - } + if (op->dialog && op->dialog==belle_sip_dialog_terminated_get_dialog(event)) { + 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: { + belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog); + belle_sip_response_t* response=belle_sip_transaction_get_response(trans); + int code = belle_sip_response_get_status_code(response); + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_client_transaction_t)) { + switch (code) { + case 487: + call_set_released(op); + break; + case 401: + case 407: + if (op->state!=SalOpStateTerminating) { + /*normal termination for chalanged dialog */ + break; + } + default: + call_set_error(op,response); + } + } else { + belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) + ,(belle_sip_callback_t) call_set_released + , op); + } + } + } belle_sip_object_unref(op->dialog); op->dialog=NULL; + sal_op_unref(op); + } else { + ms_error("dialog unknown for op "); } + + ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_get_dialog(event) + ,op); + } static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; @@ -119,7 +172,7 @@ static void cancelling_invite(SalOp* op ){ ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); cancel = belle_sip_client_transaction_create_cancel(op->pending_inv_client_trans); sal_op_send_request(op,cancel); - op->state=SalOpStateTerminated; + op->state=SalOpStateTerminating; } static void call_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; @@ -129,67 +182,45 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t 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); - char* reason; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + + if (!client_transaction) { ms_warning("Discarding state less response [%i] on op [%p]",code,op); return; } req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - reason=(char*)belle_sip_response_get_reason_phrase(response); - if (reason_header){ - reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); - } - /*FIXME should be limited to early/NULL dialog*/ - if (code >=400) { - sal_compute_sal_errors_from_code(code,&error,&sr); - op->base.root->callbacks.call_failure(op,error,sr,reason,code); - op->state=SalOpStateTerminated; - if (reason_header != NULL){ - ms_free(reason); - } - return; - } set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); - - /*check if op is terminating*/ - - - if (op->state == SalOpStateTerminating) { - if( strcmp("INVITE",belle_sip_request_get_method(req))==0 - && (!op->dialog - || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL - || belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_EARLY)) { - /*FIXME if DIALOG_CONFIRM then ACK+BYE*/ - cancelling_invite(op); - - return; - } else if (strcmp("BYE",belle_sip_request_get_method(req))==0) { - return; /*probably a 200ok for a bye*/ - } - } - if (!op->dialog) { - ms_message("call op [%p] receive out of dialog answer [%i]",op,code); - return; - } - dialog_state=belle_sip_dialog_get_state(op->dialog); + dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: { - ms_error("call op [%p] receive an unexpected answer [%i]",op,code); - break; - } + case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { - if (code >= 180) { - handle_sdp_from_response(op,response); - op->base.root->callbacks.call_ringing(op); + if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { + if ( op->state == SalOpStateTerminating) { + if (code <200) { + cancelling_invite(op); + } else if (code<400) { + sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + } else { + /*nop ?*/ + } + break; + } else if (code >= 180) { + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_ringing(op); + break; + } else { + /*nop error*/ + } + + } else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0 + || strcmp("BYE",belle_sip_request_get_method(req))==0) { + break;/*200ok for cancel or BYE*/ } else { - ms_error("call op [%p] receive an unexpected answer [%i]",op,code); + /*nop error*/ } - break; + ms_error("call op [%p] receive an unexpected answer [%i]",op,code); } case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { @@ -213,18 +244,28 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->base.root->callbacks.call_accepted(op); /*INVITE*/ op->state=SalOpStateActive; - } else { + } else { /*nop*/ } break; - + case SalOpStateTerminating: + //FIXME send bye case SalOpStateTerminated: default: ms_error("call op [%p] receive answer [%i] not implemented",op,code); } break; } - case BELLE_SIP_DIALOG_TERMINATED: + case BELLE_SIP_DIALOG_TERMINATED: { + /*if (code>=400 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ + call_set_error(op,response); + call_set_released(op); + op->state=SalOpStateTerminated; + break; + }*/ + break; + } + /* no break */ default: { ms_error("call op [%p] receive answer [%i] not implemented",op,code); } @@ -234,15 +275,12 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } -static void call_set_released(SalOp* op){ - op->base.root->callbacks.call_released(op); -} - static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; if (!op->dialog) { /*call terminated very early*/ op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); + call_set_released(op); op->state=SalOpStateTerminated; } else { /*dialog will terminated shortly, nothing to do*/ @@ -261,9 +299,11 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); } - if (strcmp("BYE",belle_sip_request_get_method(req))==0 + 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))) { + call_set_released(op); } @@ -302,11 +342,17 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_response_t* resp; belle_sip_header_t* call_info; - if (server_transaction) belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ + if (server_transaction){ + belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op); + sal_op_ref(op); + } + if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { if (op->pending_server_trans)belle_sip_object_unref(op->pending_server_trans); /*updating pending invite transaction*/ op->pending_server_trans=server_transaction; + belle_sip_object_ref(op->pending_server_trans); } if (!op->dialog) { @@ -386,7 +432,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_server_transaction_send_response(server_transaction,resp); - /*call end is notified by dialog deletion*/ + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + op->state=SalOpStateTerminating; + /*call end not notified by dialog deletion because transaction can end before dialog*/ } else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) { /*re-invite*/ if (op->base.remote_media){ @@ -429,6 +477,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t /* no break */ } + if (server_transaction) belle_sip_object_unref(server_transaction); } @@ -640,7 +689,10 @@ int sal_call_terminate(SalOp *op){ cancelling_invite(op); break; } else { - ms_error("Don't know how to termination NUlL dialog for op [%p]",op); + /*just schedule call released*/ + belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) + ,(belle_sip_callback_t) call_set_released + , op); } break; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a9c99b5cd..2f9b8484d 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -268,12 +268,17 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S } void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { /*check if dialog has changed*/ - if (dialog != op->dialog) { + if (dialog && dialog != op->dialog) { ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op); /*fixme, shouldn't we cancel previous dialog*/ - if (op->dialog)belle_sip_object_unref(op->dialog); + if (op->dialog) { + belle_sip_dialog_set_application_data(op->dialog,NULL); + belle_sip_object_unref(op->dialog); + sal_op_unref(op); + } op->dialog=dialog; belle_sip_dialog_set_application_data(op->dialog,op); + sal_op_ref(op); belle_sip_object_ref(op->dialog); } } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 8020436fc..fe0597c20 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -404,8 +404,12 @@ static void add_presence_info(belle_sip_message_t *notify, SalPresenceStatus onl 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 *op, const belle_sip_dialog_terminated_event_t *event) { - if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL; +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_response_event(void *op_base, const belle_sip_response_event_t *event){ diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 3fa6e2a2d..a0586e824 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -159,6 +159,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal const char *mtype,*proto; SalStreamDescription *stream; belle_sdp_media_t* media; + belle_sip_list_t* mime_params=NULL; belle_sip_list_t* mime_param_it=NULL; belle_sdp_mime_parameter_t* mime_param; PayloadType *pt; @@ -232,7 +233,8 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal } /* for each payload type */ - for(mime_param_it=belle_sdp_media_description_build_mime_parameters(media_desc) + mime_params=belle_sdp_media_description_build_mime_parameters(media_desc); + for(mime_param_it=mime_params ;mime_param_it!=NULL ;mime_param_it=mime_param_it->next) { mime_param=BELLE_SDP_MIME_PARAMETER(mime_param_it->data) @@ -248,7 +250,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, pt->send_fmtp ? pt->send_fmtp : ""); } - if (mime_param_it) belle_sip_list_free_with_data(mime_param_it,belle_sip_object_unref); + if (mime_params) belle_sip_list_free_with_data(mime_params,belle_sip_object_unref); /* read crypto lines if any */ if (stream->proto == SalProtoRtpSavp) { diff --git a/tester/call_tester.c b/tester/call_tester.c index 9c98fa00d..ccac96a7d 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -187,6 +187,13 @@ static void simple_call(void) { CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); } + linphone_core_destroy(marie->lc); + marie->lc=NULL; + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallReleased,1); + linphone_core_destroy(pauline->lc); + pauline->lc=NULL; + CU_ASSERT_EQUAL(stat_pauline->number_of_LinphoneCallReleased,1); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -268,6 +275,8 @@ static void cancelled_call(void) { //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + linphone_call_unref(out_call); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -285,6 +294,7 @@ static void call_with_dns_time_out(void) { CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,1); linphone_core_manager_destroy(marie); } @@ -297,10 +307,11 @@ static void cancelled_ringing_call(void) { CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); linphone_core_terminate_call(pauline->lc,out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); - //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + linphone_call_unref(out_call); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -318,8 +329,10 @@ static void early_declined_call(void) { if (in_call) { linphone_call_ref(in_call); linphone_core_terminate_call(marie->lc,in_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); linphone_call_unref(in_call); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 4513fbf81..6f7840a03 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -165,6 +165,7 @@ static void enable_codec(LinphoneCore* lc,const char* type,int rate) { if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { linphone_core_enable_payload_type(lc,pt, 1); } + ms_list_free(codecs); } LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies) { @@ -194,7 +195,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_ } void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { - linphone_core_destroy(mgr->lc); + if (mgr->lc) linphone_core_destroy(mgr->lc); if (mgr->identity) linphone_address_destroy(mgr->identity); free(mgr); } From 641ba75313eb3ff97446de9667eee21f7319703e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Mar 2013 21:56:49 +0100 Subject: [PATCH 193/909] refine transport selection algorithm and set proper routes for all kind of operations: INVITE, MESSAGE, SUBSCRIBE. --- coreapi/bellesip_sal/sal_address_impl.c | 23 +++- coreapi/chat.c | 11 +- coreapi/friend.c | 6 +- coreapi/linphonecall.c | 15 ++- coreapi/linphonecore.c | 170 +++++++++++++----------- coreapi/presence.c | 3 +- coreapi/private.h | 10 +- coreapi/proxy.c | 35 +---- include/sal/sal.h | 3 +- 9 files changed, 139 insertions(+), 137 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 540aa701b..c7f004bef 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -83,14 +83,22 @@ int sal_address_get_port_int(const SalAddress *addr){ return -1; } SalTransport sal_address_get_transport(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 && belle_sip_uri_get_transport_param(uri)) { - return sal_transport_parse(belle_sip_uri_get_transport_param(uri)); - } else + 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); @@ -132,8 +140,11 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ belle_sip_parameters_set_parameter(parameters,name,value); return ; } + void sal_address_set_transport(SalAddress* addr,SalTransport transport){ 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); +} diff --git a/coreapi/chat.c b/coreapi/chat.c index c12bb3398..54a15526b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -65,11 +65,11 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){ - const char *route=NULL; - const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route); + MSList *routes=NULL; SalOp *op=NULL; LinphoneCall *call; char* content_type; + const char *identity=NULL; time_t t=time(NULL); if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){ @@ -82,14 +82,19 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM ms_message("send SIP message through the existing call."); op = call->op; call->pending_message=msg; + identity=linphone_core_find_best_identity(cr->lc,linphone_call_get_remote_address(call)); } } } msg->time=t; if (op==NULL){ + LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(cr->lc,cr->peer_url,&routes); + if (proxy){ + identity=linphone_proxy_config_get_identity(proxy); + }else identity=linphone_core_get_primary_contact(cr->lc); /*sending out of calls*/ op = sal_op_new(cr->lc->sal); - sal_op_set_route(op,route); + linphone_transfer_routes_to_op(routes,op); 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); diff --git a/coreapi/friend.c b/coreapi/friend.c index 2a857de2d..19dd16f01 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -109,13 +109,14 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ const char *route=NULL; const char *from=NULL; LinphoneProxyConfig *cfg; + MSList *routes=NULL; friend=linphone_address_as_string(fr->uri); - cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); + cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr),&routes); if (cfg!=NULL){ - route=linphone_proxy_config_get_route(cfg); from=linphone_proxy_config_get_identity(cfg); }else from=linphone_core_get_primary_contact(fr->lc); + if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ fr->status=LinphoneStatusOffline; @@ -133,6 +134,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ sal_op_set_contact(fr->outsub,sal_op_get_contact(cfg->op)); else sal_op_set_contact(fr->outsub,NULL); + linphone_transfer_routes_to_op(routes,fr->outsub); sal_subscribe_presence(fr->outsub,from,friend); fr->subscribe_active=TRUE; ms_free(friend); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1f8a288b0..c512dc3fd 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -219,20 +219,25 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * PayloadType *pt; SalMediaDescription *old_md=call->localdesc; int i; - const char *me=linphone_core_get_identity(lc); - LinphoneAddress *addr=linphone_address_new(me); - const char *username=linphone_address_get_username (addr); + const char *me; SalMediaDescription *md=sal_media_description_new(); + LinphoneAddress *addr; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); linphone_core_adapt_to_network(lc,call->ping_time,&call->params); + if (call->dest_proxy) + me=linphone_proxy_config_get_identity(call->dest_proxy); + else + me=linphone_core_get_identity(lc); + addr=linphone_address_new(me); + md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); md->n_total_streams=(old_md ? old_md->n_total_streams : 1); md->n_active_streams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); - strncpy(md->username,username,sizeof(md->username)); + strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); if (call->params.down_bw) md->bandwidth=call->params.down_bw; @@ -523,7 +528,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro from_str=linphone_address_as_string_uri_only(from); sal_op_set_route(call->ping_op,sal_op_get_network_origin(op)); sal_op_set_user_pointer(call->ping_op,call); - sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str); + sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from),from_str); ms_free(from_str); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9d9e69059..44d8052d6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -66,6 +66,7 @@ static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" + const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); @@ -2003,7 +2004,7 @@ static void linphone_core_grab_buddy_infos(LinphoneCore *lc, LinphoneProxyConfig for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend*)elem->data; if (lf->info==NULL){ - if (linphone_core_lookup_known_proxy(lc,lf->uri)==cfg){ + if (linphone_core_lookup_known_proxy(lc,lf->uri,NULL)==cfg){ if (linphone_address_get_username(lf->uri)!=NULL){ BuddyLookupRequest *req; char *tmp=linphone_address_as_string_uri_only(lf->uri); @@ -2295,7 +2296,53 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L } } -LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ +/* 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 *addr){ + 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){ + /*still no route, so try to build a route from proxy transport + identity host, + *in order to force using the transport required for this proxy, if any.*/ + SalAddress *proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy)); + const char *transport=sal_address_get_transport_name(proxy_addr); + sal_address_destroy(proxy_addr); + if (transport){ + SalAddress *route=sal_address_new(NULL); + sal_address_set_domain(route,sal_address_get_domain((SalAddress*)addr)); + sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)addr)); + sal_address_set_transport_name(route,transport); + ret=ms_list_append(ret,route); + } + } + return ret; +} + +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri, MSList **routes){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; LinphoneProxyConfig *default_cfg=lc->default_proxy; @@ -2303,8 +2350,10 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L /*always prefer the default proxy if it is matching the destination uri*/ if (default_cfg){ const char *domain=linphone_proxy_config_get_domain(default_cfg); - if (strcmp(domain,linphone_address_get_domain(uri))==0) - return default_cfg; + if (strcmp(domain,linphone_address_get_domain(uri))==0){ + found_cfg=default_cfg; + goto end; + } } /*otherwise iterate through the other proxy config and return the first matching*/ @@ -2313,18 +2362,34 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L const char *domain=linphone_proxy_config_get_domain(cfg); if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ found_cfg=cfg; - break; + goto end; } } +end: + if (found_cfg!=NULL && found_cfg!=default_cfg){ + ms_message("Overriding default proxy setting for this call/message/subscribe operation."); + }; + + /*if route argument is given, fill adequate route set for this proxy.*/ + if (routes){ + if (found_cfg){ + *routes=make_routes_for_proxy(found_cfg,uri); + }else if (default_cfg){ + /*if the default proxy config has a locally configured route, we should use it*/ + const char *route=linphone_proxy_config_get_route(default_cfg); + if (route) + *routes=ms_list_append(*routes,sal_address_new(route)); + } + } + return found_cfg; } -const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route){ - LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to); +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to){ + LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to,NULL); 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); @@ -2474,6 +2539,15 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr return call; } +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); +} /** * Initiates an outgoing call given a destination LinphoneAddress @@ -2493,12 +2567,11 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { const char *from=NULL; - LinphoneProxyConfig *proxy=NULL,*dest_proxy=NULL; + LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; - SalAddress *route=NULL; - SalAddress *proxy_addr=NULL; char *real_url=NULL; LinphoneCall *call; + MSList *routes=NULL; bool_t defer = FALSE; linphone_core_preempt_sound_resources(lc); @@ -2510,18 +2583,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } linphone_core_get_default_proxy(lc,&proxy); - real_url=linphone_address_as_string(addr); - dest_proxy=linphone_core_lookup_known_proxy(lc,addr); + proxy=linphone_core_lookup_known_proxy(lc,addr,&routes); - if (proxy!=dest_proxy && dest_proxy!=NULL) { - ms_message("Overriding default proxy setting for this call:"); - ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy)); - } - - if (dest_proxy!=NULL) - from=linphone_proxy_config_get_identity(dest_proxy); - else if (proxy!=NULL) + if (proxy!=NULL) from=linphone_proxy_config_get_identity(proxy); /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -2530,64 +2595,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const parsed_url2=linphone_address_new(from); call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params); - call->dest_proxy=dest_proxy; - - if (linphone_core_get_route(lc)) { - sal_op_set_route(call->op,linphone_core_get_route(lc)); - } - -/* -* 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. -*/ - if (proxy && linphone_proxy_config_get_service_route(proxy)) { - /*set service route*/ - sal_op_add_route_address(call->op,linphone_proxy_config_get_service_route(proxy)); - } /*else, no route*/ - - if (!sal_op_get_route(call->op)) { - /*still no route, so try to build a route from proxy transport + identity host*/ - route=sal_address_new(NULL); - /*first, get domain and port from requerst uri*/ - sal_address_set_domain(route,sal_address_get_domain((SalAddress*)addr)); - sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)addr)); - /*next get transport either from request uri or from proxy if any*/ - if (sal_address_get_transport((SalAddress*)addr)) { - sal_address_set_transport(route,sal_address_get_transport((SalAddress*)addr)); - } else { - LinphoneProxyConfig* chosen_proxy=NULL; - - if (dest_proxy) - chosen_proxy=dest_proxy; - else if (proxy) - chosen_proxy=proxy; - else - chosen_proxy=NULL; - - if (chosen_proxy) - proxy_addr=sal_address_new(linphone_proxy_config_get_addr(chosen_proxy)); - - if (proxy_addr && sal_address_get_transport(proxy_addr)) - sal_address_set_transport(route,sal_address_get_transport(proxy_addr)); - else if (proxy_addr && linphone_proxy_config_guess_transport(chosen_proxy) && !sal_address_get_transport((SalAddress*)route)) { - /*compatibility mode*/ - sal_address_set_transport((SalAddress*)route,sal_transport_parse(linphone_proxy_config_guess_transport(chosen_proxy))); - } - } - sal_op_add_route_address(call->op,route); - } - + call->dest_proxy=proxy; + linphone_transfer_routes_to_op(routes,call->op); + if(linphone_core_add_call(lc,call)!= 0) { ms_warning("we had a problem in adding the call into the invite ... weird"); @@ -3119,7 +3129,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, linphone_core_get_default_proxy(lc,&cfg); call->dest_proxy=cfg; - call->dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to); + call->dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to,NULL); if (cfg!=call->dest_proxy && call->dest_proxy!=NULL) { ms_message("Overriding default proxy setting for this call:"); diff --git a/coreapi/presence.c b/coreapi/presence.c index 4643d7d9f..8c93b28f7 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -64,7 +64,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ tmp=linphone_address_as_string(uri); ms_message("Receiving new subscription from %s.",from); - cfg=linphone_core_lookup_known_proxy(lc,uri); + cfg=linphone_core_lookup_known_proxy(lc,uri,NULL); if (cfg!=NULL){ if (cfg->op){ if (sal_op_get_contact(cfg->op)) { @@ -73,6 +73,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ } } } + /* check if we answer to this subscription */ if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ lf->insub=op; diff --git a/coreapi/private.h b/coreapi/private.h index 19e84f9dc..10cd8757b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -240,10 +240,7 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); * Can be NULL * */ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg); -/* - *guess the transport if only one trasport is configured at core level (for backward compatibility) - * */ -const char* linphone_proxy_config_guess_transport(const LinphoneProxyConfig *obj); + int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); @@ -318,8 +315,9 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, void linphone_proxy_config_update(LinphoneProxyConfig *cfg); void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); -LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); -const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route); +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri, MSList **routes); +void linphone_transfer_routes_to_op(MSList *routes, SalOp *op); +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to); int linphone_core_get_local_ip_for(int type, const char *dest, char *result); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 7104174cc..ab638ee05 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -346,35 +346,8 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ } return ret; } -/*use for compatibility with linphone supporting only 1 transport at a time*/ -const char* linphone_proxy_config_guess_transport(const LinphoneProxyConfig *obj) { - LCSipTransports transports; - const char* transport_name; - unsigned char transports_count=0; - linphone_core_get_sip_transports(obj->lc,&transports); - if (transports.udp_port>0) { - transports_count++; - transport_name="udp"; - } - if (transports.tcp_port>0) { - transports_count++; - transport_name="tcp"; - } - if (transports.tls_port>0) { - transports_count++; - transport_name="tls"; - } - if (transports.dtls_port>0) { - transports_count++; - transport_name="dtls"; - } - if (transports_count==1) { - return transport_name; - } else { - /*cannot guess transport*/ - return NULL; - } -} + + static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); @@ -383,10 +356,6 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ char *contact; #else LinphoneAddress *contact; - - if (linphone_proxy_config_guess_transport(obj) && !sal_address_get_transport((SalAddress*)proxy)) { - sal_address_set_transport((SalAddress*)proxy,sal_transport_parse(linphone_proxy_config_guess_transport(obj))); - } #endif proxy_string=linphone_address_as_string_uri_only(proxy); linphone_address_destroy(proxy); diff --git a/include/sal/sal.h b/include/sal/sal.h index f48edbde3..0f78a4c8d 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -84,6 +84,7 @@ 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); +const char* sal_address_get_transport_name(const SalAddress* addr); void sal_address_set_display_name(SalAddress *addr, const char *display_name); void sal_address_set_username(SalAddress *addr, const char *username); @@ -96,7 +97,7 @@ char *sal_address_as_string_uri_only(const SalAddress *u); void sal_address_destroy(SalAddress *u); void sal_address_set_param(SalAddress *u,const char* name,const char* value); void sal_address_set_transport(SalAddress* addr,SalTransport transport); - +void sal_address_set_transport_name(SalAddress* addr,const char* transport); Sal * sal_init(); void sal_uninit(Sal* sal); From 6ac44d6628bc258021c1526f39ee71f53061179e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 29 Mar 2013 12:16:21 +0100 Subject: [PATCH 194/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 000ced416..d931c935f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 000ced416e943528e89f4569ee9d8d044d6b9126 +Subproject commit d931c935f351404badca4621740c583145ba65ce From 970787858bb37680f42c9e46bb62f254cc6402a6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 29 Mar 2013 16:25:42 +0100 Subject: [PATCH 195/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d931c935f..8e7337469 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d931c935f351404badca4621740c583145ba65ce +Subproject commit 8e7337469af474929fd038f1e4743737ff0a904b From cea2676afe046ed9017675222b0273124f1d648f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 29 Mar 2013 17:03:43 +0100 Subject: [PATCH 196/909] fix crash in case of multiple route --- coreapi/sal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal.c b/coreapi/sal.c index 3a6a6b5c0..1c1a30701 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -300,7 +300,7 @@ void sal_op_set_route_address(SalOp *op, const SalAddress *address){ 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*)address); + op_base->route_addresses=ms_list_append(op_base->route_addresses,(void*)sal_address_clone(address)); } else { sal_op_set_route_address(op,address); } From ee4a5d6ee46573c10e81d30ed2312a1fd27d87b8 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 2 Apr 2013 15:13:16 +0200 Subject: [PATCH 197/909] implement early declined --- coreapi/bellesip_sal/sal_impl.c | 4 ++-- coreapi/bellesip_sal/sal_op_call.c | 28 +++++++++++++++++++++++----- coreapi/linphonecore.c | 4 +++- tester/call_tester.c | 23 +++++++++++++++++++++++ tester/laure_rc | 5 ++++- tester/marie_rc | 5 ++++- tester/pauline_rc | 5 ++++- 7 files changed, 63 insertions(+), 11 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 861615fda..5dcfeac3b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -496,7 +496,7 @@ int sal_unlisten_ports(Sal *ctx){ return 0; } ortp_socket_t sal_get_socket(Sal *ctx){ - ms_fatal("sal_get_socket not implemented yet"); + ms_warning("sal_get_socket is deprecated"); return -1; } void sal_set_user_agent(Sal *ctx, const char *user_agent){ @@ -612,7 +612,7 @@ const char *sal_get_root_ca(Sal* ctx) { } int sal_reset_transports(Sal *ctx){ - ms_message("reseting transports"); + ms_message("Reseting transports"); belle_sip_provider_clean_channels(ctx->prov); return 0; } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index b9797ec12..4e33cdf60 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -23,6 +23,10 @@ static void call_set_released(SalOp* op){ op->state=SalOpStateTerminated; op->base.root->callbacks.call_released(op); } +static void call_set_released_and_unref(SalOp* op) { + call_set_released(op); + sal_op_unref(op); +} static void call_set_error(SalOp* op,belle_sip_response_t* response){ SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; @@ -114,6 +118,8 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat SalOp* op=(SalOp*)ctx; if (op->dialog && op->dialog==belle_sip_dialog_terminated_get_dialog(event)) { + belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog); + switch(belle_sip_dialog_get_previous_state(op->dialog)) { case BELLE_SIP_DIALOG_CONFIRMED: if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) { @@ -122,8 +128,14 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat op->state=SalOpStateTerminating; } break; + case BELLE_SIP_DIALOG_NULL: { + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_server_transaction_t)) { + /*call declined very early, no need to notify call release*/ + break; + } + } default: { - belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog); + belle_sip_response_t* response=belle_sip_transaction_get_response(trans); int code = belle_sip_response_get_status_code(response); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_client_transaction_t)) { @@ -141,8 +153,9 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat call_set_error(op,response); } } else { + sal_op_ref(op); /*to make sure op is still there when call released is scheduled*/ belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) - ,(belle_sip_callback_t) call_set_released + ,(belle_sip_callback_t) call_set_released_and_unref , op); } @@ -206,12 +219,17 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t /*nop ?*/ } break; - } else if (code >= 180) { + } else if (code >= 180 && code<300) { handle_sdp_from_response(op,response); op->base.root->callbacks.call_ringing(op); break; - } else { - /*nop error*/ + } else if (code>=300){ + if (dialog_state==BELLE_SIP_DIALOG_NULL) { + call_set_error(op,response); + break; + } else { + /*nop let process_dialog_terminated manage error reporting*/ + } } } else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0 diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 44d8052d6..87136f5dd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2330,7 +2330,6 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA *in order to force using the transport required for this proxy, if any.*/ SalAddress *proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy)); const char *transport=sal_address_get_transport_name(proxy_addr); - sal_address_destroy(proxy_addr); if (transport){ SalAddress *route=sal_address_new(NULL); sal_address_set_domain(route,sal_address_get_domain((SalAddress*)addr)); @@ -2338,6 +2337,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA sal_address_set_transport_name(route,transport); ret=ms_list_append(ret,route); } + sal_address_destroy(proxy_addr); } return ret; } @@ -5185,6 +5185,8 @@ void sip_config_uninit(LinphoneCore *lc) ms_list_free(lc->auth_info); lc->auth_info=NULL; + sal_reset_transports(lc->sal); + sal_iterate(lc->sal); /*make sure event are purged*/ sal_uninit(lc->sal); lc->sal=NULL; diff --git a/tester/call_tester.c b/tester/call_tester.c index ccac96a7d..89021f501 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -320,6 +320,28 @@ static void cancelled_ringing_call(void) { static void early_declined_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + linphone_core_set_max_calls(marie->lc,0); + LinphoneCallLog* in_call; + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); + CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_call_logs(marie->lc)),1); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + + if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { + CU_ASSERT_PTR_NOT_NULL(in_call=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data)); + CU_ASSERT_EQUAL(linphone_call_log_get_status(in_call),LinphoneCallDeclined); + } + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_declined(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); @@ -692,6 +714,7 @@ static void call_transfer_existing_call_outgoing_call(void) { test_t call_tests[] = { { "Early declined call", early_declined_call }, + { "Call declined", call_declined }, { "Cancelled call", cancelled_call }, { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, diff --git a/tester/laure_rc b/tester/laure_rc index b4480494c..54a682401 100644 --- a/tester/laure_rc +++ b/tester/laure_rc @@ -35,4 +35,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/tester/marie_rc b/tester/marie_rc index 26cb42992..56c96bc98 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -41,4 +41,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/tester/pauline_rc b/tester/pauline_rc index f2da8991c..5b73641cd 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -40,4 +40,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file From 3da68349308b7c9d970fd960471f708029d6e66c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 2 Apr 2013 15:21:52 +0200 Subject: [PATCH 198/909] very simple support of Supported=100rel header --- coreapi/bellesip_sal/sal_op_call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 4e33cdf60..f68784277 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -578,7 +578,7 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){ handle_offer_answer_response(op,ringing_response); } /*fixme it should support PRACK in the right way*/ - if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require")) { + if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require") || belle_sip_message_get_header((belle_sip_message_t*)req,"Supported")) { belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); belle_sip_header_contact_t* contact_header; belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_message_get_header((belle_sip_message_t*)req,"Require")); From 02ce52650c639f6dc9adfcd676692731b058fbed Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 2 Apr 2013 15:23:29 +0200 Subject: [PATCH 199/909] Allow uPnP 1.0 uuid --- coreapi/upnp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 75d0ef9e2..ec7d1f9c6 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define UPNP_CORE_READY_CHECK 1 #define UPNP_CORE_RETRY_DELAY 4 #define UPNP_CALL_RETRY_DELAY 1 -#define UPNP_UUID_LEN 32 +#define UPNP_UUID_LEN 128 #define UPNP_UUID_LEN_STR UPNP_TOSTRING(UPNP_UUID_LEN) /* * uPnP Definitions @@ -1236,7 +1236,7 @@ static void linphone_upnp_config_list_port_bindings_cb(const char *entry, struct bool_t valid = TRUE; UpnpPortBinding *port; - ret = sscanf(entry, "%"UPNP_UUID_LEN_STR"s-%3s-%i-%i", device_id, protocol_str, &external_port, &local_port); + 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) { From 63117d28af1744331b550482742543b48d6f2495 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 2 Apr 2013 15:41:14 +0200 Subject: [PATCH 200/909] Use correct mode parameter to fopen() call ("r+" instead of "rw"). --- coreapi/lpconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index db4e5de5c..dd3de63db 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -215,7 +215,7 @@ LpConfig * lp_config_new(const char *filename){ if (filename!=NULL){ ms_message("Using (r/w) config information from %s", filename); lpconfig->filename=ortp_strdup(filename); - lpconfig->file=fopen(filename,"rw"); + lpconfig->file=fopen(filename,"r+"); if (lpconfig->file!=NULL){ struct stat fileStat; lp_config_parse(lpconfig,lpconfig->file); From 08b6f466a0d71db1becfda13fd2b2adb9935fd9a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 3 Apr 2013 18:15:59 +0200 Subject: [PATCH 201/909] javadoc enhancements --- coreapi/linphonecore.h | 62 +++- .../org/linphone/core/CallDirection.java | 10 +- .../org/linphone/core/LinphoneAddress.java | 29 +- .../org/linphone/core/LinphoneAuthInfo.java | 2 +- .../org/linphone/core/LinphoneCallLog.java | 20 +- .../org/linphone/core/LinphoneCore.java | 310 +++++++++++++++--- .../linphone/core/LinphoneCoreFactory.java | 6 + .../org/linphone/core/LinphoneCoreImpl.java | 21 +- 8 files changed, 385 insertions(+), 75 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ab8836a5d..241813790 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -47,12 +47,29 @@ typedef struct _LinphoneCore LinphoneCore; struct _LpConfig; -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; @@ -934,7 +951,12 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); - +/** + * @ingroup media_parameters + * Get default call parameters reflecting current linphone core configuration + * @param LinphoneCore object + * @return LinphoneCallParams + */ LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); @@ -982,16 +1004,23 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); - +/** + * Enable payload type + * @param linphone core + * @param pt payload type to enable, can be retrieve from #linphone_core_find_payload_type + * @param TRUE if enabled + * @return 0 if succed + * + */ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); /** - * Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algirithm + * 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 @@ -1370,7 +1399,13 @@ 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); - +/** + * 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 + */ const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); @@ -1385,8 +1420,19 @@ int linphone_core_terminate_conference(LinphoneCore *lc); 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); - +/** + * 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 + */ int linphone_core_get_max_calls(LinphoneCore *lc); +/** + * Set the maximum number of simultaneous calls Linphone core can manage at a time. All new call above this limit are declined with a busy answer + * @ingroup initializing + * @param lc core + * @param max number of simultaneous calls + */ void linphone_core_set_max_calls(LinphoneCore *lc, int max); bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); 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/LinphoneAddress.java b/java/common/org/linphone/core/LinphoneAddress.java index b2a2c9380..fe5164b01 100644 --- a/java/common/org/linphone/core/LinphoneAddress.java +++ b/java/common/org/linphone/core/LinphoneAddress.java @@ -39,21 +39,48 @@ public interface LinphoneAddress { */ public String getUserName(); /** - * + * Domain name * @return null if not set */ public String getDomain(); + /** + * Port as String + * @return null if not set + */ public String getPort(); + /** + * Port as integer value. + * @return negative value if not set if not set + */ public int getPortInt(); /** * 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); + /** + * set port as String + * @param port, null if not set + */ public void setPort(String port); + /** + * set port as int + * @param port, negative value if not set + */ public void setPortInt(int port); + /** + * Removes address's tags and uri headers so that it is displayable to the user. + **/ public void clean(); /** diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index ed8a84017..0213720eb 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. 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/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index ab25520a4..144b7dfe2 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -20,6 +20,9 @@ package org.linphone.core; import java.util.Vector; +import org.linphone.core.LinphoneCall.State; +import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; + /** * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}. * @@ -172,11 +175,22 @@ public interface LinphoneCore { } /** - * 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() {}; @@ -389,10 +403,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,6 +416,8 @@ 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); /** @@ -417,7 +433,7 @@ public interface LinphoneCore { 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(); /** @@ -482,8 +498,6 @@ public interface LinphoneCore { */ public void deferCallUpdate(LinphoneCall aCall) throws LinphoneCoreException; - public void startRinging(); - /** * @return a list of LinphoneCallLog */ @@ -499,7 +513,7 @@ public interface LinphoneCore { */ public void setNetworkReachable(boolean isReachable); /** - * + * Get network state has known by {@link LinphoneCore} * @return if false, there is no network connection. */ public boolean isNetworkReachable(); @@ -541,16 +555,16 @@ public interface LinphoneCore { /** * 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 */ @@ -560,23 +574,43 @@ public interface LinphoneCore { * 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); /*** * 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); + + /*** + * 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; /** @@ -595,10 +629,11 @@ 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(); @@ -632,12 +667,36 @@ public interface LinphoneCore { * @return {@link LinphoneChatRoom} where messaging can take place. */ LinphoneChatRoom createChatRoom(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(); /** @@ -665,6 +724,7 @@ public interface LinphoneCore { */ void setStunServer(String stun_server); /** + * Get STUN server * @return stun server address if previously set. */ String getStunServer(); @@ -678,11 +738,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,7 +778,7 @@ 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(); @@ -706,7 +790,18 @@ public interface LinphoneCore { void setRootCA(String path); void setUploadBandwidth(int bw); - + /** + * 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); /** @@ -720,9 +815,20 @@ public interface LinphoneCore { * @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); - + /** + * get current preferred video size for sending. + * @return video size + * + **/ VideoSize getPreferredVideoSize(); /** @@ -766,13 +872,18 @@ public interface LinphoneCore { 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); @@ -783,33 +894,75 @@ 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); + /** + * 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(); /** - * Terminate the conference, all users are disconnected. + * 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); @@ -817,22 +970,60 @@ public interface LinphoneCore { * 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); - + /** + * 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); /** @@ -884,15 +1075,31 @@ public interface LinphoneCore { void tunnelAddServerAndMirror(String host, int port, int udpMirrorPort, int roundTripDelay); 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); - + /** 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); /** @@ -961,7 +1168,10 @@ public interface LinphoneCore { * 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); /** diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index ea325057e..5e8637999 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -48,6 +48,12 @@ abstract public class LinphoneCoreFactory { } return theLinphoneCoreFactory; } + /** + * 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); /** * create {@link LinphoneAuthInfo} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 5a52f7559..0b4c984d6 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -745,12 +745,6 @@ 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) { @@ -801,10 +795,17 @@ class LinphoneCoreImpl implements LinphoneCore { 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); @@ -908,4 +909,8 @@ class LinphoneCoreImpl implements LinphoneCore { public void stopConferenceRecording() { stopConferenceRecording(nativePtr); } + @Override + public PayloadType findPayloadType(String mime) { + return findPayloadType(mime, FIND_PAYLOAD_IGNORE_RATE); + } } From 6f1ca06a9f783b5c84674d1b345afc330d22eaa5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 4 Apr 2013 08:23:33 +0200 Subject: [PATCH 202/909] fix compilation issue --- coreapi/linphonecore.h | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 241813790..fefd050e7 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -71,7 +71,6 @@ typedef struct _LCSipTransports{ int tls_port; } LCSipTransports; -typedef struct _LCSipTransports LCSipTransports; /** * Object that represents a SIP address. From fd7d18bf5a250a1dcfe75c69bb4b86f52f7b60c5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 4 Apr 2013 11:33:43 +0200 Subject: [PATCH 203/909] Add exports. --- coreapi/linphonecore.h | 26 +++++++++++++------------- coreapi/lpconfig.h | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5e2c1f77e..d0e077b46 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -91,7 +91,7 @@ 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); +LINPHONE_PUBLIC int linphone_address_get_port_int(const LinphoneAddress *u); /** * Get port number, null if not present. */ @@ -625,17 +625,17 @@ typedef struct _LinphoneAuthInfo LinphoneAuthInfo; LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1,const char *realm); -void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); -void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); -void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); -void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); -void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); +LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); +LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); +LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); +LINPHONE_PUBLIC void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); +LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); -const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); /* you don't need those function*/ void linphone_auth_info_destroy(LinphoneAuthInfo *info); @@ -992,7 +992,7 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); -bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); +LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); @@ -1050,7 +1050,7 @@ LINPHONE_PUBLIC void linphone_core_add_auth_info(LinphoneCore *lc, const Linphon 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); diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 310baaff3..6079a80ee 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -73,7 +73,7 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * @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); +LINPHONE_PUBLIC 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); /** * Retrieves a configuration item as a range, given its section, key, and default min and max values. @@ -82,14 +82,14 @@ 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. @@ -97,7 +97,7 @@ int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ -int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value); +LINPHONE_PUBLIC int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value); int lp_config_read_file(LpConfig *lpconfig, const char *filename); @@ -107,25 +107,25 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * @ingroup misc * The default float value is returned if the config item isn't found. **/ -float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); +LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); /** * Sets a string config item * * @ingroup misc **/ -void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); +LINPHONE_PUBLIC void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); /** * Sets a range config item * * @ingroup misc */ -void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value); +LINPHONE_PUBLIC void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value); /** * Sets an integer config item * * @ingroup misc **/ -void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); +LINPHONE_PUBLIC void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); /** * Sets an integer config item, but store it as hexadecimal @@ -139,14 +139,14 @@ void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *k * * @ingroup misc **/ -void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value); +LINPHONE_PUBLIC void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value); /** * Sets a float config item * * @ingroup misc **/ -void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); +LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); /** * Writes the config file to disk. * From 2499c3aa4f129b4475f63793a9241fc4af71a37a Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 4 Apr 2013 16:30:32 +0200 Subject: [PATCH 204/909] Automatically adding friends in the address book Display missed call in recent calls tab Notification for chat message --- gtk/calllogs.c | 82 ++++++++++++++++++++++++------- gtk/chat.c | 92 ++++++++++++++++++++++++++-------- gtk/friendlist.c | 123 +++++++++++++++++++++++++++++----------------- gtk/incall_view.c | 9 ++-- gtk/linphone.h | 4 +- gtk/main.c | 2 +- gtk/main.ui | 121 +++++++++++++++++++++++++++++---------------- 7 files changed, 299 insertions(+), 134 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 9d2714153..481c8d3d3 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -19,7 +19,6 @@ 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; @@ -36,14 +35,16 @@ static void fill_renderers(GtkTreeView *v){ void call_log_selection_changed(GtkTreeView *v){ GtkTreeSelection *select; GtkTreeIter iter; - GtkTreeModel *model; + GtkTreeModel *model=NULL; select = gtk_tree_view_get_selection(v); - 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); + 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); + } } } @@ -91,19 +92,18 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){ static bool_t put_selection_to_uribar(GtkWidget *treeview){ GtkTreeSelection *sel; - + sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); if (sel!=NULL){ GtkTreeModel *model=NULL; GtkTreeIter iter; if (gtk_tree_selection_get_selected (sel,&model,&iter)){ - 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); + LinphoneAddress *la; + gtk_tree_model_get(model,&iter,2,&la,-1); + 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; } @@ -159,7 +159,6 @@ static GtkWidget *linphone_gtk_create_call_log_menu(GtkWidget *call_log){ 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); @@ -186,25 +185,74 @@ gboolean linphone_gtk_call_log_button_pressed(GtkWidget *widget, GdkEventButton 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; + + l=gtk_label_new("Recent calls"); + 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){ + 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")); GtkTreeStore *store; const MSList *logs; GtkTreeSelection *select; + GtkWidget *notebook=linphone_gtk_get_widget(w,"viewswitch"); + gint nb; store=(GtkTreeStore*)gtk_tree_view_get_model(v); if (store==NULL){ - store=gtk_tree_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"))); } + 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){ @@ -237,7 +285,6 @@ void linphone_gtk_call_log_update(GtkWidget *w){ } else { display=linphone_address_get_display_name(la); } - if (display==NULL){ display=linphone_address_get_username (la); if (display==NULL){ @@ -294,7 +341,6 @@ void linphone_gtk_call_log_update(GtkWidget *w){ g_free(logtxt); g_free(headtxt); } - } void linphone_gtk_history_row_activated(GtkWidget *treeview){ diff --git a/gtk/chat.c b/gtk/chat.c index 69c4e832f..9c0f64bbb 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -61,10 +61,9 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { 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")); g_return_if_fail(w!=NULL); - gtk_notebook_remove_page(GTK_NOTEBOOK(nb),idx); + gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); linphone_gtk_create_chat_picture(FALSE); g_object_set_data(G_OBJECT(friendlist),"chatview",NULL); g_object_set_data(G_OBJECT(w),"from_message",NULL); @@ -74,7 +73,8 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { } const char* get_display_name(const LinphoneAddress *from){ - const char *display=linphone_address_get_display_name(from); + const char *display; + display=linphone_address_get_display_name(from); if (display==NULL || display[0]=='\0') { display=linphone_address_get_username(from); } @@ -92,7 +92,7 @@ GtkWidget *create_tab_chat_header(LinphoneChatRoom *cr,const LinphoneAddress *ur 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); - l=gtk_label_new (get_display_name(uri)); + 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); @@ -131,7 +131,12 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, char *from_message=(char *)g_object_get_data(G_OBJECT(w),"from_message"); GList *list=g_object_get_data(G_OBJECT(w),"list"); time_t t; - + char buf[80]; + time_t tnow; + struct tm *tm; + int tnow_day; + int tnow_year; + gtk_text_buffer_get_start_iter(buffer,&begin); gtk_text_buffer_get_end_iter(buffer,&iter); off=gtk_text_iter_get_offset(&iter); @@ -162,15 +167,22 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, } case LinphoneChatMessageStateDelivered: { - struct tm *tm=localtime(&t); - char buf[80]; + tnow=time(NULL); + tm=gmtime(&tnow); + tnow_day=tm->tm_yday; + tnow_year=tm->tm_year; + tm=gmtime(&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, - "right","small","italic","font_grey",me ? "bg":NULL,NULL); - break; + } + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,buf,-1, + "right","small","italic","font_grey",me ? "bg":NULL,NULL); + break; } case LinphoneChatMessageStateNotDelivered: - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Error",-1, + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Message not sent",-1, "right","small","italic","font_grey",me ? "bg":NULL,NULL); break; default : gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1, @@ -202,6 +214,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag GtkTextIter iter; GtkTextIter end; GtkTextIter start; + gchar *result; gtk_text_buffer_get_iter_at_line(b,&iter, GPOINTER_TO_INT(g_list_nth_data(list,0))); @@ -217,7 +230,6 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag 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; switch (state) { case LinphoneChatMessageStateInProgress: result="Sending "; @@ -295,6 +307,29 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon } } +void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ + //LinphoneAddress *addr=(LinphoneAddress *)data; + LinphoneFriend *lf=NULL; + char *uri=linphone_address_as_string(addr); + lf=linphone_friend_new_with_addr(uri); + ms_free(uri); + char *fixed_uri=NULL; + gboolean show_presence=FALSE; + + linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); + linphone_friend_send_subscribe(lf,show_presence); + + linphone_core_interpret_friend_uri(linphone_gtk_get_core(),uri,&fixed_uri); + if (fixed_uri==NULL){ + linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); + return ; + } + linphone_friend_set_addr(lf,addr); + linphone_core_add_friend(linphone_gtk_get_core(),lf); + ms_free(fixed_uri); + linphone_gtk_show_friends(); +} + 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 (); @@ -312,7 +347,6 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres color.red = 32512; color.green = 32512; color.blue = 32512; - colorb.red = 56832; colorb.green = 60928; colorb.blue = 61952; @@ -321,12 +355,12 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres linphone_chat_room_mark_as_read(cr); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text),FALSE); 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); 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),"list",list); gtk_text_buffer_create_tag(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), @@ -369,18 +403,25 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, char *uri_str=linphone_address_as_string(uri); char *uri_only=linphone_address_as_string_uri_only(uri); MSList *messages=NULL; - + linphone_chat_room_mark_as_read(cr); 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; + GtkWidget *cb; 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); + cb=linphone_gtk_get_widget(chat_view,"contact_bar"); + if(!linphone_gtk_friend_list_is_contact(uri)){ + gtk_widget_show(cb); + } else { + gtk_widget_hide(cb); + } g_object_set_data(G_OBJECT(chat_view),"cr",cr); 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); @@ -389,6 +430,7 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, } ms_free(from_str); ms_free(uri_str); + ms_free(uri_only); } void linphone_gtk_chat_destroyed(GtkWidget *w){ @@ -408,18 +450,27 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, 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"); char *from=linphone_address_as_string(linphone_chat_message_get_from(msg)); + w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); if(w!=NULL){ char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ send=TRUE; } else { + if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ + //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); + linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); + } send=FALSE; } } else { send=FALSE; + if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ + //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); + 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); g_object_set_data(G_OBJECT(friendlist),"from",from); @@ -439,14 +490,13 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } #endif if(send){ - linphone_chat_room_mark_as_read(room); + if(gtk_notebook_get_current_page(notebook)!=gtk_notebook_page_num(notebook,w)){ + linphone_gtk_show_friends(); + } linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), FALSE,room,msg,FALSE); } else { linphone_gtk_show_friends(); - //linphone_gtk_friend_list_update_message(msg); } - //linphone_gtk_update_chat_picture(); - //gtk_window_present(GTK_WINDOW(w)); - /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ + //linphone_gtk_update_chat_picture(); } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 9f5a935b8..3997e29f3 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -32,7 +32,6 @@ enum{ FRIEND_ICON, FRIEND_CALL, FRIEND_CHAT, - FRIEND_NB_UNREAD_MSG, FRIEND_LIST_NCOL }; @@ -76,17 +75,23 @@ 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_active_chat_picture(){ GdkPixbuf *pixbuf; pixbuf = create_pixbuf("active_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 +115,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; @@ -156,28 +171,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=gtk_widget_get_toplevel(button); + GtkWidget *w=linphone_gtk_get_main_window(); GtkTreeSelection *select; GtkTreeIter iter; GtkTreeModel *model; + GtkWidget *chat_view; LinphoneFriend *lf=NULL; - select = gtk_tree_view_get_selection(GTK_TREE_VIEW(linphone_gtk_get_widget(w,"contact_list"))); + 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); - cr=linphone_core_get_chat_room(linphone_gtk_get_core(),linphone_friend_get_address(lf)); + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); linphone_chat_room_delete_history(cr); + if(chat_view!=NULL){ + char *from=g_object_get_data(G_OBJECT(friendlist),"from"); + char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); + if(g_strcmp0(from,addr)==0){ + 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(); } } @@ -209,7 +247,7 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } -void linphone_gtk_tree_view_set_chat_conversation(LinphoneAddress *la){ +void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ GtkTreeIter iter; GtkListStore *store=NULL; GtkWidget *w = linphone_gtk_get_main_window(); @@ -240,7 +278,7 @@ void linphone_gtk_tree_view_set_chat_conversation(LinphoneAddress *la){ do{ const LinphoneAddress *uri; char *lf_str; - gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); + gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1); uri=linphone_friend_get_address(lf); lf_str=linphone_address_as_string(uri); if( g_strcmp0(lf_str,la_str)==0){ @@ -259,14 +297,30 @@ void linphone_gtk_tree_view_set_chat_conversation(LinphoneAddress *la){ gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); linphone_gtk_create_chat_picture(FALSE); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); - gtk_list_store_set(store,&iter,FRIEND_CHAT,create_active_chat_picture(),-1); - gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,"",-1); 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; + const LinphoneAddress *addr=(const LinphoneAddress *)data; + 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=linphone_core_get_chat_room(linphone_gtk_get_core(),addr); + if(cr!=NULL){ + linphone_chat_room_mark_as_read(cr); + linphone_gtk_show_friends(); + } + } } - } void linphone_gtk_chat_selected(GtkWidget *item){ @@ -303,8 +357,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,page)); linphone_gtk_create_chat_picture(FALSE); 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); - gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,"",-1); + g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,(gpointer)uri); } } @@ -577,8 +630,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_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)); @@ -588,7 +640,7 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(friendlist),friend_search_func,NULL,NULL); gtk_tree_view_set_search_column(GTK_TREE_VIEW(friendlist),FRIEND_NAME); gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),FRIEND_NAME,friend_sort,NULL,NULL); - + /*Name and presence column*/ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Presence status"), @@ -599,6 +651,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); @@ -616,11 +669,6 @@ static void linphone_gtk_friend_list_init(GtkWidget *friendlist){ gtk_tree_view_column_set_clickable(column,TRUE); gtk_tree_view_column_set_expand(column,TRUE); gtk_tree_view_column_set_max_width(column,60); - - renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start(column,renderer,TRUE); - gtk_tree_view_column_add_attribute (column,renderer,"text",FRIEND_NB_UNREAD_MSG); - gtk_tree_view_append_column (GTK_TREE_VIEW (friendlist), column); /* Call column*/ @@ -641,7 +689,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);*/ } @@ -713,7 +761,6 @@ void linphone_gtk_show_friends(void){ 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); } @@ -735,7 +782,7 @@ 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}; + //char buf[26]={0}; int nbmsg=0; /*if (lookup){ @@ -752,26 +799,13 @@ void linphone_gtk_show_friends(void){ gtk_list_store_append(store,&iter); 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_tree_model_get(gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)),&iter,FRIEND_CHATROOM,&cr,-1); - if(cr!=NULL){ - nbmsg=linphone_chat_room_get_unread_messages_count(cr); - if(nbmsg != 0){ - sprintf(buf,"%i",nbmsg); - } - } else { - 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){ - sprintf(buf,"%i",nbmsg); - } + FRIEND_CHAT,create_chat_picture(),FRIEND_CALL,create_call_picture(),-1); + 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){ + gtk_list_store_set(store,&iter,FRIEND_CHAT,create_unread_msg(),-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); - gtk_list_store_set(store,&iter,FRIEND_NB_UNREAD_MSG,buf,-1); escaped=g_markup_escape_text(uri,-1); gtk_list_store_set(store,&iter,FRIEND_SIP_ADDRESS,escaped,-1); g_free(escaped); @@ -823,6 +857,7 @@ void linphone_gtk_contact_ok(GtkWidget *button){ char *fixed_uri=NULL; 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){ @@ -841,7 +876,7 @@ void linphone_gtk_contact_ok(GtkWidget *button){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - LinphoneAddress* friend_address = linphone_address_new(fixed_uri); + friend_address = linphone_address_new(fixed_uri); linphone_address_set_display_name(friend_address,name); linphone_friend_set_addr(lf,friend_address); linphone_address_destroy(friend_address); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 0a64a1041..4ab0bd72e 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -431,8 +431,6 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *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,12 +442,13 @@ 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){ diff --git a/gtk/linphone.h b/gtk/linphone.h index ccdebea69..00484a04f 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -152,5 +152,5 @@ void linphone_gtk_monitor_usb(void); void linphone_gtk_unmonitor_usb(void); gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); -void linphone_gtk_friend_list_update_message(LinphoneChatMessage *msg); -void linphone_gtk_tree_view_set_chat_conversation(LinphoneAddress *la); +void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la); +gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); \ No newline at end of file diff --git a/gtk/main.c b/gtk/main.c index b188782ab..e3699757f 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1726,6 +1726,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); @@ -1748,7 +1749,6 @@ static void linphone_gtk_init_main_window(){ linphone_gtk_check_menu_items(); } - void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ if (verbose){ const char *lname="undef"; diff --git a/gtk/main.ui b/gtk/main.ui index 0b27240e7..5875bc844 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -104,6 +104,41 @@ True False + + + True + False + + + True + False + + + True + True + 0 + + + + + True + True + True + False + + + False + False + 1 + + + + + False + True + 0 + + True @@ -120,7 +155,7 @@ True True - 0 + 1 @@ -192,7 +227,8 @@ False False - 1 + end + 2 @@ -794,6 +830,8 @@ False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 660 + 450 True @@ -1042,6 +1080,7 @@ False False + 6 end 1 @@ -1247,49 +1286,11 @@ 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 @@ -1375,7 +1376,7 @@ False False 5 - 2 + 0 @@ -1401,14 +1402,47 @@ False False - 3 + 1 False False - end + 1 + + + + + True + False + end + + + gtk-clear + True + True + True + False + True + + + + False + False + 0 + + + + + + + + + + + False + True 2 @@ -1428,6 +1462,7 @@ True False + True From 5ede7a56fab54a9bfd8e217d1f3b06d33b1e33dd Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 4 Apr 2013 16:44:46 +0200 Subject: [PATCH 205/909] Fix upnp binding loop when not getting provided port --- coreapi/upnp.c | 11 +++++------ mediastreamer2 | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index c7e2ffd0b..982ab0368 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -558,9 +558,8 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind 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", PACKAGE_NAME, @@ -882,7 +881,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); + *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, -1); } // Get addresses @@ -1112,8 +1111,8 @@ void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBi 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) { diff --git a/mediastreamer2 b/mediastreamer2 index 8e7337469..f6c51a11f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8e7337469af474929fd038f1e4743737ff0a904b +Subproject commit f6c51a11f1ef1156c6f768b8466698a2305a2188 From 9e6bb9aff75004c3a71ccc1b561a816987b8b6e5 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 4 Apr 2013 16:49:46 +0200 Subject: [PATCH 206/909] Fix tab click --- gtk/calllogs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 481c8d3d3..7daa1b011 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -201,6 +201,9 @@ void linphone_gtk_call_log_clear_missed_call(){ } 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; From 12265257ed32a3a2059c7278453ecc3a5365b454 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 4 Apr 2013 16:44:46 +0200 Subject: [PATCH 207/909] Fix upnp binding loop when not getting provided port --- coreapi/upnp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index ec7d1f9c6..71a3c9d2a 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -553,9 +553,8 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind 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", PACKAGE_NAME, @@ -877,7 +876,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); + *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, -1); } // Get addresses @@ -1107,8 +1106,8 @@ void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBi 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) { From 882622f1deb20a3c37fde08e69d532aae9515304 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 4 Apr 2013 17:06:01 +0200 Subject: [PATCH 208/909] remove some features in the interface change date --- gtk/chat.c | 9 +-------- gtk/main.ui | 40 ++-------------------------------------- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 9c0f64bbb..cf6d61c98 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -237,7 +237,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag case LinphoneChatMessageStateDelivered: { time_t t=time(NULL); - struct tm *tm=localtime(&t); + struct tm *tm=gmtime(&t); char buf[80]; strftime(buf,80,"%H:%M",tm); result=buf; @@ -410,18 +410,11 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, GtkTextIter start; GtkTextIter end; GtkTextBuffer *text_buffer; - GtkWidget *cb; 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); - cb=linphone_gtk_get_widget(chat_view,"contact_bar"); - if(!linphone_gtk_friend_list_is_contact(uri)){ - gtk_widget_show(cb); - } else { - gtk_widget_hide(cb); - } g_object_set_data(G_OBJECT(chat_view),"cr",cr); 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); diff --git a/gtk/main.ui b/gtk/main.ui index 5875bc844..347a402ea 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -104,41 +104,6 @@ True False - - - True - False - - - True - False - - - True - True - 0 - - - - - True - True - True - False - - - False - False - 1 - - - - - False - True - 0 - - True @@ -155,7 +120,7 @@ True True - 1 + 0 @@ -227,8 +192,7 @@ False False - end - 2 + 1 From 7dc5adeaf411b897b7690f731d5f5e4f12ab1a06 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 4 Apr 2013 17:21:56 +0200 Subject: [PATCH 209/909] Export refresh registers --- coreapi/linphonecore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d0e077b46..f2e331c78 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1376,7 +1376,7 @@ 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); From 43e311b769eb937c5a185d79427de7f0feb83be9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Apr 2013 12:16:05 +0200 Subject: [PATCH 210/909] fix sending of PUBLISH requests (was not set to the proxy address actually) --- coreapi/proxy.c | 1 + coreapi/sal_eXosip2_presence.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5546102ba..42c21f01b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -792,6 +792,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphoneOnlineStatus presence_mode){ int err; SalOp *op=sal_op_new(proxy->lc->sal); + sal_op_set_route(op,proxy->reg_proxy); err=sal_publish(op,linphone_proxy_config_get_identity(proxy), linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode)); if (proxy->publish_op!=NULL) diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 356d2a9fb..ffa7ed920 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -635,7 +635,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - i = eXosip_build_publish(&pub,from, to, NULL, "presence", "300", + i = eXosip_build_publish(&pub,from, to, sal_op_get_route(op), "presence", "300", presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); if (i<0){ ms_warning("Failed to build publish request."); From aad536f02b924e463a23f43f7da95608098293dc Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 5 Apr 2013 12:45:00 +0200 Subject: [PATCH 211/909] Don't include xml2lpc and lpc2xml in android.mk --- build/android/Android-no-neon.mk | 2 -- build/android/Android.mk | 7 ------- build/android/lpc2xml.mk | 1 + build/android/xml2lpc.mk | 1 + 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index d0c87b4f8..d8e75ca0b 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -21,7 +21,6 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi - include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk @@ -43,4 +42,3 @@ include $(BUILD_SHARED_LIBRARY) $(call import-module,android/cpufeatures) - diff --git a/build/android/Android.mk b/build/android/Android.mk index 7fb75d0a4..10fba32dd 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -39,10 +39,3 @@ include $(BUILD_SHARED_LIBRARY) $(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/lpc2xml.mk b/build/android/lpc2xml.mk index f7858f94d..b5757ad99 100644 --- a/build/android/lpc2xml.mk +++ b/build/android/lpc2xml.mk @@ -40,6 +40,7 @@ LOCAL_C_INCLUDES = \ LOCAL_SHARED_LIBRARIES = \ libxml2 \ + liblinphonenoneon \ liblinphone \ LOCAL_MODULE := liblpc2xml diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk index 32bfb38c3..449251cc8 100644 --- a/build/android/xml2lpc.mk +++ b/build/android/xml2lpc.mk @@ -40,6 +40,7 @@ LOCAL_C_INCLUDES = \ LOCAL_SHARED_LIBRARIES = \ libxml2 \ + liblinphonenoneon \ liblinphone \ LOCAL_MODULE := libxml2lpc From 30f5b028b4be6ac1dbdd23ab1b9fb004b6236aa2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 5 Apr 2013 15:38:31 +0200 Subject: [PATCH 212/909] fix build issue introduced by LINPHONE_PUBLIC --- coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/lpconfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f68784277..7f360710f 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -581,7 +581,7 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){ if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require") || belle_sip_message_get_header((belle_sip_message_t*)req,"Supported")) { belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); belle_sip_header_contact_t* contact_header; - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_message_get_header((belle_sip_message_t*)req,"Require")); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100Rel"))); belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1"))); 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)); diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 6079a80ee..8b7bbb825 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -24,7 +24,7 @@ #ifndef LPCONFIG_H #define LPCONFIG_H - +#include "linphonecore.h" /*to get LINPHONE_PUBLIC, maybe we can include less stuff*/ #include /** From ec1d4483a9147e29885cd28b70856afd5ed1609e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Apr 2013 18:24:07 +0200 Subject: [PATCH 213/909] set mtu to 1300 because mtu detection is absolutely not reliable. This is making a lot of problems with video packets especially. --- coreapi/linphonecore.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0089dd0fb..7b4d6a998 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -463,7 +463,7 @@ static void net_config_read (LinphoneCore *lc) 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); diff --git a/mediastreamer2 b/mediastreamer2 index 8596ed901..f6c51a11f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8596ed9017c0d9b9c63c758d7628bac1fc07efd7 +Subproject commit f6c51a11f1ef1156c6f768b8466698a2305a2188 From 542a84503cc5871b89c89dc1e83e3f49fbed3b33 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 8 Apr 2013 12:59:42 +0200 Subject: [PATCH 214/909] change unread messages picture chnage time for time change --- coreapi/message_storage.c | 1 + coreapi/sal_eXosip2.c | 1 + gtk/chat.c | 11 +++++------ pixmaps/active_chat.png | Bin 3103 -> 3415 bytes 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 0c41c20d0..8ba642b68 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -66,6 +66,7 @@ static void create_chat_message(char **argv, void *data){ for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; } + ret.tm_isdst=-1; } new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); new_message->state=atoi(argv[7]); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 2ea0f9aff..b86fc26e0 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1798,6 +1798,7 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; } + ret.tm_isdst=-1; }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); diff --git a/gtk/chat.c b/gtk/chat.c index cf6d61c98..9bcf0bb8b 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -168,10 +168,10 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, case LinphoneChatMessageStateDelivered: { tnow=time(NULL); - tm=gmtime(&tnow); + tm=localtime(&tnow); tnow_day=tm->tm_yday; tnow_year=tm->tm_year; - tm=gmtime(&t); + 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 { @@ -237,7 +237,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag case LinphoneChatMessageStateDelivered: { time_t t=time(NULL); - struct tm *tm=gmtime(&t); + struct tm *tm=localtime(&t); char buf[80]; strftime(buf,80,"%H:%M",tm); result=buf; @@ -450,10 +450,10 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(w!=NULL){ char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ + linphone_chat_room_mark_as_read(room); send=TRUE; } else { if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ - //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); } send=FALSE; @@ -461,7 +461,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } else { send=FALSE; if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ - //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); } w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); @@ -469,6 +468,7 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, g_object_set_data(G_OBJECT(friendlist),"from",from); } get_display_name(linphone_chat_message_get_from(msg)); + #ifdef HAVE_GTK_OSXs /* Notified when a new message is sent */ linphone_gtk_status_icon_set_blinking(TRUE); @@ -491,5 +491,4 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } else { linphone_gtk_show_friends(); } - //linphone_gtk_update_chat_picture(); } diff --git a/pixmaps/active_chat.png b/pixmaps/active_chat.png index e428845d55648e21ab59ad6c9d94e48b7e8a70ea..d82b7c595c8a90fddb3c313be4bd9c6c524b0af4 100644 GIT binary patch delta 677 zcmV;W0$Tl_7}pxGzY2c>f=NU{RCwCVRbNO`Q5^ox_1e8H-8F<|u7Uc{LqQStVh@I- zL7*WNJ@_L1c?hWpst0>4DC(_25Co>ih(Z&I>_x1mlL&$+v_h*%CexQ~y0-3hp0B55 zy1VHdK|lB&4u^Ao=ljF&2$J~MrEK(|Iq?AA^9L~-9)tYxth#^6B`Ad8Vefe7(Yq5U zb=TnZy+D3VwBjNRJohWLwfB|Jn?3WM9l`|4(Qv@?y1mqg_{5 zni&xqd&LR`1X6$CE~6`Dy{+ZW49RpRx~{|NbgnIzQI4CwN7yt!ftCx`V46wbX9#lu z%63-6REuxTPJR0T0BKB~_VzNTS~7WNUooM80)j#-VtdyJ&kp<&?n{FpX=8j!q%F%r zwusAQ0v%URqU-$vb{#u~%f}m_nK8WRybUWBI?;6GkZym=q&Ej9;jeG$7J`6I-^eVZ z(eG^BzLfyD=iI|57l&D5>&aTFO0AO0{rEUNiN_s-XsmI;sQ@=_wV^UxgO}WUg(f1l zO#1rzY+o&NX)7DA_8<@lFc=I%*L4_% zf%^J-0Kn+zC?b&vgb)xyEKBtF)ly23gp?A^&CMds=uGJD?j}k4{eBJ&4RO8xtVUMj zHBCcLPY)Is7g1MNCpMh8OdDRWmxf`WwY62``~4k?|N4*5rTz>6c>+{F&e}*B00000 LNkvXXu0mjfl!8b} delta 362 zcmV-w0hRvO8lM=jzY2c=N=ZaPRCwCdl`)ROFc3xmShk!rP6OL5$3WV2G*l^a1MZX~ zP^6;a0+A9aRM1j$0Hn~6CXr{GRm8%QC`3V8OKvQWM}GhNo0u764}mv~w=|J|EpE44 zCZb*k5fQAl_?S-d<@>*i>0XmKjyVVdxUP%7dNDH&`#q#mn9qOb^zj6GMdlX z49DZKT@xC}zp87vT6bu2gJ`$g;e0-K9z2;$;QM}4FQja5!Z(69g?$VFz*;-5h55&6 zofaN~ivfr}O0*z-KBR;!_z`KZai{eHg(02kWB6|-2`r~m)}07*qo IM6N<$f~JM4GXMYp From c5f71d3e6f6d404eceb8ada4ee00b41d0e25c2ce Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Apr 2013 13:56:44 +0200 Subject: [PATCH 215/909] update ms2 and ortp for call quality indicator improvements. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index f6c51a11f..d9ce543de 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f6c51a11f1ef1156c6f768b8466698a2305a2188 +Subproject commit d9ce543dee40d7cb7da55e50c6716a25f53ea2ba diff --git a/oRTP b/oRTP index 31d242e8c..35f5efbfb 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 31d242e8c544ed197f60630593515aef2fb580e9 +Subproject commit 35f5efbfbf7814bd0403249431a6b94d6c4286b4 From 34c9550f0eb873195960bf4e91e0b616e7810754 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 8 Apr 2013 14:09:45 +0200 Subject: [PATCH 216/909] fix unread messages --- gtk/chat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/chat.c b/gtk/chat.c index 9bcf0bb8b..a61afcf21 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -450,7 +450,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(w!=NULL){ char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ - linphone_chat_room_mark_as_read(room); send=TRUE; } else { if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ @@ -485,6 +484,8 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(send){ if(gtk_notebook_get_current_page(notebook)!=gtk_notebook_page_num(notebook,w)){ linphone_gtk_show_friends(); + } else { + linphone_chat_room_mark_as_read(room); } linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), FALSE,room,msg,FALSE); From 84eab624373493b0bbc0918fca5742fc566a90ad Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 8 Apr 2013 17:49:42 +0200 Subject: [PATCH 217/909] Add missing exports. --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9865a6894..d4ca59bea 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1231,7 +1231,7 @@ char linphone_core_get_sound_source(LinphoneCore *lc); void linphone_core_set_sound_source(LinphoneCore *lc, char source); 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); +LINPHONE_PUBLIC 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); @@ -1443,7 +1443,7 @@ int linphone_core_get_max_calls(LinphoneCore *lc); * @param lc core * @param max number of simultaneous calls */ -void linphone_core_set_max_calls(LinphoneCore *lc, int max); +LINPHONE_PUBLIC void linphone_core_set_max_calls(LinphoneCore *lc, int max); bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); From fac86ba95e895200240354f50e937c889259be61 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 8 Apr 2013 17:50:06 +0200 Subject: [PATCH 218/909] Define variables at the beginning of a code block. --- tester/call_tester.c | 6 ++++-- tester/message_tester.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 89021f501..64d19c2cb 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -320,9 +320,11 @@ static void cancelled_ringing_call(void) { static void early_declined_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - linphone_core_set_max_calls(marie->lc,0); LinphoneCallLog* in_call; - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + LinphoneCall* out_call; + + linphone_core_set_max_calls(marie->lc,0); + out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); diff --git a/tester/message_tester.c b/tester/message_tester.c index 730546a7d..140a369f9 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -80,6 +80,7 @@ static void text_message_compatibility_mode(void) { char*tmp; LCSipTransports transport; char* to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room; linphone_core_get_default_proxy(marie->lc,&proxy); CU_ASSERT_PTR_NOT_NULL (proxy); @@ -100,7 +101,7 @@ static void text_message_compatibility_mode(void) { CU_ASSERT_TRUE (wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,1)); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + chat_room = linphone_core_create_chat_room(marie->lc,to); linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceivedLegacy,1); From b4bb4268004b22608640cc352b2d854bc4c78003 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 8 Apr 2013 17:52:10 +0200 Subject: [PATCH 219/909] Add polarSSL to the LibLinphoneTester-wp8 project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 6 ++ .../LibLinphoneTester-wp8.sln | 80 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 6d8974c3d..1ffbcd88a 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -218,6 +218,12 @@ {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index f2d278134..ff1e6eade 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -41,6 +41,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcaecm", "..\..\..\..\webrtc\build\windows\webrtcaecm\webrtcaecm\webrtcaecm.vcxproj", "{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\belle-sip\build\windows\polarssl\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\windows\libilbc-rfc3951\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\windows\mssilk\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -301,6 +309,78 @@ Global {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.Build.0 = Release|Win32 {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.ActiveCfg = Release|Win32 {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Mixed Platforms.Build.0 = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.ActiveCfg = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.ActiveCfg = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Mixed Platforms.Build.0 = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.ActiveCfg = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Mixed Platforms.Build.0 = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From fead5875883a2e036ebc1717d04925554ce64e39 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 9 Apr 2013 10:02:59 +0200 Subject: [PATCH 220/909] Fix upnp forgotten retain --- coreapi/upnp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 71a3c9d2a..0922dad59 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -29,8 +29,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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_RETRY_DELAY 10 +#define UPNP_CALL_RETRY_DELAY 3 #define UPNP_UUID_LEN 128 #define UPNP_UUID_LEN_STR UPNP_TOSTRING(UPNP_UUID_LEN) /* @@ -876,7 +876,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, -1); + *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port); } // Get addresses @@ -1053,11 +1053,17 @@ 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; } @@ -1104,6 +1110,7 @@ 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 && From f9eae01a9399283f133e589b57d4bcd8e9a968b2 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 9 Apr 2013 10:49:08 +0200 Subject: [PATCH 221/909] Updated translation file Clear missed call Add picture for unread messages --- gtk/calllogs.c | 6 +- gtk/chat.c | 7 +- gtk/friendlist.c | 46 +++--- gtk/incall_view.c | 8 +- gtk/linphone.h | 30 ++-- gtk/main.c | 4 +- po/cs.po | 342 ++++++++++++++++++++------------------- po/de.po | 339 +++++++++++++++++++------------------- po/es.po | 348 ++++++++++++++++++++------------------- po/fr.po | 402 ++++++++++++++++++++++++---------------------- po/he.po | 352 +++++++++++++++++++++------------------- po/hu.po | 360 +++++++++++++++++++++-------------------- po/it.po | 344 ++++++++++++++++++++------------------- po/ja.po | 341 ++++++++++++++++++++------------------- po/nb_NO.po | 344 ++++++++++++++++++++------------------- po/nl.po | 341 ++++++++++++++++++++------------------- po/pl.po | 341 ++++++++++++++++++++------------------- po/pt_BR.po | 341 ++++++++++++++++++++------------------- po/ru.po | 348 ++++++++++++++++++++------------------- po/sr.po | 348 ++++++++++++++++++++------------------- po/sv.po | 344 ++++++++++++++++++++------------------- po/zh_CN.po | 344 ++++++++++++++++++++------------------- po/zh_TW.po | 344 ++++++++++++++++++++------------------- 23 files changed, 3157 insertions(+), 2867 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 7daa1b011..466541006 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -61,7 +61,7 @@ void linphone_gtk_call_log_chat_selected(GtkWidget *w){ gtk_tree_model_get(model,&iter,2,&pla,-1); la=(LinphoneAddress*)pla; if (la!=NULL){ - linphone_gtk_tree_view_set_chat_conversation(la); + linphone_gtk_friend_list_set_chat_conversation(la); } } } @@ -192,8 +192,9 @@ void linphone_gtk_call_log_clear_missed_call(){ 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("Recent calls"); + 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); @@ -359,6 +360,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)); } diff --git a/gtk/chat.c b/gtk/chat.c index a61afcf21..4fa1c917c 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -64,7 +64,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); - linphone_gtk_create_chat_picture(FALSE); + 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); g_object_set_data(G_OBJECT(w),"cr",NULL); @@ -385,6 +385,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); entry = linphone_gtk_get_widget(chat_view,"text_entry"); g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL); + g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL); ms_free(with_str); return chat_view; } @@ -404,13 +405,13 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, char *uri_only=linphone_address_as_string_uri_only(uri); MSList *messages=NULL; - linphone_chat_room_mark_as_read(cr); 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; - + + linphone_chat_room_mark_as_read(cr); 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); diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 3997e29f3..8f73c2fcb 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -87,11 +87,6 @@ static GdkPixbuf *create_chat_picture(){ return pixbuf; } -/*static GdkPixbuf *create_active_chat_picture(){ - GdkPixbuf *pixbuf; - pixbuf = create_pixbuf("active_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; @@ -226,18 +221,22 @@ 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; + int nbmsg=0; if (gtk_tree_model_get_iter_first(model,&iter)) { do{ - //if(!active){ + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + nbmsg=linphone_chat_room_get_unread_messages_count(cr); + if(nbmsg != 0){ + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); + } else { gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); - //} 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)); } } @@ -247,7 +246,7 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } -void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ +void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ GtkTreeIter iter; GtkListStore *store=NULL; GtkWidget *w = linphone_gtk_get_main_window(); @@ -270,7 +269,7 @@ void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ linphone_gtk_load_chatroom(cr,la,chat_view); } gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); - linphone_gtk_create_chat_picture(FALSE); + 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))); @@ -295,7 +294,7 @@ void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ linphone_gtk_load_chatroom(cr,uri,chat_view); } gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); - linphone_gtk_create_chat_picture(FALSE); + linphone_gtk_friend_list_update_chat_picture(); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); break; } @@ -309,17 +308,16 @@ void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guin GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); GtkWidget *chat_view; LinphoneChatRoom *cr=NULL; - const LinphoneAddress *addr=(const LinphoneAddress *)data; - 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=linphone_core_get_chat_room(linphone_gtk_get_core(),addr); - if(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(); + linphone_gtk_show_friends(); } - } + } } } @@ -355,9 +353,8 @@ void linphone_gtk_chat_selected(GtkWidget *item){ linphone_gtk_load_chatroom(cr,uri,page); } 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")); - g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,(gpointer)uri); } } @@ -809,7 +806,6 @@ void linphone_gtk_show_friends(void){ 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= diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 4ab0bd72e..44b35c03c 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")); @@ -688,7 +688,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ 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); @@ -843,7 +843,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) { @@ -859,7 +859,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); diff --git a/gtk/linphone.h b/gtk/linphone.h index 00484a04f..f987b2abe 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -58,7 +58,6 @@ 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); - const char *linphone_gtk_message_storage_get_db_file(const char *filename); void linphone_gtk_show_assistant(void); void linphone_gtk_close_assistant(void); @@ -68,15 +67,11 @@ 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); @@ -85,7 +80,6 @@ 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); @@ -99,21 +93,25 @@ 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); - void linphone_gtk_terminate_call(GtkWidget *button); -void update_tab_header(LinphoneCall *call,gboolean pause); - +void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause); 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); +LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); + +void linphone_gtk_friend_list_update_chat_picture(); +void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); +gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); +void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data); +void linphone_gtk_show_friends(void); +void linphone_gtk_show_contact(LinphoneFriend *lf); +void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); /*functions controlling the different views*/ gboolean linphone_gtk_use_in_call_view(); @@ -151,6 +149,4 @@ void linphone_gtk_uninit_instance(void); void linphone_gtk_monitor_usb(void); void linphone_gtk_unmonitor_usb(void); -gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); -void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la); -gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); \ No newline at end of file +gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); \ No newline at end of file diff --git a/gtk/main.c b/gtk/main.c index e3699757f..e914e42bd 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1232,10 +1232,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); diff --git a/po/cs.po b/po/cs.po index 726ba26a4..481b7aa17 100644 --- a/po/cs.po +++ b/po/cs.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-3.4.99.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-11-04 22:30+0100\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" @@ -27,26 +27,41 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Volat komu: %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Poslat text komu: %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Probíhá hovor" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "–" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "přerušen" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "promeškán" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Odmítnout" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -54,7 +69,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -62,21 +77,26 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konference" @@ -89,31 +109,35 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Neplatný sipový kontakt!" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "Soubor, kam zapisovat protokol." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 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:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Zavolá právě teď na tuto adresu" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "je-li nastaveno, automaticky zvedne příchozí hovor" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -121,12 +145,12 @@ msgstr "" "Zadejte pracovní adresář (měl by být základní instalační adresář, například " "c:\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Hovor s %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -139,7 +163,7 @@ msgstr "" "do svého adresáře?\n" "Odpovíte-li ne, tato osobo bude dočasně blokována." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -148,59 +172,59 @@ msgstr "" "Prosím, zadejte heslo pro uživatele %s\n" "v doméně %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Odpovědět" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Odmítnout" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Hovor odložen" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porty" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Odkaz na webovou stránku" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Lipnhone – internetový videofon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Výchozí)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Byly jsme přepojeni na %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -208,63 +232,54 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Volný SIP videofon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Zobrazit adresář" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Stav" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Jméno" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Volat komu: %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Diskuzní skupina" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Hledat v adresáři %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Neplatný sipový kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Volat komu: %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Poslat text komu: %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Upravit kontakt „%s“" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Odstranit kontakt „%s“" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Přidat nový kontakt z adresáře %s" @@ -365,20 +380,24 @@ msgstr "norština" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Žádná" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -634,114 +653,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Volá se…" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "dobrá" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "průměrná" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "slabá" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "velmi slabá" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "příliš špatná" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nedostupná" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "Probíhá konference" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Probíhá hovor" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Odložený hovor" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Hovor skončil." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Přepojit" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Přepojit" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Obnovit" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Odložit" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Odložit" @@ -764,157 +783,152 @@ msgstr "Odeslat" 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 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Přepojit" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Telefonuje se" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Délka" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Hodnocení kvality hovoru" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "V_olby" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Zobrazovat sám sebe" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "Nápo_věda" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Zobrazit ladicí okno" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Domovská stránka" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Vyhledat akt_ualizace" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP adresa nebo telefonní číslo:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Zahájit nový hovor" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakty" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Přidat" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Upravit" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Hledat" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Přidat kontakty z adresáře" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Přidat kontakt" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Nedávné hovory" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Moje současná totožnost:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Uživatelské jméno" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Heslo" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Připojení k Internetu:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Přihlašovat mě automaticky" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Informace o přihlášení" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Vítejte!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "všech uživatelích" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "připojených uživatelích" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber Channel" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Výchozí" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1529,7 +1543,7 @@ msgstr "" msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Připraven." @@ -1584,11 +1598,11 @@ msgstr "Připojeno." msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" @@ -1688,116 +1702,116 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Nelze se přihlásit jako %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Vyzvání na druhé straně." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Vyzvání na druhé straně…" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Časná média." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Hovor s %s je odložen." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Hovor přijat kým: %s – odložen." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Hovor obnoven." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Hovor přijat kým: %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Byli jsme obnoveni…" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Hovor byl aktualizován protistranou…" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Hovor ukončen." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Uživatel je zaneprázdněn." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Uživatel je dočasně nedostupný." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Uživatel si nepřeje být rušen." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Volání odmítnuto." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Žádná odpověď." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Chyba protokolu." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Přesměrováno" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Volání se nezdařilo." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrace na %s byla úspěšná." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Odregistrování z %s hotovo." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "odpověď nedorazila včas" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrace na %s selhala: %s" @@ -1807,7 +1821,7 @@ msgstr "Registrace na %s selhala: %s" msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/de.po b/po/de.po index a4745d95f..44c1e66ea 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-11-07 19:27+0100\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" @@ -17,53 +17,73 @@ msgstr "" "X-Generator: Lokalize 1.5\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "„%s“ anrufen" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Text zu „%s“ schicken" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Im Gespräch" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "nicht verfügbar" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Abgebrochen" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Entgangen" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Abgewiesen" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i Minute" msgstr[1] "%i Minuten" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i Sekunde" msgstr[1] "%i Sekunden" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format +msgid "%s\t%s" +msgstr "" + +#: ../gtk/calllogs.c:323 +#, fuzzy, 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" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:329 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\t\n" +"%s" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konferenz" @@ -76,33 +96,37 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Ungültiger SIP-Kontakt!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "Linphone mit ausgeschaltetem Video starten." -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 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:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Im Moment anzurufende Adresse" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Falls aktiviert, werden eingehende Anrufe automatisch beantwortet" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,12 +134,12 @@ msgstr "" "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. " "C:\\Programme\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Im Gespräch mit %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -128,7 +152,7 @@ msgstr "" "Ihrer Kontaktliste hinzufügen?\n" "Wenn Sie mit Nein antworten, wird diese Person vorläufig blockiert." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -137,59 +161,59 @@ msgstr "" "Geben Sie bitte Ihr Passwort für den Benutzernamen %s\n" " auf der Domäne %s ein:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Annehmen" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Abweisen" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Anruf wird gehalten" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, c-format msgid "by %s" msgstr "von %s" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, 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:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Website-Verknüpfung" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - ein Internet-Video-Telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Vorgabe)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Vermittlung nach %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -197,61 +221,52 @@ msgstr "" "Auf diesem Rechner können keine Soundkarten gefunden werden.\n" "Sie können keine Audio-Anrufe tätigen oder entgegennehmen." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Ein freies SIP-Video-Telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Zum Adressbuch hinzufügen" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Anwesenheitsstatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Name" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Anrufen" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Chat Raum" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Im %s-Verzeichnis suchen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Ungültiger SIP-Kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "„%s“ anrufen" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Text zu „%s“ schicken" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Kontakt „%s“ bearbeiten" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Kontakt „%s“ löschen" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" @@ -352,22 +367,26 @@ msgstr "Norwegisch" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Keinen" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -621,112 +640,112 @@ msgstr "" msgid "%.3f seconds" msgstr "%i Sekunde" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Verbindungsaufbau..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "gut" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "durchschnittlich" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "schlecht" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "sehr schlecht" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "zu schlecht" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Gesichert durch SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Auf „Ungeprüft“ setzen" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Auf „Geprüft“ setzen" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "In Konferenz" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Gehaltener Anruf" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Anruf beendet." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "Vermittlung läuft" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Vermittlung abgeschlossen." -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Vermittlung fehlgeschlagen." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Fortsetzen" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Halten" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Halten" @@ -749,155 +768,151 @@ msgstr "Senden" msgid "End conference" msgstr "In Konferenz" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Vermittlung" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Dauer" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Bewertung der Verbindungsqualität" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Optionen" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "Video immer starten" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Selbstansicht ein" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Hilfe" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Debug-Fenster anzeigen" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Auf _Aktualisierungen überprüfen" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP-Adresse oder Telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Einen neuen Anruf beginnen" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakte" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Hinzufügen" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Bearbeiten" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Suchen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Kontakte aus einem Verzeichnis hinzufügen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Kontakt hinzufügen" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Letzte Gespräche" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Aktuelle Identität:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Benutzername" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passwort" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internetverbindung:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Automatisch anmelden" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Anmeldeinformationen" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Willkommen !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Alle Teilnehmer" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Angemeldete Teilnehmer" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Glasfaserkabel" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Vorgabe" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1508,7 +1523,7 @@ msgstr "" msgid "Outgoing call" msgstr "Abgehender Anruf" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Bereit" @@ -1564,11 +1579,11 @@ msgstr "Verbunden." msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." @@ -1669,115 +1684,115 @@ msgstr "" "Sie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:" "alice@beispiel.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Anmeldung als %s fehlgeschlagen" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Klingeln bei der Gegenseite." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Klingeln bei der Gegenseite..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Anruf mit %s wird gehalten." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Der von %s entgegengenommene Anruf wird gehalten." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Anruf fortgesetzt." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Anruf wird von %s entgegengenommen." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Inkompatibel, überprüfen Sie die Codecs..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "Anruf wird fortgesetzt." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "Anruf wird von der Gegenseite gehalten." -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "Anruf ist von der Gegenseite aktualisiert worden." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Anruf beendet." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Teilnehmer ist besetzt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Teilnehmer zur Zeit nicht verfügbar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Teilnehmer möchte nicht gestört werden." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Anruf abgewiesen" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Keine Antwort." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokollfehler" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Umgeleitet" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "Inkompatible Medienparameter." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Anruf fehlgeschlagen." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrierung auf %s erfolgreich." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Abmeldung von %s ist erfolgt." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Zeitüberschreitung bei der Antwort" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrierung auf %s fehlgeschlagen: %s" @@ -1787,7 +1802,7 @@ msgstr "Registrierung auf %s fehlgeschlagen: %s" msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/es.po b/po/es.po index 9bdca11b7..90fa0f926 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-12-06 15:54+0100\n" "Last-Translator: BERAUDO Guillaume \n" "Language-Team: es \n" @@ -15,58 +15,80 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Llamar a %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Enviar mensaje a %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "En llamada " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "n/a" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "abortada" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "perdida" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Rechazar" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i minuto" msgstr[1] "%i minutos" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i segundo" msgstr[1] "%i segundos" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tCalidad: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conferencia" @@ -79,32 +101,36 @@ msgstr "Yo" msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "¡Contacto SIP no válido!" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "ruta a un fichero donde escribir logs." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Iniciar sólo en la barra de tareas, no mostrar la interfaz principal." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "dirección a la que llamar inmediatamente" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "si está activo, responder a llamadas entrantes automáticamente" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -112,12 +138,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Llamar con %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -130,7 +156,7 @@ msgstr "" "contactos?\n" "Si responde no, esta persona será bloqueada temporalmente." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -139,63 +165,63 @@ msgstr "" "Por favor, introduzca la contraseña para el usuario %s\n" " en el dominio %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Error en la llamada." -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Llamada terminada" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Contestar" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "Rechazar" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Llamada en pausa" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Puertos" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Enlace a la Web" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - un video-teléfono a través de Internet" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Opción predeterminada)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Somos transferidos a %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -203,63 +229,54 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Un video-teléfono SIP gratuito" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Añadir a la agenda" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "Estado de Presencia" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nombre" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Llamada" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Buscar en el directorio %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "¡Contacto SIP no válido!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Llamar a %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Enviar mensaje a %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Editar contacto '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Eliminar contacto '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Añadir nuevo contacto desde el directorio %s" @@ -360,21 +377,25 @@ msgstr "Noruego" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Deberá reiniciar linphone para aplicar la nueva selección de lenguaje" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "Ninguno." -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -632,119 +653,119 @@ msgstr "" msgid "%.3f seconds" msgstr "%i segundo" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr " Llamando..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "buena" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "media" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "mala" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "muy mala" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "demasiado mala" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "no disponible" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Cifrada con SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Cifrada con ZRTP - [token de autenticación: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Set sin verificar" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Set verificado" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "En conferencia" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Llamada en pausa" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Llamada finalizada." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Transferir" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Transferir" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Reanudar" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pausar" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pausar" @@ -769,172 +790,168 @@ msgstr "Enviar" msgid "End conference" msgstr "En conferencia" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etiqueta" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Transferir" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Duración" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Calidad de la llamada" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Opciones" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Activar vista propia" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Ayuda" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Mostrar ventana de depuración" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Pagina_de_Inicio" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Buscar_Actualizaciones" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Dirección SIP o número de teléfono" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Iniciar nueva llamada" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Contactos" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Añadir" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editar" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Buscar" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Añadir contactos desde un directorio" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Añadir contacto" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Llamadas recientes " -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Mi identidad actual:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Nombre de usuario" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Contraseña:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Conexión a Internet" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Iniciar sesión automáticamente" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Datos de inicio de sesión" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "¡Bienvenido/a!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Todos los usuarios" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "Usuarios conectados" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Canal de Fibra" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Predeterminado" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1586,7 +1603,7 @@ msgstr "" msgid "Outgoing call" msgstr "Llamada saliente" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Preparado" @@ -1648,11 +1665,11 @@ msgstr "Conectado." msgid "Call aborted" msgstr "Llamada abortada" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "No se pudo pausar la llamada" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Pausando la llamada actual..." @@ -1757,121 +1774,121 @@ msgstr "" "Debe ser del tipo sip:username@proxydomain, como por ejemplo sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "No se pudo iniciar sesión como %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Medios iniciales." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "La llamada con %s está puesta en pausa." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Llamada respondida por %s - en espera." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Llamada reanudada." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "Llamada respondida por %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Nos han reanudado..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "La llamada ha sido actualizada por el destinatario..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "Llamada finalizada." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "El usuario está ocupado." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "El usuario no está disponible temporalmente." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "El usuario no quiere que le molesten." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Llamada rechazada." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "No hay respuesta." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Error de protocolo." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Redigirida" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "La llamada ha fallado." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Se ha registrado con éxito en %s." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Cancelación de registro en %s completada." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "timeout sin respuesta" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "El registro en %s ha fallado." @@ -1881,13 +1898,16 @@ msgstr "El registro en %s ha fallado." msgid "Authentication token is %s" msgstr "El tóken de autenticación es%s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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." +#~ msgid "label" +#~ msgstr "etiqueta" + #~ msgid "Chat with %s" #~ msgstr "Conversación con %s" diff --git a/po/fr.po b/po/fr.po index 322a2ff4c..d4cb84c52 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" -"PO-Revision-Date: 2002-12-06 17:33+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"PO-Revision-Date: 2013-04-08 16:46+0100\n" "Last-Translator: Simon Morlat \n" "Language-Team: french \n" "Language: \n" @@ -15,51 +15,71 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Appeler %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Chatter avec %s" + +#: ../gtk/calllogs.c:223 +#, c-format +msgid "Recent calls (%i)" +msgstr "Appels récents (%i)" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "inconnu" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Abandonné" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Manqué" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Refusé" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conférence" @@ -72,31 +92,35 @@ msgstr "Moi" msgid "Couldn't find pixmap file: %s" msgstr "Icone non trouvée: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Contact sip invalide !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "affiche des informations de debogage" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Démarrer linphone avec la vidéo désactivée." -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Démarre iconifié, sans interface principale." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "addresse à appeler maintenant" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -104,12 +128,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Appel avec %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -123,7 +147,7 @@ msgstr "" "Si vous répondez non, cette personne sera mise temporairement sur liste " "noire." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -132,59 +156,59 @@ msgstr "" "Entrez le mot de passe pour %s\n" " sur le domaine %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Appel en pause" -#: ../gtk/main.c:1137 -#, fuzzy, c-format +#: ../gtk/main.c:1142 +#, c-format msgid "by %s" -msgstr "Ports utilisés" +msgstr "" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Lien site web" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - un téléphone video pour l'internet" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -192,60 +216,51 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Un visiophone libre" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Ajouter au carnet d'adresse" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Appeler" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Rechercher dans l'annuaire de %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Contact sip invalide !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Appeler %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Chatter avec %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Editer le contact '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Supprimer le contact '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Supprimer l'historique de chat de '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Ajouter un contact depuis l'annuaire %s" @@ -346,22 +361,26 @@ msgstr "Norvégien" msgid "Hebrew" msgstr "Hébreu" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "Serbe" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" -msgstr "" +msgstr "Aucun" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -382,7 +401,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..." @@ -408,22 +427,24 @@ msgid "" "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:43 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Créer un compte sur linphone.org" #: ../gtk/setupwizard.c:44 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:45 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:85 msgid "Enter your linphone.org username" -msgstr "" +msgstr "Entrez votre identifiant linphone.org" #: ../gtk/setupwizard.c:92 msgid "Username:" @@ -447,7 +468,7 @@ msgstr "Mot de passe*" #: ../gtk/setupwizard.c:125 msgid "Domain*" -msgstr "" +msgstr "Domaine*" #: ../gtk/setupwizard.c:126 msgid "Proxy" @@ -455,7 +476,7 @@ msgstr "" #: ../gtk/setupwizard.c:298 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Champs requis" #: ../gtk/setupwizard.c:299 msgid "Username: (*)" @@ -471,7 +492,7 @@ msgstr "" #: ../gtk/setupwizard.c:305 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Confirmez votre mot de passe: (*)" #: ../gtk/setupwizard.c:369 msgid "" @@ -499,9 +520,8 @@ msgid "Account setup assistant" msgstr "" #: ../gtk/setupwizard.c:575 -#, fuzzy msgid "Configure your account (step 1/1)" -msgstr "Configuer un compte SIP" +msgstr "Configurez votre compte" #: ../gtk/setupwizard.c:580 msgid "Enter your sip username (step 1/1)" @@ -566,7 +586,7 @@ msgstr "" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" -msgstr "" +msgstr "uPnP non activé" #: ../gtk/incall_view.c:240 #, fuzzy @@ -603,112 +623,112 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" -msgstr "" +msgstr "Raccrocher" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "bon" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "moyen" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "faible" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "très faible" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "indisponible" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Sécurisé par SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Sécurisé par ZRTP- [jeton: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "En conférence" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Appel en cours" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Appel en attente" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Appel terminé." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" -msgstr "" +msgstr "Transfert en cours" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Transfert terminé" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Transfert échoué" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pause" @@ -730,157 +750,153 @@ msgstr "Envoyer" msgid "End conference" msgstr "Fin de conférence" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "Vidéo" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Transfert" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Appel en cours" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Durée" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Qualité de l'appel" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" -msgstr "" +msgstr "Toujours démarrer la vidéo" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Se voir" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Aide" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Fenêtre de débogage" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Site web" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Adresse SIP ou numéro" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Démarrer un nouvel appel" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Contacts" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Ajouter" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editer" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Rechercher" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Ajouter un contact depuis l'annuaire" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Ajouter un contact." -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Appels récents" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Mon identité sip:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Nom d'utilisateur" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Mot de passe" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Me connecter automatiquement" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Information de login" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Bienvenue !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Tous" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "En ligne" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Par défaut" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" -msgstr "" +msgstr "Supprimer" #: ../gtk/about.ui.h:1 msgid "About linphone" @@ -935,7 +951,7 @@ msgstr "" #: ../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" @@ -975,7 +991,7 @@ msgstr "" #: ../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:" @@ -999,7 +1015,7 @@ msgstr "Publier la présence" #: ../gtk/sip_account.ui.h:11 msgid "Configure a SIP account" -msgstr "Configuer un compte SIP" +msgstr "Configurer un compte SIP" #: ../gtk/parameters.ui.h:1 msgid "default soundcard" @@ -1023,7 +1039,7 @@ msgstr "Codecs audio" #: ../gtk/parameters.ui.h:6 msgid "Video codecs" -msgstr "Codecs video" +msgstr "Codecs vidéo" #: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 msgid "C" @@ -1162,11 +1178,11 @@ msgstr "Son" #: ../gtk/parameters.ui.h:40 msgid "Video input device:" -msgstr "Périphérique d'entrée video" +msgstr "Périphérique d'entrée vidéo" #: ../gtk/parameters.ui.h:41 msgid "Prefered video resolution:" -msgstr "Résolution video préférée:" +msgstr "Résolution de vidéo préférée:" #: ../gtk/parameters.ui.h:42 msgid "Video" @@ -1179,8 +1195,8 @@ msgstr "Paramètres multimedia" #: ../gtk/parameters.ui.h:44 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" +"Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de " +"compte SIP" #: ../gtk/parameters.ui.h:45 msgid "Your display name (eg: John Doe):" @@ -1192,7 +1208,7 @@ msgstr "Votre nom d'utilisateur:" #: ../gtk/parameters.ui.h:47 msgid "Your resulting SIP address:" -msgstr "Votre addresse SIP:" +msgstr "Votre adresse SIP:" #: ../gtk/parameters.ui.h:48 msgid "Default identity" @@ -1480,7 +1496,7 @@ msgstr "" msgid "Outgoing call" msgstr "Appel sortant" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Prêt." @@ -1535,11 +1551,11 @@ msgstr "En ligne." msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." @@ -1641,116 +1657,116 @@ msgstr "" "Elle doit être de la forme sip:username@domain, comme par example sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Echec de la connexion en tant que %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Sonnerie distante." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Sonnerie distante..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." -msgstr "Prise d'appel anticipée" +msgstr "Prise d'appel anticipée." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "%s est maintenant en attente." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Appel répondu par %s - en attente" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Appel répondu par %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Reprise..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "L'appel a été repris par le correspondant." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Appel terminé." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Occupé..." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "L'usager est temporairement indisponible." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "L'usager ne souhaite pas être dérangé" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Appel décliné." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Pas de réponse." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Erreur de protocole" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Redirection" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "L'appel a échoué." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Enregistrement sur %s effectué." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Désenregistrement sur %s effectué." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Pas de réponse" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Echec de l'enregistrement sur %s: %s" @@ -1760,7 +1776,7 @@ msgstr "Echec de l'enregistrement sur %s: %s" msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/he.po b/po/he.po index 7439d2651..b8b2895b8 100644 --- a/po/he.po +++ b/po/he.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.5.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-12-27 10:14+0200\n" "Last-Translator: Isratine Citizen \n" "Language-Team: Rahut \n" @@ -19,59 +19,82 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.5.4\n" -#: ../gtk/calllogs.c:82 +# צור קשר עם +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "התקשר אל %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "שלח טקסט אל %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "בשיחה כעת" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "לא זמין (n/a)" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "ננטשה" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "הוחמצה" # דחיה -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "לדחות" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "דקה %i" msgstr[1] "%i דקות" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "שניה %i" msgstr[1] "%i שניות" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tאיכות: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tאיכות: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tאיכות: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "ועידה" @@ -84,42 +107,47 @@ msgstr "אני" msgid "Couldn't find pixmap file: %s" msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" +# איש־קשר +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "כתובת sip לא תקפה !" + # cli -#: ../gtk/main.c:88 +#: ../gtk/main.c:92 #, fuzzy msgid "log to stdout some debug information while running." msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמן ביצוע." # cli -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 #, fuzzy msgid "path to a file to write logs into." msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" # cli -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 #, fuzzy msgid "Start only in the system tray, do not show the main interface." msgstr "התחל במגש המערכת בלבד, אל תציג את הממשק הראשי." # cli -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 #, fuzzy msgid "address to call right now" msgstr "כתובת להתקשרות ברגע זה" # cli -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 #, fuzzy msgid "if set automatically answer incoming calls" msgstr "באם אפשרות זו נקבעת ענה אוטומטית לקריאות נכנסות" # cli -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 #, fuzzy msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" @@ -128,14 +156,14 @@ msgstr "" "ציין מדור העבודה (אמור להיות מבוסס על ההתקנה, למשל: c:\\Program Files" "\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "התקשרות באמצעות %s" # הקשר שלהם # אם התשובה -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -148,7 +176,7 @@ msgstr "" "שלך ?\n" "היה ותשובתך תהיה לא, אדם זה יהיה מסומן באופן זמני ברשימה השחורה." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -158,64 +186,64 @@ msgstr "" " בתחום %s:" # שיחה -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "שגיאת קריאה" # Conversation ended -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "שיחה הסתיימה" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "לענות" # דחיה -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "לדחות" # Conversation paused -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "שיחה הושהתה" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Ports utilisés" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "קישור אתר רשת" # ‫Linphone - וידאופון במרשתת -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "‫Linphone - וידאופון אינטרנטי" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "‫%s (משתמטת)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "אנחנו מועברים אל %s" # קריאות שמע -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -223,63 +251,52 @@ msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" "לא תהיה ביכולתך לשלוח או לקבל שיחות שמע." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "וידאופון SIP חופשי" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "הוסף אל ספר כתובות" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "מצב נוכחות" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "שם" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "קריאה" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" # a name or a number -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "חיפוש במדור %s" -# איש־קשר -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "כתובת sip לא תקפה !" - -# צור קשר עם -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "התקשר אל %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "שלח טקסט אל %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "ערוך איש קשר '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "מחק איש קשר '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "הוסף איש קשר חדש מן מדור %s" @@ -384,21 +401,25 @@ msgstr "norsk" msgid "Hebrew" msgstr "" +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + # selected הנבחרת -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "ללא" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -659,121 +680,121 @@ msgstr "" msgid "%.3f seconds" msgstr "שניה %i" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "מתקשר כעת..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "‭00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "טובה" # רגילה -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "ממוצעת" # weak חלשה חלושה רפויה רופפת -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "דלה" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "דלה מאוד" # רעה -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "גרועה מדי" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "לא זמינה" # באמצעות -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "מאובטחת על ידי SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" # set or unset verification state of ZRTP SAS. -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "הגדר כלא מאומתת" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "הגדר כמאומתת" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "בשיחת ועידה" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "שיחה מושהית" # שעות %02i דקות %02i שניות %02i # Force LTR time format (hours::minutes::seconds) with LRO chatacter (U+202D) -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "‭%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "שיחה הסתיימה." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "העברה" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "העברה" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "חזרה" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "השהיה" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "השהיה" @@ -798,159 +819,155 @@ msgstr "שיגור" msgid "End conference" msgstr "בשיחת ועידה" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "תוויות" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "העברה" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "משך זמן" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "אומדן איכות שיחה" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_אפשרויות" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "אפשר ראות-עצמית" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_עזרה" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "הצג חלון ניפוי שגיאות" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_עמוד הבית" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "בדיקת _עדכונים" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "אשף חשבון" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "כתובת SIP או מספר טלפון" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "התחלת שיחה חדשה" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "אנשי קשר" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "הוסף" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "ערוך" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "חיפוש" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "הוסף אנשי קשר מן מדור" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "הוספת איש קשר" # קריאות אחרונות -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "שיחות אחרונות" # הזהות הנוכחית שלי -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "זהותי הנוכחית:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "שם משתמש" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "סיסמה" # מרשתת -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "חיבור אינטרנט:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "חבר אותי אוטומטית" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "מידע התחברות" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "ברוך בואך !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "כל המשתמשים" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "משתמשים מקוונים" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "‫ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "ערוץ סיב" # משתמט -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "ברירת מחדל" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1577,7 +1594,7 @@ msgstr "" msgid "Outgoing call" msgstr "קריאה יוצאת" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "מוכן" @@ -1636,11 +1653,11 @@ msgstr "מקושר." msgid "Call aborted" msgstr "קריאה בוטלה" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "לא ניתן להשהות את השיחה" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "משהה כעת שיחה נוכחית..." @@ -1747,40 +1764,40 @@ msgstr "" "זו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" # בשם כ־ -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "לא ניתן להתחבר בזהות %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "צלצול מרוחק." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "צלצול מרוחק..." # A SIP state -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "מדיה מוקדמת." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "שיחה עם %s מושהית." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "קריאה נענתה על ידי %s - בהמתנה." # renewed -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "קריאה חודשה." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "קריאה נענתה על ידי %s." @@ -1788,89 +1805,89 @@ msgstr "קריאה נענתה על ידי %s." # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "חוסר תאימות, נא לבדוק קודקים..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "חזרנו..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" # באופן מרוחק -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "שיחה עודכנה מרחוק..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "קריאה הסתיימה." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "משתמש עסוק כעת." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "משתמש לא זמין זמנית." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "משתמש לא מעוניין שיפריעו לו." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "קריאה סורבה." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "אין תגובה." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "שגיאת פרוטוקול." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "מכוון מחדש" # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 #, fuzzy msgid "Incompatible media parameters." msgstr "חוסר תאימות, נא לבדוק קודקים..." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "קריאה נכשלה." # הרשמה אצל %s הושלמה בהצלחה. -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "רישום אצל %s הושלם בהצלחה." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "אי רישום אצל %s סוים." # Pas de réponse # no response in defined time -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "אין היענות תוך זמן מוגדר" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "רישום אצל %s נכשל: %s" @@ -1881,13 +1898,16 @@ msgid "Authentication token is %s" msgstr "אות האימות הינה %s" # האם כדאי לחקות את הטלפונים הניידים? שיחות של נענו -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "החמצת שיחה %i." msgstr[1] "החמצת %i שיחות." +#~ msgid "label" +#~ msgstr "תוויות" + #~ msgid "by %s" #~ msgstr "מאת %s" diff --git a/po/hu.po b/po/hu.po index 54f7821a5..256e7ffba 100644 --- a/po/hu.po +++ b/po/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2013-03-26 19:00+0100\n" "Last-Translator: Viktor \n" "Language-Team: \n" @@ -17,53 +17,75 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" "Plural-Forms: nplurals=1; plural=1 == 1 ? 0 : 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "%s hívása" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Szöveg küldése a következőnek: %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "vonalban" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "-" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Megszakítva" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Nem fogadott" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Elutasítva" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i perc" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i másodperc" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" -msgstr "" -"%s\t%s\tMinőség: %s\n" -"%s\t%s %s\t" - -#: ../gtk/calllogs.c:108 -#, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\t\n" "%s\t%s" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:323 +#, fuzzy, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" +"%s\t%s\tMinőség: %s\n" +"%s\t%s %s\t" + +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\t\n" +"%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konferencia" @@ -76,31 +98,35 @@ msgstr "én" msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Érvénytelen sip partner !" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "fájl elérési útja, melybe a naplók kerülnek." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "Linphone indítása, videó kikpacsolva. " -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Csak a tálcaikon indítása, ne mutassa a fő ablakot." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Cím azonnali híváshoz" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Bekapcsolva automatikusan válaszol a bejövő hívásokra" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -108,12 +134,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Hívás %s -el" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -126,7 +152,7 @@ msgstr "" "szeretné adni a partnerlistához?\n" "Ha nemmel válaszol, ez a személy átmenetileg tiltólistára kerül." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -135,59 +161,59 @@ msgstr "" "Kérem, adja meg jelszavát a következő felhasználónévhez: %s\n" "tartomány %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Hívás fogadása" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Elutasítás" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Hívás várakoztatva" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, c-format msgid "by %s" msgstr "a következő által: %s" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s szerené elidítani a videót. Elfogadja?" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Internetes oldal" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - internetes videó telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Alapértelmezett)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Át vagyunk irányítva ide: %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -195,60 +221,51 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Hozzáadás címjegyzékhez" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Jelenlét státusz" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Név" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Hivás" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "Csevegés" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Keresés ebben a könyvtárban: %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Érvénytelen sip partner !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "%s hívása" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Szöveg küldése a következőnek: %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Kapcsolatinformációk szerkesztése: '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "'%s' partner törlése" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Új partner hozzáadása ebből a könyvtárból: %s" @@ -349,22 +366,26 @@ msgstr "norvég" msgid "Hebrew" msgstr "héber" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Nincs" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -610,105 +631,105 @@ msgstr "" msgid "%.3f seconds" msgstr "%.3f másodperc" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Befejezés" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Hívás folyamatban..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "jó" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "közepes" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "gyenge" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "nagyon gyenge" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "rossz" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nem elérhető" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "SRTP-vel titkosítva" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Beállítás ellenőrizetlenként" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Beállítás ellenőrzöttként" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "Konferencián" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "vonalban" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Várakoztatott hívás" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Hívás vége." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "Átvitel folyamatban" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Átvitel befejezve." -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Az átvitel sikertelen." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Visszatérés" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Várakoztatás" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" @@ -717,7 +738,7 @@ msgstr "" "Felvétel a következőbe\n" "%s %s" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "(Várakoztatva)" @@ -738,155 +759,151 @@ msgstr "Küld" msgid "End conference" msgstr "Konferencia vége" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "címke" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "Beszélgetés felvétele hangfájlba" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "Videó" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "Elnémítás" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Átvitel" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "vonalban" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Időtartam" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Hívásminőség" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Beállítások" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "Videó indítása mindig" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Saját nézet" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Segítség" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Hibakeresési ablak mutatása" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Honlap" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Frissítések keresése" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Fiók varázsló" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Adja meg a SIP címet vagy a telefonszámot:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Új hívás kezdeményezése" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Partnerek" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Hozzáadás" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Szerkesztés" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Keresés" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Partnerek hozzáadása könyvtárból" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Partner hozzáadása" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Legutóbbi hívások" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Jelenlegi identitásom:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Felhasználónév" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Jelszó" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet kapcsolat:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Jelentkeztessen be automatikusan" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Bejelentkezési információ" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Üdvözöljük !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Minden felhasználó" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Elérhető" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber csatorna" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Alapértelmezett" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "Törlés" @@ -1489,7 +1506,7 @@ msgstr "" msgid "Outgoing call" msgstr "Kimenő hívás" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Kész" @@ -1544,11 +1561,11 @@ msgstr "Kapcsolódva." msgid "Call aborted" msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Jelenlegi hívás várakoztatásának aktiválása..." @@ -1649,115 +1666,115 @@ msgstr "" "Így kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:" "aladar@pelda.hu" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Nem sikerült belépni ezzel: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Távoli csengés." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Távoli csengés..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Korai médiák." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "A hívás a következővel: %s várakoztatva" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "%s fogadta a hívást - várakoztatva." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Hívás visszatért" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "%s válaszolt a hívásra." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 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:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "Visszatértünk." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "Megállítva a másik fél által." -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "A hívás távolról frissítve." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "A hívás befejezve." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "A felhasználó foglalt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "A felhasználó ideiglenesen nem elérhető" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "A felhasználó nem akarja, hogy zavarják." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Hívás elutasítva" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Nincs válasz." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokol hiba." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Átirányítva" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "Nem kompatibilis médiajellemzők." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Nem sikerült a hívás." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "A kiregisztrálás kész a következőn: %s ." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "időtúllépés után nincs válasz" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" @@ -1767,12 +1784,15 @@ msgstr "A regisztáció a %s -n nem sikerült: %s" msgid "Authentication token is %s" msgstr "Hitelesítési jel: %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Van %i nem fogadott hivás." +#~ msgid "label" +#~ msgstr "címke" + #~ msgid "Chat with %s" #~ msgstr "Chat-elés %s -el" diff --git a/po/it.po b/po/it.po index 9e9a1183d..f1c29e8b0 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" "Last-Translator: Matteo Piazza \n" "Language-Team: it \n" @@ -15,54 +15,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Chiamata %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Invia testo a %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "In chiamata con" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "annullato" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "mancante" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Rifiuta" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -78,42 +98,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Contatto SIP non valido" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat con %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -125,128 +149,119 @@ msgstr "" "veda il tuo stato o aggiungerlo alla tua lista dei contatti Se rispondi no " "questo utente sarà momentaneamente bloccato." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, 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:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Cronologia" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Chiamata terminata" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Rifiuta" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "annullato" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porte" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Presenza" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Chiamata %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Cerca contatti nella directory %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Contatto SIP non valido" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Chiamata %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Invia testo a %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Modifica contatto %s" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Elimina contatto %s" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Aggiungi nuovo contatto dalla directory %s" @@ -347,20 +362,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -612,117 +631,117 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Linguaggio" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "In chiamata con" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Termina chiamata" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Chiamata terminata." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Chiamata rifiutata" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -744,167 +763,163 @@ msgstr "Invia" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etichetta" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "In chiamata" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Durata" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Self-view abilitato" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone debug window" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Configuratore di account" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Indirizzo sip o numero." -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "In connessione" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Aggiungi" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Edita" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Trovato %i contatto" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "In chiamata" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Identità corrente" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Username" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Password" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Connessione Internet:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Login Automatico" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Credenziali di accesso" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Benvenuto !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "Tutti gli utenti\n" "Utenti Online" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fibra Ottica" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Default" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1521,7 +1536,7 @@ msgstr "" msgid "Outgoing call" msgstr "Chiamata in uscita" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Pronto" @@ -1580,12 +1595,12 @@ msgstr "Connessione" msgid "Call aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Mostra chiamata corrente" @@ -1686,118 +1701,118 @@ msgstr "" "L'identità sip utilizza è invalida.\n" "Dovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "impossibile login come %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat con %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Chiamata terminata" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Chiamata terminata." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Utente occupato" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Utente non disponibile" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "L'utente non vuole essere disturbato" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 #, fuzzy msgid "No response." msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Rediretto verso %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrazione su %s attiva" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Unregistrazione su %s" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrazione su %s fallita: %s" @@ -1807,13 +1822,16 @@ msgstr "Registrazione su %s fallita: %s" msgid "Authentication token is %s" msgstr "Linphone - Autenticazione richiesta" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" msgstr[1] "" +#~ msgid "label" +#~ msgstr "etichetta" + #~ msgid "Chat with %s" #~ msgstr "Chat con %s" diff --git a/po/ja.po b/po/ja.po index e95879bb8..668018fd1 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2003-01-21 00:05+9000\n" "Last-Translator: YAMAGUCHI YOSHIYA \n" "Language-Team: \n" @@ -17,53 +17,73 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "接続中" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "通話はキャンセルされました。" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "ライン入力" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -76,42 +96,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -120,132 +144,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "通話は拒否されました。" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "ライン入力" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "接続中" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "電話帳" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "状態" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名前" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "通話はキャンセルされました。" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(接続するための情報がありません!)" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -346,21 +361,25 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "ありません。" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -606,118 +625,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "接続中" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "接続中" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "接続中" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "通話は拒否されました。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -740,170 +759,166 @@ msgstr "サウンド" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "情報" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "使用する" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "レジストラサーバーのSIPアドレス" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "接続中" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "追加する" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "コーデックの情報" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "(接続するための情報がありません!)" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "接続中" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "個人情報" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "ユーザーマニュアル" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "パスワード" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "コーデックの情報" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "接続中" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "ライン入力" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "個人情報" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1527,7 +1542,7 @@ msgstr "" msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "準備完了。" @@ -1589,11 +1604,11 @@ msgstr "接続しました。" msgid "Call aborted" msgstr "通話はキャンセルされました。" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1693,121 +1708,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "登録中……" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "登録中……" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "電話をかける\n" "電話に出る" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "ユーザーはビジーです" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "ユーザーは、今出られません。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "ユーザーは手が離せないようです。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "通話はキャンセルされました。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "登録しました。" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "登録しました。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "登録しました。" @@ -1817,7 +1832,7 @@ msgstr "登録しました。" msgid "Authentication token is %s" msgstr "コーデックの情報" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/nb_NO.po b/po/nb_NO.po index c1500d304..8b7f20c28 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-04-05 01:56+0200\n" "Last-Translator: Øyvind Sæther \n" "Language-Team: Norwegian Bokmål \n" @@ -17,54 +17,74 @@ msgstr "" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Ring %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Send tekst til %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "I samtale med" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "avbrutt" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "ubesvart" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Avvis" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -78,31 +98,35 @@ msgstr "Skru mikrofonen av" msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Ugyldig SIP kontakt !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "skriv logg-informasjon under kjøring" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Start skjult i systemkurven, ikke vis programbildet." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "address som skal ringes nå" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "besvarer innkommende samtaler automatisk om valgt" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,12 +134,12 @@ msgstr "" "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:" "\\Programfiler\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Ring med %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -128,7 +152,7 @@ msgstr "" "din kontaktliste?\n" "Hvis du svarer nei vil personen bli svartelyst midlertidig." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -137,61 +161,61 @@ msgstr "" "Skriv inn ditt passord for brukernavn %s\n" " på domene %s:i>:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Samtalehistorikk" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Svarer" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avvis" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Samtale avbrutt" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porter" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Peker til nettsted" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Standard)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Vi er overført til %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -199,61 +223,52 @@ msgstr "" "Klarte ikke å finne noe lydkort på denne datamaskinen.\n" "Du vil ikke kunne sende eller motta lydsamtaler." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Tilstedestatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Navn" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Ring %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Søk i %s katalogen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Ugyldig SIP kontakt !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Ring %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Send tekst til %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Rediger kontakt '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Slett kontakt '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Legg til kontakt fra %s katalogen" @@ -354,20 +369,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -620,114 +639,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "I samtale med" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Pauset samtale" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Samtale avsluttet." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Overfører" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Overfører" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Fortsett" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pause" @@ -750,157 +769,153 @@ msgstr "Send" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Overfører" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "I samtale" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Varighet" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Alternativer" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Vis video av deg selv" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Hjelp" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Vis avlusningsvindu" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "H_jemmeside" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Sjekk _Oppdateringer" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Sip adresse eller telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Start en ny samtale" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakter" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Legg til" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Rediger" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Søk" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Legg til kontakter fra katalogen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Legg til kontakt" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "I samtale" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Min nåværende identitet:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Brukernavn" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passord" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet forbindelse:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Logg meg på automatisk" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Innlogginsinformasjon" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Velkommen!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Alle brukere" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Tilkoblede brukere" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber Kanal" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Standard" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1514,7 +1529,7 @@ msgstr "" msgid "Outgoing call" msgstr "Utgående samtale" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Klar" @@ -1570,11 +1585,11 @@ msgstr "Tilkoblet" msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" @@ -1676,116 +1691,116 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Ikke ikke logge inn som %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Tidlig media" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Samtalen med %s er pauset." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Samtale besvart av %s - på vent." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Samtale gjenopptatt." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Samtale besvart av %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Vi har blitt gjenopptatt..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Samtale avsluttet." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Brukeren er opptatt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Brukeren er midlertidig ikke tilgjengelig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Brukeren vil ikke bli forstyrret." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Samtale avvist." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Ikke noe svar." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokollfeil." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Omdirigert" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Samtale feilet." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lykkes." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lykkes." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "ingen svar innen angitt tid" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislykkes: %s" @@ -1795,13 +1810,16 @@ msgstr "Registrering hos %s mislykkes: %s" msgid "Authentication token is %s" msgstr "Autorisering kreves" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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 "label" +#~ msgstr "etikett" + #~ msgid "Keypad" #~ msgstr "Tastatur" diff --git a/po/nl.po b/po/nl.po index 926bd7bb6..8cfe7febd 100644 --- a/po/nl.po +++ b/po/nl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: nl\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2007-09-05 10:40+0200\n" "Last-Translator: Hendrik-Jan Heins \n" "Language-Team: Nederlands \n" @@ -19,54 +19,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, fuzzy, c-format +msgid "Call %s" +msgstr "Oproepgeschiedenis" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Contactlijst" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "afgebroken" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "gemist" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "lijn" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -79,42 +99,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat met %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -123,131 +147,122 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Linphone - Oproepgeschiedenis" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Oproep beeindigd" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "lijn" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "afgebroken" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Contactlijst" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Een Vrije SIP video-telefoon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Adresboek" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Aanwezigheidsstatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Naam" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Oproepgeschiedenis" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Chat box" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Oproepgeschiedenis" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Bewerk contactgegevens" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Geen" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -609,118 +628,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Contactlijst" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Oproep beeindigd" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -743,173 +762,169 @@ msgstr "Geluid" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Inkomende oproep" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informatie" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Video aan" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "_Help" msgstr "Help" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Geef het SIP adres of telefoonnummer in" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Verbinden" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Adres" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Bewerken" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Contact informatie" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Bewerk contactgegevens" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Inkomende oproep" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "SIP-identiteit:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "gebruikersnaam:" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "wachtwoord:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Automatically log me in" msgstr "Automatisch een geldige hostnaam raden" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Contact informatie" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Contactlijst" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "Aanwezig" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "SIP-identiteit:" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1543,7 +1558,7 @@ msgstr "" msgid "Outgoing call" msgstr "Uitgaande oproep" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Gereed." @@ -1602,12 +1617,12 @@ msgstr "Verbonden." msgid "Call aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Kon niet oproepen" @@ -1709,121 +1724,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat met %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Oproep beeindigd" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Oproepen of\n" "beantwoorden" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Oproep beeindigd." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Gebruiker is bezet." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Gebruiker is tijdelijk niet beschikbaar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "De gebruiker wenst niet gestoord te worden." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Oproep geweigerd." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Doorgeschakeld naar %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Oproep geannuleerd." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registratie op %s mislukt (time-out)." @@ -1833,7 +1848,7 @@ msgstr "Registratie op %s mislukt (time-out)." msgid "Authentication token is %s" msgstr "Authorisatie gegevens" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pl.po b/po/pl.po index 7999a657d..4512b7230 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2003-08-22 12:50+0200\n" "Last-Translator: Robert Nasiadek \n" "Language-Team: Polski \n" @@ -15,53 +15,73 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Dzwonie do " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "Połączenie odwołane." -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "linia" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -74,42 +94,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -118,132 +142,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Rozmowa odrzucona." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linia" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Dzwonie do " -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Książka adresowa" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "Obecność" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nazwa" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Połączenie odwołane." -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -344,21 +359,25 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "Brak." -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -604,118 +623,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Dzwonie do " -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Rozmowa odrzucona." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -738,171 +757,167 @@ msgstr "Dźwięk" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informacja" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Włączone" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Adres serwera rejestracji sip" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Adres" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Informacje o kodeku" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Tożsamość" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Podręcznik" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Twoje hasło:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Informacje o kodeku" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "linia" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Tożsamość" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1526,7 +1541,7 @@ msgstr "" msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Gotowy." @@ -1586,11 +1601,11 @@ msgstr "Połączony" msgid "Call aborted" msgstr "Połączenie odwołane." -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1690,121 +1705,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Zadzwoń lub\n" "Odpowiedz" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Osoba jest zajęta." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Osoba jest tymczasowo niedostępna." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Osoba nie chce, aby jej przeszkadzać." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Połączenie odwołane." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Rejestracja powiodła się." @@ -1814,7 +1829,7 @@ msgstr "Rejestracja powiodła się." msgid "Authentication token is %s" msgstr "Informacje o kodeku" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pt_BR.po b/po/pt_BR.po index 9cd72ea90..821ba910f 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-1.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2006-07-11 23:30+0200\n" "Last-Translator: Rafael Caesar Lenzi \n" "Language-Team: pt_BR \n" @@ -17,54 +17,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, fuzzy, c-format +msgid "Call %s" +msgstr "Histórico de chamadas" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Contatando " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "Abortado" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "Perdido" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "linha" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,42 +97,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Bate-papo com %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -121,132 +145,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Linphone - Histórico de chamadas" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Chamada cancelada." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linha" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Abortado" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Contatando " -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Catálogo de endereços" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Status de presença" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Histórico de chamadas" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Sala de bate-papo" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Histórico de chamadas" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Edicar informação de contato" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Nenhum" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -608,118 +627,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Contatando " -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Contatando " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Contatando " -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Chamada cancelada." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -742,171 +761,167 @@ msgstr "Som" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Camadas recebidas" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informações" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Ativado" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Contatando " -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Endereço" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editar" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Informação de contato" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Edicar informação de contato" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Camadas recebidas" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Identificação SIP:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Usuário" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Senha:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Automatically log me in" msgstr "Adquirir automaticamente um nome de servidor válido." -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Informação de contato" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Contatando " -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "linha" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Identificação SIP:" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1535,7 +1550,7 @@ msgstr "" msgid "Outgoing call" msgstr "Chamadas efetuadas" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Pronto." @@ -1594,11 +1609,11 @@ msgstr "Conectado." msgid "Call aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1688,121 +1703,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Bate-papo com %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Chamada cancelada." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Ligar ou\n" "atender" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Usuário está ocupado." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Usuário está temporáriamente indisponível." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Redirecionado para %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Histórico de chamadas" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registro falhou (tempo esgotado)." @@ -1812,7 +1827,7 @@ msgstr "Registro falhou (tempo esgotado)." msgid "Authentication token is %s" msgstr "Informações de autenticação" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/ru.po b/po/ru.po index a7fd4a832..66419e69a 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2010-01-22 18:43+0300\n" "Last-Translator: Maxim Prokopyev \n" "Language-Team: Russian \n" @@ -17,26 +17,41 @@ msgstr "" "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:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Набрать %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Послать текст к %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Соединен с" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "отмененный" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "пропущенный" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Отклонить" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -44,7 +59,7 @@ msgstr[0] "%i минута" msgstr[1] "%i минуты" msgstr[2] "%i минут" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -52,25 +67,32 @@ msgstr[0] "%i секунда" msgstr[1] "%i секунды" msgstr[2] "%i секунд" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tКачество: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Конференция" @@ -83,33 +105,37 @@ msgstr "Я" msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Неверный sip-контакт!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" "Вывод некоторой отладочной информации на устройство стандартного вывода во " "время работы" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "путь к файлу для записи журнала работы." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Запускать только в системном лотке, не показывая главное окно" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "адрес для звонка" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "автоматически принимать входящие вызовы, если включено" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -117,12 +143,12 @@ msgstr "" "Укажите рабочий каталог (должен содержать установленные файлы приложения, " "например: c:\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Чат с %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -135,7 +161,7 @@ msgstr "" "его(её) в свой контактный лист?\n" "Если вы ответите Нет, этот человек будет временно заблокирован." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -144,59 +170,59 @@ msgstr "" "Пожалуйста, введите пароль для пользователя %s\n" " в домене %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Ошибка вызова" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Разговор окончен" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Ответить" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Отклонить" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Вызов приостановлен" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Порты" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Ссылка на сайт" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - видео-телефон для интернета" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (По умолчанию)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Мы переведены на %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -204,61 +230,52 @@ msgstr "" "На этом компьютере не обнаружено ни одной звуковой карты.\n" "Вы не сможете совершать или принимать аудио-вызовы." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Свободный SIP видео-телефон" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Добавить в адресную книгу" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Статус присутствия" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Имя" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Вызов" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Комната чата" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Поиск в директории %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Неверный sip-контакт!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Набрать %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Послать текст к %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Редактировать контакт '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Удалить контакт '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Добавить новый контакт из директории '%s'" @@ -359,22 +376,26 @@ msgstr "Норвежский" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Вы должны перезапустить Linphone для того, чтобы языковые настройки вступили " "в силу." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Нет" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -627,114 +648,114 @@ msgstr "" msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Вызов..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "хорошее" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "среднее" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "плохое" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "очень плохое" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "слишком плохое" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Защищено SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Защищено ZRTP - [токен: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Не проверен" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверен" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "В конференции" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Соединен с" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Приостановленный вызов" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Звонок закончен." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Перевести" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Перевести" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Продолжить" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Пауза" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Пауза" @@ -757,155 +778,151 @@ msgstr "Отправить" msgid "End conference" msgstr "В конференции" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "метка" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Перевести" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Вызов" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Продолжительность" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Уровень качества звонка" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Настройки" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Включить своё видео" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Помощь" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Показать окно отладки" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Домашняя страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Проверить _Обновления" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP-адрес или номер телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Совершить новый вызов" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Контакты" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Добавить" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Редактировать" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Поиск" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Добавить контакты из директории" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Добавить контакт" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Недавние вызовы" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Мой текущий идентификатор:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Имя пользователя" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Пароль" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Интернет-соединение:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Входить автоматически" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Информация для входа" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Добро пожаловать!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Все пользователи" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Пользователи в сети" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Оптоволокно" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "По умолчанию" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1522,7 +1539,7 @@ msgstr "" msgid "Outgoing call" msgstr "Исходящий звонок" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Готов" @@ -1578,11 +1595,11 @@ msgstr "Соединён." msgid "Call aborted" msgstr "Вызов отменён" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Не удалось приостановить вызов" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Приостановление текущего вызова..." @@ -1685,118 +1702,118 @@ msgstr "" "Они должны выглядеть как sip:username@proxydomain, например such as sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Невозможно зайти как %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Абонент вызывается." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Абонент вызывается..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Гудки." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Вызов %s приостановлен." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Вызов отвечен %s - в ожидании." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Разговор продолжен." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Вызов отвечен %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Наш вызов продолжен..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Вызов обновлён вызываемым абонентом..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Звонок прерван." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Пользователь занят." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Пользователь временно недоступен." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Абонент не хочет отвечать." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Звонок отклонён." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Нет ответа." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Ошибка протокола." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Переадресован" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 #, fuzzy msgid "Incompatible media parameters." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Не удалось совершить вызов." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Регистрация на %s прошла успешно." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Отмена регистрации на %s завершена." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "время ожидания истекло" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Регистрация на %s не удалась: %s" @@ -1806,7 +1823,7 @@ msgstr "Регистрация на %s не удалась: %s" msgid "Authentication token is %s" msgstr "Аутентификационный токен: %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1814,6 +1831,9 @@ msgstr[0] "У вас пропущен %i звонок." msgstr[1] "У вас пропущено %i звонка." msgstr[2] "У вас пропущено %i звонков." +#~ msgid "label" +#~ msgstr "метка" + #~ msgid "by %s" #~ msgstr "со стороны: %s" diff --git a/po/sr.po b/po/sr.po index 4a465ec8e..814b4d050 100644 --- a/po/sr.po +++ b/po/sr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2013-02-11 19:03+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" @@ -16,26 +16,41 @@ msgstr "" "Plural-Forms: nplurals=4; plural=n==1? 3 : 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:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Позови „%s“" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Пошаљи текст за %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "У позиву" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "прекинути" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "пропуштени" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Одбиј" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -44,7 +59,7 @@ msgstr[1] "%i минута" msgstr[2] "%i минута" msgstr[3] "Један минут" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -53,25 +68,32 @@ msgstr[1] "%i секунде" msgstr[2] "%i секунде" msgstr[3] "Једна секунда" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tКвалитет: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Конференција" @@ -84,31 +106,35 @@ msgstr "Ја" msgid "Couldn't find pixmap file: %s" msgstr "Не могу да пронађем датотеку сличице: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Неисправан сип контакт !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "бележи у стандардни излаз неке податке за уклањање грешака док ради." -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "путања до датотеке за уписивање бележака." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "адреса за позивање управо сада" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "ако је подешено сам ће се јављати на долазне позиве" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -116,12 +142,12 @@ msgstr "" "Наводи радни директоријум (треба да буде основа инсталације, нпр: c:" "\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Позив са корисником %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -134,7 +160,7 @@ msgstr "" "на ваш списак пријатеља ?\n" "Ако одговорите са не, ова особа ће привремено бити стављена на црни списак." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -143,59 +169,59 @@ msgstr "" "Унесите вашу лозинку за корисничко име %s\n" " на домену %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Грешка позива" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Позив је завршен" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Јави се" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Одбиј" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Позив је заустављен" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Кодеци" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Веза веб сајта" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Линфон — интернет телефон са снимком" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (основно)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Преселили смо се на %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -203,60 +229,51 @@ msgstr "" "Ниједна звучна картица није откривен ана овом рачунару.\n" "Нећете бити у могућности да шаљете или да примате звучне позиве." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Слободан СИП телефон са снимком" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Додајте у адресар" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Стање присуства" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Име" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Позови" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Тражи у директоријуму „%s“" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Неисправан сип контакт !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Позови „%s“" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Пошаљи текст за %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Уредите контакт „%s“" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Обришите контакт „%s“" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Додајте нови контакт из директоријума „%s“" @@ -357,21 +374,25 @@ msgstr "Норвешки" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Трба поново да покренете линфон да би нови изабрани језик ступио на снагу." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Ништа" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "СРТП" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ЗРТП" @@ -626,114 +647,114 @@ msgstr "" msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Позивам..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "добро" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "просечно" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "оскудно" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "јадно" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "много лоше" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Осигурано СРТП-ом" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Непроверено подешавање" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверено подешавање" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "На конференцији" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "У позиву" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Заустављен позив" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Позив је завршен." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Пребаци" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Пребаци" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Настави" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Застани" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Застани" @@ -756,156 +777,152 @@ msgstr "Пошаљи" msgid "End conference" msgstr "На конференцији" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "натпис" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Пребаци" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Долазни позив" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Трајање" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Оцена квалитета позива" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Могућности" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Укључи самовиђење" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "По_моћ" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Прикажи прозорче прочишћавања" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Матична страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Провери _ажурирања" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "СИП адреса или број телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Започните нови позив" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Пријатељи" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Додај" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Уреди" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Тражи" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Додај пријатеље из директоријума" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Додај пријатеља" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Скорашњи позиви" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Мој тренутни идентитет:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Корисничко име" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Лозинка" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Интернет веза:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Сам ме пријави" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Подаци пријављивања" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Добродошли !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Сви корисници" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Корисницима на мрежи" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "АДСЛ" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Оптички канал" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Основно" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1517,7 +1534,7 @@ msgstr "" msgid "Outgoing call" msgstr "Одлазни позив" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Спреман" @@ -1573,11 +1590,11 @@ msgstr "Повезан сам." msgid "Call aborted" msgstr "Позив је прекинут" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Не могу да зауставим позив" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Заустављам тренутни позив..." @@ -1678,116 +1695,116 @@ msgstr "" "Треба да изгледа као „sip:корисник@домен-посредника, као што је „sip:" "alice@example.net“" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Не могу да се пријавим као %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Удаљено звоњење." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Удаљено звоњење..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Ранији медиј." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Позив са „%s“ је заустављен." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Позив на који је одговорио „%s“ — на чекању." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Позив је настављен." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "На позив је одговорио „%s“." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Позив нам је настављен..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Позив је ажуриран удаљеним..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Позив је завршен." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Корисник је заузет." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Корисник је привремено недоступан." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Корисник не жели да буде узнемираван." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Позив је одбијен." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Нема одговора." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Грешка у протоколу." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Преусмерен" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Позив није успео." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Уписивање на „%s“ је успело." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Исписивање са „%s“ је обављено." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "нема ограничења одговора" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Уписивање на „%s“ није успело: %s" @@ -1797,7 +1814,7 @@ msgstr "Уписивање на „%s“ није успело: %s" msgid "Authentication token is %s" msgstr "Симбол потврђивања идентитета је „%s“" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1806,6 +1823,9 @@ msgstr[1] "Пропустили сте %i позива." msgstr[2] "Пропустили сте %i позива." msgstr[3] "Пропустили сте један позив." +#~ msgid "label" +#~ msgstr "натпис" + #~ msgid "Chat with %s" #~ msgstr "Ћаскајте са „%s“" diff --git a/po/sv.po b/po/sv.po index 0b2882efc..4f7ec762c 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2009-02-17 15:22+0100\n" "Last-Translator: Emmanuel Frécon \n" "Language-Team: SWEDISH \n" @@ -16,54 +16,74 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Ringer %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Skicka text till %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "I samtal med" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "avbrytade" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "missade" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Avböj" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,31 +97,35 @@ msgstr "Mikrofon av" msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "ogiltig SIP kontakt!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "skriv loggning information under körning" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Starta ikonifierat, visa inte huvudfönstret" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Samtalsmottagare" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Om på, besvara automatisk alla inkommande samtal" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -109,12 +133,12 @@ msgstr "" "Välj en arbetskatalog som ska vara basen för installationen, såsom C:" "\\Program\\Linphone" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Samtal med %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -127,7 +151,7 @@ msgstr "" "henne till din kontaktlista?\n" "Om du svarar nej, personen kommer att vara bannlyst." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -136,121 +160,112 @@ msgstr "" "Mata in ditt lösenord för användaren %s\n" "vid domänen %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Samtalshistorik" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avböj" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "avbrytade" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Portar" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Webbsajt" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Närvarostatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Namn" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Ringer %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Sök i %s katalogen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "ogiltig SIP kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Ringer %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Skicka text till %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Ändra kontakt '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Ta bort kontakt '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Lägg till kontakt ifrån %s katalogen" @@ -351,20 +366,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -616,116 +635,116 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "I samtal med" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Lägg på" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Samtalet slut." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -747,169 +766,165 @@ msgstr "Skicka" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "I samtal" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Förlopp" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Själv bild" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone debug fönster" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "_Homepage" msgstr "Hemsidan" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Check _Updates" msgstr "Letar efter uppdateringar" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Användarnamn" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Kontaktar" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Lägg till" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editera" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Sök" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Lägg till kontakt ifrån katalogen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Hittat kontakt %i" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "I samtal" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Min nuvarande identitet" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Användarnamn" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Lösenord" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet förbindelse:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Logga mig automatiskt" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Login information" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Välkommen!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "Alla användare\n" "Online användare" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fiber" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "%s (Default)" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1519,7 +1534,7 @@ msgstr "" msgid "Outgoing call" msgstr "Utgående samtal" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Redo" @@ -1578,12 +1593,12 @@ msgstr "Kopplad" msgid "Call aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Nuvarande samtal" @@ -1684,119 +1699,119 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Kunde inte logga in som %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Tidig media" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Samtal med %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Samtalet slut" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Samtalet slut." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Användare upptagen." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Användaren temporärt inte tillgänglig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Användaren vill inte bli störd." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 #, fuzzy msgid "No response." msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Omdirigerat till %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lyckades." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lyckades." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislyckades: %s" @@ -1806,13 +1821,16 @@ msgstr "Registrering hos %s mislyckades: %s" msgid "Authentication token is %s" msgstr "Linphone - Autentisering krävs" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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 "label" +#~ msgstr "etikett" + #~ msgid "Chat with %s" #~ msgstr "Chatta med %s" diff --git a/po/zh_CN.po b/po/zh_CN.po index f03c496d8..7c81df3fc 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-01-08 23:51+0800\n" "Last-Translator: Aron Xu \n" "Language-Team: Chinese (simplified) \n" @@ -18,52 +18,72 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "呼叫 %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "发送消息给 %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "正在呼叫" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "中断" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "丢失" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "拒绝" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,42 +97,46 @@ msgstr "静音" msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "无效的 SIP 联系人!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "运行时向标准输出记录调试信息。" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "启动到系统托盘,不显示主界面。" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "现在呼叫的地址" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "是否设置呼叫自动应答" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "与 %s 通话" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -124,68 +148,68 @@ msgstr "" "您是否允许他看到您的在线状态或者将它加为您的联系人允许?\n" "如果您回答否,则会将该人临时性的放入黑名单" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "请输入 %s@%s 的密码:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "呼叫历史" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "呼入" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒绝" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "中断" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "端口" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "网站" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - 互联网视频电话" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (默认)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -193,61 +217,52 @@ msgstr "" "未在此计算机上检测到声卡。\n" "您无法发送或接收音频呼叫。" -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "免费的 SIP 视频电话" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "在线状态" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名称" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "呼叫 %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "在 %s 目录中查找 " -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "无效的 SIP 联系人!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "呼叫 %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "发送消息给 %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "编辑联系人 %s" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "删除联系人 %s" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "从 %s 目录增加联系人 " @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重启 linphone 以使语言选择生效。" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -613,116 +632,116 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "正在呼叫..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "呼入" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "通话结束。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "呼叫失败。" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -744,167 +763,163 @@ msgstr "发送" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "标签" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "呼入" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "通话时间" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "启用自视" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone 调试窗口" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "_Homepage" msgstr "主页" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Check _Updates" msgstr "检查更新" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "帐户设置向导" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP 地址或电话号码:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "联系人" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "添加" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "编辑" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "搜索" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "从目录增加联系人" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "找到 %i 联系方式" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "呼入" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "当前地址:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "用户名" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密码" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "网络连接:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "自动登录" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登录信息" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "欢迎!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "全部用户\n" "在线用户" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "光纤" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "默认" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1530,7 +1545,7 @@ msgstr "" msgid "Outgoing call" msgstr "呼出" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "就绪" @@ -1588,12 +1603,12 @@ msgstr "已连接。" msgid "Call aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1689,116 +1704,116 @@ msgstr "" "您输入的地址无效。\n" "它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "无法登录为 %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "响铃。" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "响铃。" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "与 %s 通话" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "呼叫结束" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "通话结束。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "被叫正忙。" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "您呼叫的用户暂时无法接通。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "用户已开启免打扰功能。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "呼叫被拒绝。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "没有响应。" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "协议错误。" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "已重定向" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "呼叫失败。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "成功注册到 %s" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "已在 %s 解除注册。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "没有响应,超时" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "注册到 %s 失败: %s" @@ -1808,12 +1823,15 @@ msgstr "注册到 %s 失败: %s" msgid "Authentication token is %s" msgstr "Linphone - 需要认证" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您错过了 %i 个呼叫。" +#~ msgid "label" +#~ msgstr "标签" + #~ msgid "Keypad" #~ msgstr "数字键盘" diff --git a/po/zh_TW.po b/po/zh_TW.po index c65dcb84f..d1b2ce1a7 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-04-06 21:24+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: \n" @@ -17,52 +17,72 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "播打給 %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "傳送文字給 %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "通話中" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "已放棄" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "未接" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "拒接" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -76,43 +96,47 @@ msgstr "靜音" msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "無效的 sip 連絡人!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "執行時將一些除錯資訊記錄到標準輸出。" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "只在系統匣啟動,不要顯示主要介面。" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "現在要打電話的位址" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "如啟用此項,將會自動接聽來電" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "和 %s 通話" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -124,7 +148,7 @@ msgstr "" "您是否要允許他看見您的上線狀態或將他加入您的連絡人清單?\n" "如果您回答否,這個人會被暫時列入黑名單。" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -133,61 +157,61 @@ msgstr "" "請輸入您使用者名稱 %s\n" "於網域 %s 的密碼:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "通話紀錄" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "來電" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "接聽" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒接" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "通話已放棄" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "連接埠" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "網站連結" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - 網路視訊電話" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (預設值)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "我們被轉接到 %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -195,61 +219,52 @@ msgstr "" "在這臺電腦中偵測不到音效卡。\n" "您將無法傳送或接收語音電話。" -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "自由的 SIP 視訊電話" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "上線狀態" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名稱" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "播打給 %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "在 %s 目錄中搜尋" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "無效的 sip 連絡人!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "播打給 %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "傳送文字給 %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "編輯連絡人「%s」" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "刪除連絡人「%s」" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "從 %s 目錄加入新的連絡人" @@ -350,20 +365,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -614,114 +633,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "播打..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "來電" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "通話中" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "暫停通話" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "通話結束。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "轉接" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "轉接" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "繼續" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "暫停" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "暫停" @@ -744,157 +763,153 @@ msgstr "傳送" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "標籤" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "轉接" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "通話中" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "時間長度" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "選項(_O)" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "啟用自拍檢視" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "求助(_H)" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "顯示除錯視窗" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "官方網頁(_H)" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "檢查更新(_U)" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "帳號設定助理" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP 位址或電話號碼:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "打出新電話" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "連絡人" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "加入" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "編輯" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "搜尋" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "從目錄加入連絡人" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "加入聯絡人" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "通話中" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "我目前的使用者識別:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "使用者名稱" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密碼" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "網路連線:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "將我自動登入" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登入資訊" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "歡迎使用!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "所有使用者" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "線上使用者" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "光纖通道" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "預設值" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1505,7 +1520,7 @@ msgstr "" msgid "Outgoing call" msgstr "去電" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "準備就緒" @@ -1559,11 +1574,11 @@ msgstr "已連線。" msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "暫停目前的通話..." @@ -1662,115 +1677,115 @@ msgstr "" "您輸入的 sip 身分是無效的。\n" "它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "無法以 %s 登入" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "遠端響鈴。" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "遠端響鈴..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "早期媒體。" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "和 %s 的通話已暫停。" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "通話由 %s 接聽 - 保留中。" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "通話已繼續。" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "通話由 %s 接聽。" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "我們要繼續了..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "通話已終止。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "使用者現正忙碌。" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "使用者暫時無法聯繫。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "使用者不想要被打擾。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "通話被拒接。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "沒有回應。" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "通訊協定錯誤。" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "已重新導向" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "通話失敗。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "在 %s 註冊成功。" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "在 %s 取消註冊完成。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "沒有回應逾時" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "在 %s 註冊失敗:%s" @@ -1780,12 +1795,15 @@ msgstr "在 %s 註冊失敗:%s" msgid "Authentication token is %s" msgstr "驗證失敗" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您有 %i 通未接來電。" +#~ msgid "label" +#~ msgstr "標籤" + #~ msgid "Keypad" #~ msgstr "撥號盤" From a0f096f7a9e3f88efcd1a2181b5ff73ca4e34f67 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Apr 2013 12:33:15 +0200 Subject: [PATCH 222/909] Add missing exports. --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d4ca59bea..fd3b89a17 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1233,8 +1233,8 @@ LINPHONE_PUBLIC void linphone_core_set_ring(LinphoneCore *lc, const char *path); const char *linphone_core_get_ring(const LinphoneCore *lc); LINPHONE_PUBLIC 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 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); From 1d2f4eac5919cbd627e4ea2d2b65c3bed0f901f4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Apr 2013 18:24:07 +0200 Subject: [PATCH 223/909] set mtu to 1300 because mtu detection is absolutely not reliable. This is making a lot of problems with video packets especially. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f6c51a11f..d9ce543de 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f6c51a11f1ef1156c6f768b8466698a2305a2188 +Subproject commit d9ce543dee40d7cb7da55e50c6716a25f53ea2ba From 4a6be4863bab18f6e380784c226e268c993100bb Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 8 Apr 2013 12:59:42 +0200 Subject: [PATCH 224/909] change unread messages picture chnage time for time change --- coreapi/message_storage.c | 1 + coreapi/sal_eXosip2.c | 1 + gtk/chat.c | 11 +++++------ pixmaps/active_chat.png | Bin 3103 -> 3415 bytes 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 0c41c20d0..8ba642b68 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -66,6 +66,7 @@ static void create_chat_message(char **argv, void *data){ for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; } + ret.tm_isdst=-1; } new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); new_message->state=atoi(argv[7]); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 2ea0f9aff..b86fc26e0 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1798,6 +1798,7 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; } + ret.tm_isdst=-1; }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); diff --git a/gtk/chat.c b/gtk/chat.c index cf6d61c98..9bcf0bb8b 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -168,10 +168,10 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, case LinphoneChatMessageStateDelivered: { tnow=time(NULL); - tm=gmtime(&tnow); + tm=localtime(&tnow); tnow_day=tm->tm_yday; tnow_year=tm->tm_year; - tm=gmtime(&t); + 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 { @@ -237,7 +237,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag case LinphoneChatMessageStateDelivered: { time_t t=time(NULL); - struct tm *tm=gmtime(&t); + struct tm *tm=localtime(&t); char buf[80]; strftime(buf,80,"%H:%M",tm); result=buf; @@ -450,10 +450,10 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(w!=NULL){ char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ + linphone_chat_room_mark_as_read(room); send=TRUE; } else { if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ - //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); } send=FALSE; @@ -461,7 +461,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } else { send=FALSE; if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ - //linphone_gtk_load_chatroom(room,linphone_chat_message_get_from(msg),w); linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); } w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); @@ -469,6 +468,7 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, g_object_set_data(G_OBJECT(friendlist),"from",from); } get_display_name(linphone_chat_message_get_from(msg)); + #ifdef HAVE_GTK_OSXs /* Notified when a new message is sent */ linphone_gtk_status_icon_set_blinking(TRUE); @@ -491,5 +491,4 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, } else { linphone_gtk_show_friends(); } - //linphone_gtk_update_chat_picture(); } diff --git a/pixmaps/active_chat.png b/pixmaps/active_chat.png index e428845d55648e21ab59ad6c9d94e48b7e8a70ea..d82b7c595c8a90fddb3c313be4bd9c6c524b0af4 100644 GIT binary patch delta 677 zcmV;W0$Tl_7}pxGzY2c>f=NU{RCwCVRbNO`Q5^ox_1e8H-8F<|u7Uc{LqQStVh@I- zL7*WNJ@_L1c?hWpst0>4DC(_25Co>ih(Z&I>_x1mlL&$+v_h*%CexQ~y0-3hp0B55 zy1VHdK|lB&4u^Ao=ljF&2$J~MrEK(|Iq?AA^9L~-9)tYxth#^6B`Ad8Vefe7(Yq5U zb=TnZy+D3VwBjNRJohWLwfB|Jn?3WM9l`|4(Qv@?y1mqg_{5 zni&xqd&LR`1X6$CE~6`Dy{+ZW49RpRx~{|NbgnIzQI4CwN7yt!ftCx`V46wbX9#lu z%63-6REuxTPJR0T0BKB~_VzNTS~7WNUooM80)j#-VtdyJ&kp<&?n{FpX=8j!q%F%r zwusAQ0v%URqU-$vb{#u~%f}m_nK8WRybUWBI?;6GkZym=q&Ej9;jeG$7J`6I-^eVZ z(eG^BzLfyD=iI|57l&D5>&aTFO0AO0{rEUNiN_s-XsmI;sQ@=_wV^UxgO}WUg(f1l zO#1rzY+o&NX)7DA_8<@lFc=I%*L4_% zf%^J-0Kn+zC?b&vgb)xyEKBtF)ly23gp?A^&CMds=uGJD?j}k4{eBJ&4RO8xtVUMj zHBCcLPY)Is7g1MNCpMh8OdDRWmxf`WwY62``~4k?|N4*5rTz>6c>+{F&e}*B00000 LNkvXXu0mjfl!8b} delta 362 zcmV-w0hRvO8lM=jzY2c=N=ZaPRCwCdl`)ROFc3xmShk!rP6OL5$3WV2G*l^a1MZX~ zP^6;a0+A9aRM1j$0Hn~6CXr{GRm8%QC`3V8OKvQWM}GhNo0u764}mv~w=|J|EpE44 zCZb*k5fQAl_?S-d<@>*i>0XmKjyVVdxUP%7dNDH&`#q#mn9qOb^zj6GMdlX z49DZKT@xC}zp87vT6bu2gJ`$g;e0-K9z2;$;QM}4FQja5!Z(69g?$VFz*;-5h55&6 zofaN~ivfr}O0*z-KBR;!_z`KZai{eHg(02kWB6|-2`r~m)}07*qo IM6N<$f~JM4GXMYp From f2f51005dc1581c4601f375ca4cec94ba1895ef6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Apr 2013 13:56:44 +0200 Subject: [PATCH 225/909] update ms2 and ortp for call quality indicator improvements. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 913661226..35f5efbfb 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 9136612268a133eaf0b3ea2e7fd0869bdd0b6686 +Subproject commit 35f5efbfbf7814bd0403249431a6b94d6c4286b4 From bd9504d010ddf8b25ee12c812bf3273d349c4cc7 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 8 Apr 2013 14:09:45 +0200 Subject: [PATCH 226/909] fix unread messages --- gtk/chat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/chat.c b/gtk/chat.c index 9bcf0bb8b..a61afcf21 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -450,7 +450,6 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(w!=NULL){ char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); if(g_strcmp0(from,from_chatview)==0){ - linphone_chat_room_mark_as_read(room); send=TRUE; } else { if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ @@ -485,6 +484,8 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, if(send){ if(gtk_notebook_get_current_page(notebook)!=gtk_notebook_page_num(notebook,w)){ linphone_gtk_show_friends(); + } else { + linphone_chat_room_mark_as_read(room); } linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), FALSE,room,msg,FALSE); From fb5faa5bb83d406ef4d9e374611e8a28d9b4bd96 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 9 Apr 2013 10:02:59 +0200 Subject: [PATCH 227/909] Fix upnp forgotten retain --- coreapi/upnp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 982ab0368..682240e46 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -29,8 +29,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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_RETRY_DELAY 10 +#define UPNP_CALL_RETRY_DELAY 3 #define UPNP_UUID_LEN 128 #define UPNP_UUID_LEN_STR UPNP_TOSTRING(UPNP_UUID_LEN) /* @@ -881,7 +881,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, -1); + *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port); } // Get addresses @@ -1058,11 +1058,17 @@ 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; } @@ -1109,6 +1115,7 @@ 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 && From a0b6520903db9681af2d9832fd222d6469a4f20b Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 9 Apr 2013 10:49:08 +0200 Subject: [PATCH 228/909] Updated translation file Clear missed call Add picture for unread messages --- gtk/calllogs.c | 6 +- gtk/chat.c | 7 +- gtk/friendlist.c | 46 +++--- gtk/incall_view.c | 8 +- gtk/linphone.h | 30 ++-- gtk/main.c | 4 +- po/cs.po | 342 ++++++++++++++++++++------------------- po/de.po | 339 +++++++++++++++++++------------------- po/es.po | 348 ++++++++++++++++++++------------------- po/fr.po | 402 ++++++++++++++++++++++++---------------------- po/he.po | 352 +++++++++++++++++++++------------------- po/hu.po | 360 +++++++++++++++++++++-------------------- po/it.po | 344 ++++++++++++++++++++------------------- po/ja.po | 341 ++++++++++++++++++++------------------- po/nb_NO.po | 344 ++++++++++++++++++++------------------- po/nl.po | 341 ++++++++++++++++++++------------------- po/pl.po | 341 ++++++++++++++++++++------------------- po/pt_BR.po | 341 ++++++++++++++++++++------------------- po/ru.po | 348 ++++++++++++++++++++------------------- po/sr.po | 348 ++++++++++++++++++++------------------- po/sv.po | 344 ++++++++++++++++++++------------------- po/zh_CN.po | 344 ++++++++++++++++++++------------------- po/zh_TW.po | 344 ++++++++++++++++++++------------------- 23 files changed, 3157 insertions(+), 2867 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 7daa1b011..466541006 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -61,7 +61,7 @@ void linphone_gtk_call_log_chat_selected(GtkWidget *w){ gtk_tree_model_get(model,&iter,2,&pla,-1); la=(LinphoneAddress*)pla; if (la!=NULL){ - linphone_gtk_tree_view_set_chat_conversation(la); + linphone_gtk_friend_list_set_chat_conversation(la); } } } @@ -192,8 +192,9 @@ void linphone_gtk_call_log_clear_missed_call(){ 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("Recent calls"); + 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); @@ -359,6 +360,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)); } diff --git a/gtk/chat.c b/gtk/chat.c index a61afcf21..4fa1c917c 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -64,7 +64,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); - linphone_gtk_create_chat_picture(FALSE); + 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); g_object_set_data(G_OBJECT(w),"cr",NULL); @@ -385,6 +385,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); entry = linphone_gtk_get_widget(chat_view,"text_entry"); g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL); + g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL); ms_free(with_str); return chat_view; } @@ -404,13 +405,13 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, char *uri_only=linphone_address_as_string_uri_only(uri); MSList *messages=NULL; - linphone_chat_room_mark_as_read(cr); 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; - + + linphone_chat_room_mark_as_read(cr); 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); diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 3997e29f3..8f73c2fcb 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -87,11 +87,6 @@ static GdkPixbuf *create_chat_picture(){ return pixbuf; } -/*static GdkPixbuf *create_active_chat_picture(){ - GdkPixbuf *pixbuf; - pixbuf = create_pixbuf("active_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; @@ -226,18 +221,22 @@ 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; + int nbmsg=0; if (gtk_tree_model_get_iter_first(model,&iter)) { do{ - //if(!active){ + gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); + nbmsg=linphone_chat_room_get_unread_messages_count(cr); + if(nbmsg != 0){ + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); + } else { gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); - //} 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)); } } @@ -247,7 +246,7 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } -void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ +void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ GtkTreeIter iter; GtkListStore *store=NULL; GtkWidget *w = linphone_gtk_get_main_window(); @@ -270,7 +269,7 @@ void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ linphone_gtk_load_chatroom(cr,la,chat_view); } gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); - linphone_gtk_create_chat_picture(FALSE); + 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))); @@ -295,7 +294,7 @@ void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la){ linphone_gtk_load_chatroom(cr,uri,chat_view); } gtk_notebook_set_current_page(notebook,gtk_notebook_page_num(notebook,chat_view)); - linphone_gtk_create_chat_picture(FALSE); + linphone_gtk_friend_list_update_chat_picture(); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(chat_view,"text_entry")); break; } @@ -309,17 +308,16 @@ void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guin GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); GtkWidget *chat_view; LinphoneChatRoom *cr=NULL; - const LinphoneAddress *addr=(const LinphoneAddress *)data; - 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=linphone_core_get_chat_room(linphone_gtk_get_core(),addr); - if(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(); + linphone_gtk_show_friends(); } - } + } } } @@ -355,9 +353,8 @@ void linphone_gtk_chat_selected(GtkWidget *item){ linphone_gtk_load_chatroom(cr,uri,page); } 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")); - g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,(gpointer)uri); } } @@ -809,7 +806,6 @@ void linphone_gtk_show_friends(void){ 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= diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 4ab0bd72e..44b35c03c 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")); @@ -688,7 +688,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ 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); @@ -843,7 +843,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) { @@ -859,7 +859,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); diff --git a/gtk/linphone.h b/gtk/linphone.h index 00484a04f..f987b2abe 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -58,7 +58,6 @@ 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); - const char *linphone_gtk_message_storage_get_db_file(const char *filename); void linphone_gtk_show_assistant(void); void linphone_gtk_close_assistant(void); @@ -68,15 +67,11 @@ 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); @@ -85,7 +80,6 @@ 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); @@ -99,21 +93,25 @@ 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); - void linphone_gtk_terminate_call(GtkWidget *button); -void update_tab_header(LinphoneCall *call,gboolean pause); - +void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause); 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); +LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); +void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); + +void linphone_gtk_friend_list_update_chat_picture(); +void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); +gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); +void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data); +void linphone_gtk_show_friends(void); +void linphone_gtk_show_contact(LinphoneFriend *lf); +void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf); /*functions controlling the different views*/ gboolean linphone_gtk_use_in_call_view(); @@ -151,6 +149,4 @@ void linphone_gtk_uninit_instance(void); void linphone_gtk_monitor_usb(void); void linphone_gtk_unmonitor_usb(void); -gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); -void linphone_gtk_tree_view_set_chat_conversation(const LinphoneAddress *la); -gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); \ No newline at end of file +gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); \ No newline at end of file diff --git a/gtk/main.c b/gtk/main.c index e3699757f..e914e42bd 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1232,10 +1232,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); diff --git a/po/cs.po b/po/cs.po index 726ba26a4..481b7aa17 100644 --- a/po/cs.po +++ b/po/cs.po @@ -17,7 +17,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-3.4.99.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-11-04 22:30+0100\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" @@ -27,26 +27,41 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Volat komu: %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Poslat text komu: %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Probíhá hovor" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "–" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "přerušen" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "promeškán" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Odmítnout" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -54,7 +69,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -62,21 +77,26 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konference" @@ -89,31 +109,35 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Neplatný sipový kontakt!" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "Soubor, kam zapisovat protokol." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 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:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Zavolá právě teď na tuto adresu" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "je-li nastaveno, automaticky zvedne příchozí hovor" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -121,12 +145,12 @@ msgstr "" "Zadejte pracovní adresář (měl by být základní instalační adresář, například " "c:\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Hovor s %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -139,7 +163,7 @@ msgstr "" "do svého adresáře?\n" "Odpovíte-li ne, tato osobo bude dočasně blokována." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -148,59 +172,59 @@ msgstr "" "Prosím, zadejte heslo pro uživatele %s\n" "v doméně %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Odpovědět" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Odmítnout" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Hovor odložen" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porty" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Odkaz na webovou stránku" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Lipnhone – internetový videofon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Výchozí)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Byly jsme přepojeni na %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -208,63 +232,54 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Volný SIP videofon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Zobrazit adresář" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Stav" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Jméno" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Volat komu: %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Diskuzní skupina" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Hledat v adresáři %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Neplatný sipový kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Volat komu: %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Poslat text komu: %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Upravit kontakt „%s“" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Odstranit kontakt „%s“" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Přidat nový kontakt z adresáře %s" @@ -365,20 +380,24 @@ msgstr "norština" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Žádná" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -634,114 +653,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Volá se…" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "dobrá" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "průměrná" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "slabá" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "velmi slabá" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "příliš špatná" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nedostupná" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "Probíhá konference" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Probíhá hovor" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Odložený hovor" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Hovor skončil." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Přepojit" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Přepojit" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Obnovit" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Odložit" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Odložit" @@ -764,157 +783,152 @@ msgstr "Odeslat" 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 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Přepojit" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Telefonuje se" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Délka" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Hodnocení kvality hovoru" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "V_olby" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Zobrazovat sám sebe" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "Nápo_věda" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Zobrazit ladicí okno" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Domovská stránka" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Vyhledat akt_ualizace" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP adresa nebo telefonní číslo:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Zahájit nový hovor" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakty" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Přidat" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Upravit" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Hledat" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Přidat kontakty z adresáře" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Přidat kontakt" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Nedávné hovory" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Moje současná totožnost:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Uživatelské jméno" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Heslo" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Připojení k Internetu:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Přihlašovat mě automaticky" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Informace o přihlášení" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Vítejte!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "všech uživatelích" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "připojených uživatelích" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber Channel" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Výchozí" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1529,7 +1543,7 @@ msgstr "" msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Připraven." @@ -1584,11 +1598,11 @@ msgstr "Připojeno." msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" @@ -1688,116 +1702,116 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Nelze se přihlásit jako %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Vyzvání na druhé straně." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Vyzvání na druhé straně…" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Časná média." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Hovor s %s je odložen." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Hovor přijat kým: %s – odložen." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Hovor obnoven." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Hovor přijat kým: %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Byli jsme obnoveni…" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Hovor byl aktualizován protistranou…" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Hovor ukončen." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Uživatel je zaneprázdněn." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Uživatel je dočasně nedostupný." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Uživatel si nepřeje být rušen." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Volání odmítnuto." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Žádná odpověď." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Chyba protokolu." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Přesměrováno" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Volání se nezdařilo." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrace na %s byla úspěšná." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Odregistrování z %s hotovo." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "odpověď nedorazila včas" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrace na %s selhala: %s" @@ -1807,7 +1821,7 @@ msgstr "Registrace na %s selhala: %s" msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/de.po b/po/de.po index a4745d95f..44c1e66ea 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-11-07 19:27+0100\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" @@ -17,53 +17,73 @@ msgstr "" "X-Generator: Lokalize 1.5\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "„%s“ anrufen" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Text zu „%s“ schicken" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Im Gespräch" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "nicht verfügbar" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Abgebrochen" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Entgangen" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Abgewiesen" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i Minute" msgstr[1] "%i Minuten" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i Sekunde" msgstr[1] "%i Sekunden" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format +msgid "%s\t%s" +msgstr "" + +#: ../gtk/calllogs.c:323 +#, fuzzy, 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" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:329 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\t\n" +"%s" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konferenz" @@ -76,33 +96,37 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Ungültiger SIP-Kontakt!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "Linphone mit ausgeschaltetem Video starten." -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 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:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Im Moment anzurufende Adresse" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Falls aktiviert, werden eingehende Anrufe automatisch beantwortet" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,12 +134,12 @@ msgstr "" "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. " "C:\\Programme\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Im Gespräch mit %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -128,7 +152,7 @@ msgstr "" "Ihrer Kontaktliste hinzufügen?\n" "Wenn Sie mit Nein antworten, wird diese Person vorläufig blockiert." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -137,59 +161,59 @@ msgstr "" "Geben Sie bitte Ihr Passwort für den Benutzernamen %s\n" " auf der Domäne %s ein:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Annehmen" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Abweisen" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Anruf wird gehalten" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, c-format msgid "by %s" msgstr "von %s" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, 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:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Website-Verknüpfung" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - ein Internet-Video-Telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Vorgabe)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Vermittlung nach %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -197,61 +221,52 @@ msgstr "" "Auf diesem Rechner können keine Soundkarten gefunden werden.\n" "Sie können keine Audio-Anrufe tätigen oder entgegennehmen." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Ein freies SIP-Video-Telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Zum Adressbuch hinzufügen" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Anwesenheitsstatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Name" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Anrufen" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Chat Raum" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Im %s-Verzeichnis suchen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Ungültiger SIP-Kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "„%s“ anrufen" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Text zu „%s“ schicken" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Kontakt „%s“ bearbeiten" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Kontakt „%s“ löschen" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" @@ -352,22 +367,26 @@ msgstr "Norwegisch" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Keinen" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -621,112 +640,112 @@ msgstr "" msgid "%.3f seconds" msgstr "%i Sekunde" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Verbindungsaufbau..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "gut" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "durchschnittlich" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "schlecht" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "sehr schlecht" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "zu schlecht" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Gesichert durch SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Auf „Ungeprüft“ setzen" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Auf „Geprüft“ setzen" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "In Konferenz" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Gehaltener Anruf" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Anruf beendet." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "Vermittlung läuft" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Vermittlung abgeschlossen." -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Vermittlung fehlgeschlagen." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Fortsetzen" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Halten" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Halten" @@ -749,155 +768,151 @@ msgstr "Senden" msgid "End conference" msgstr "In Konferenz" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Vermittlung" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Dauer" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Bewertung der Verbindungsqualität" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Optionen" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "Video immer starten" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Selbstansicht ein" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Hilfe" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Debug-Fenster anzeigen" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Auf _Aktualisierungen überprüfen" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP-Adresse oder Telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Einen neuen Anruf beginnen" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakte" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Hinzufügen" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Bearbeiten" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Suchen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Kontakte aus einem Verzeichnis hinzufügen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Kontakt hinzufügen" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Letzte Gespräche" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Aktuelle Identität:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Benutzername" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passwort" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internetverbindung:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Automatisch anmelden" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Anmeldeinformationen" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Willkommen !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Alle Teilnehmer" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Angemeldete Teilnehmer" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Glasfaserkabel" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Vorgabe" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1508,7 +1523,7 @@ msgstr "" msgid "Outgoing call" msgstr "Abgehender Anruf" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Bereit" @@ -1564,11 +1579,11 @@ msgstr "Verbunden." msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." @@ -1669,115 +1684,115 @@ msgstr "" "Sie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:" "alice@beispiel.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Anmeldung als %s fehlgeschlagen" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Klingeln bei der Gegenseite." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Klingeln bei der Gegenseite..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Anruf mit %s wird gehalten." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Der von %s entgegengenommene Anruf wird gehalten." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Anruf fortgesetzt." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Anruf wird von %s entgegengenommen." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Inkompatibel, überprüfen Sie die Codecs..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "Anruf wird fortgesetzt." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "Anruf wird von der Gegenseite gehalten." -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "Anruf ist von der Gegenseite aktualisiert worden." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Anruf beendet." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Teilnehmer ist besetzt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Teilnehmer zur Zeit nicht verfügbar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Teilnehmer möchte nicht gestört werden." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Anruf abgewiesen" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Keine Antwort." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokollfehler" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Umgeleitet" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "Inkompatible Medienparameter." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Anruf fehlgeschlagen." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrierung auf %s erfolgreich." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Abmeldung von %s ist erfolgt." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Zeitüberschreitung bei der Antwort" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrierung auf %s fehlgeschlagen: %s" @@ -1787,7 +1802,7 @@ msgstr "Registrierung auf %s fehlgeschlagen: %s" msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/es.po b/po/es.po index 9bdca11b7..90fa0f926 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-12-06 15:54+0100\n" "Last-Translator: BERAUDO Guillaume \n" "Language-Team: es \n" @@ -15,58 +15,80 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Llamar a %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Enviar mensaje a %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "En llamada " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "n/a" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "abortada" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "perdida" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Rechazar" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i minuto" msgstr[1] "%i minutos" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i segundo" msgstr[1] "%i segundos" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tCalidad: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conferencia" @@ -79,32 +101,36 @@ msgstr "Yo" msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "¡Contacto SIP no válido!" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "ruta a un fichero donde escribir logs." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Iniciar sólo en la barra de tareas, no mostrar la interfaz principal." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "dirección a la que llamar inmediatamente" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "si está activo, responder a llamadas entrantes automáticamente" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -112,12 +138,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Llamar con %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -130,7 +156,7 @@ msgstr "" "contactos?\n" "Si responde no, esta persona será bloqueada temporalmente." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -139,63 +165,63 @@ msgstr "" "Por favor, introduzca la contraseña para el usuario %s\n" " en el dominio %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Error en la llamada." -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Llamada terminada" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Contestar" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "Rechazar" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Llamada en pausa" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Puertos" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Enlace a la Web" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - un video-teléfono a través de Internet" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Opción predeterminada)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Somos transferidos a %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -203,63 +229,54 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Un video-teléfono SIP gratuito" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Añadir a la agenda" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "Estado de Presencia" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nombre" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Llamada" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Buscar en el directorio %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "¡Contacto SIP no válido!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Llamar a %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Enviar mensaje a %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Editar contacto '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Eliminar contacto '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Añadir nuevo contacto desde el directorio %s" @@ -360,21 +377,25 @@ msgstr "Noruego" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Deberá reiniciar linphone para aplicar la nueva selección de lenguaje" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "Ninguno." -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -632,119 +653,119 @@ msgstr "" msgid "%.3f seconds" msgstr "%i segundo" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr " Llamando..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "buena" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "media" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "mala" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "muy mala" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "demasiado mala" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "no disponible" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Cifrada con SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Cifrada con ZRTP - [token de autenticación: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Set sin verificar" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Set verificado" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "En conferencia" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Llamada en pausa" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Llamada finalizada." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Transferir" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Transferir" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Reanudar" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pausar" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pausar" @@ -769,172 +790,168 @@ msgstr "Enviar" msgid "End conference" msgstr "En conferencia" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etiqueta" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Transferir" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Duración" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Calidad de la llamada" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Opciones" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Activar vista propia" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Ayuda" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Mostrar ventana de depuración" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Pagina_de_Inicio" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Buscar_Actualizaciones" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Dirección SIP o número de teléfono" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Iniciar nueva llamada" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Contactos" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Añadir" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editar" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Buscar" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Añadir contactos desde un directorio" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Añadir contacto" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Llamadas recientes " -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Mi identidad actual:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Nombre de usuario" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Contraseña:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Conexión a Internet" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Iniciar sesión automáticamente" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Datos de inicio de sesión" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "¡Bienvenido/a!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Todos los usuarios" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "Usuarios conectados" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Canal de Fibra" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Predeterminado" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1586,7 +1603,7 @@ msgstr "" msgid "Outgoing call" msgstr "Llamada saliente" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Preparado" @@ -1648,11 +1665,11 @@ msgstr "Conectado." msgid "Call aborted" msgstr "Llamada abortada" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "No se pudo pausar la llamada" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Pausando la llamada actual..." @@ -1757,121 +1774,121 @@ msgstr "" "Debe ser del tipo sip:username@proxydomain, como por ejemplo sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "No se pudo iniciar sesión como %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Medios iniciales." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "La llamada con %s está puesta en pausa." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Llamada respondida por %s - en espera." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Llamada reanudada." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "Llamada respondida por %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Nos han reanudado..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "La llamada ha sido actualizada por el destinatario..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "Llamada finalizada." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "El usuario está ocupado." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "El usuario no está disponible temporalmente." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "El usuario no quiere que le molesten." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Llamada rechazada." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "No hay respuesta." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Error de protocolo." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Redigirida" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "La llamada ha fallado." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Se ha registrado con éxito en %s." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Cancelación de registro en %s completada." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "timeout sin respuesta" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "El registro en %s ha fallado." @@ -1881,13 +1898,16 @@ msgstr "El registro en %s ha fallado." msgid "Authentication token is %s" msgstr "El tóken de autenticación es%s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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." +#~ msgid "label" +#~ msgstr "etiqueta" + #~ msgid "Chat with %s" #~ msgstr "Conversación con %s" diff --git a/po/fr.po b/po/fr.po index 322a2ff4c..d4cb84c52 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" -"PO-Revision-Date: 2002-12-06 17:33+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"PO-Revision-Date: 2013-04-08 16:46+0100\n" "Last-Translator: Simon Morlat \n" "Language-Team: french \n" "Language: \n" @@ -15,51 +15,71 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Appeler %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Chatter avec %s" + +#: ../gtk/calllogs.c:223 +#, c-format +msgid "Recent calls (%i)" +msgstr "Appels récents (%i)" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "inconnu" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Abandonné" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Manqué" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Refusé" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conférence" @@ -72,31 +92,35 @@ msgstr "Moi" msgid "Couldn't find pixmap file: %s" msgstr "Icone non trouvée: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Contact sip invalide !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "affiche des informations de debogage" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Démarrer linphone avec la vidéo désactivée." -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Démarre iconifié, sans interface principale." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "addresse à appeler maintenant" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -104,12 +128,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Appel avec %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -123,7 +147,7 @@ msgstr "" "Si vous répondez non, cette personne sera mise temporairement sur liste " "noire." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -132,59 +156,59 @@ msgstr "" "Entrez le mot de passe pour %s\n" " sur le domaine %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Appel en pause" -#: ../gtk/main.c:1137 -#, fuzzy, c-format +#: ../gtk/main.c:1142 +#, c-format msgid "by %s" -msgstr "Ports utilisés" +msgstr "" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Lien site web" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - un téléphone video pour l'internet" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -192,60 +216,51 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Un visiophone libre" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Ajouter au carnet d'adresse" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Appeler" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Rechercher dans l'annuaire de %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Contact sip invalide !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Appeler %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Chatter avec %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Editer le contact '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Supprimer le contact '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "Supprimer l'historique de chat de '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Ajouter un contact depuis l'annuaire %s" @@ -346,22 +361,26 @@ msgstr "Norvégien" msgid "Hebrew" msgstr "Hébreu" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "Serbe" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" -msgstr "" +msgstr "Aucun" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -382,7 +401,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..." @@ -408,22 +427,24 @@ msgid "" "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:43 msgid "Create an account on linphone.org" -msgstr "" +msgstr "Créer un compte sur linphone.org" #: ../gtk/setupwizard.c:44 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:45 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:85 msgid "Enter your linphone.org username" -msgstr "" +msgstr "Entrez votre identifiant linphone.org" #: ../gtk/setupwizard.c:92 msgid "Username:" @@ -447,7 +468,7 @@ msgstr "Mot de passe*" #: ../gtk/setupwizard.c:125 msgid "Domain*" -msgstr "" +msgstr "Domaine*" #: ../gtk/setupwizard.c:126 msgid "Proxy" @@ -455,7 +476,7 @@ msgstr "" #: ../gtk/setupwizard.c:298 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Champs requis" #: ../gtk/setupwizard.c:299 msgid "Username: (*)" @@ -471,7 +492,7 @@ msgstr "" #: ../gtk/setupwizard.c:305 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Confirmez votre mot de passe: (*)" #: ../gtk/setupwizard.c:369 msgid "" @@ -499,9 +520,8 @@ msgid "Account setup assistant" msgstr "" #: ../gtk/setupwizard.c:575 -#, fuzzy msgid "Configure your account (step 1/1)" -msgstr "Configuer un compte SIP" +msgstr "Configurez votre compte" #: ../gtk/setupwizard.c:580 msgid "Enter your sip username (step 1/1)" @@ -566,7 +586,7 @@ msgstr "" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" -msgstr "" +msgstr "uPnP non activé" #: ../gtk/incall_view.c:240 #, fuzzy @@ -603,112 +623,112 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" -msgstr "" +msgstr "Raccrocher" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "bon" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "moyen" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "faible" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "très faible" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "indisponible" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Sécurisé par SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Sécurisé par ZRTP- [jeton: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "En conférence" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Appel en cours" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Appel en attente" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Appel terminé." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" -msgstr "" +msgstr "Transfert en cours" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Transfert terminé" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Transfert échoué" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pause" @@ -730,157 +750,153 @@ msgstr "Envoyer" msgid "End conference" msgstr "Fin de conférence" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "Vidéo" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Transfert" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Appel en cours" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Durée" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Qualité de l'appel" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" -msgstr "" +msgstr "Toujours démarrer la vidéo" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Se voir" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Aide" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Fenêtre de débogage" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Site web" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Adresse SIP ou numéro" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Démarrer un nouvel appel" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Contacts" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Ajouter" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editer" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Rechercher" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Ajouter un contact depuis l'annuaire" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Ajouter un contact." -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Appels récents" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Mon identité sip:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Nom d'utilisateur" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Mot de passe" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Me connecter automatiquement" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Information de login" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Bienvenue !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Tous" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "En ligne" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Par défaut" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" -msgstr "" +msgstr "Supprimer" #: ../gtk/about.ui.h:1 msgid "About linphone" @@ -935,7 +951,7 @@ msgstr "" #: ../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" @@ -975,7 +991,7 @@ msgstr "" #: ../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:" @@ -999,7 +1015,7 @@ msgstr "Publier la présence" #: ../gtk/sip_account.ui.h:11 msgid "Configure a SIP account" -msgstr "Configuer un compte SIP" +msgstr "Configurer un compte SIP" #: ../gtk/parameters.ui.h:1 msgid "default soundcard" @@ -1023,7 +1039,7 @@ msgstr "Codecs audio" #: ../gtk/parameters.ui.h:6 msgid "Video codecs" -msgstr "Codecs video" +msgstr "Codecs vidéo" #: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 msgid "C" @@ -1162,11 +1178,11 @@ msgstr "Son" #: ../gtk/parameters.ui.h:40 msgid "Video input device:" -msgstr "Périphérique d'entrée video" +msgstr "Périphérique d'entrée vidéo" #: ../gtk/parameters.ui.h:41 msgid "Prefered video resolution:" -msgstr "Résolution video préférée:" +msgstr "Résolution de vidéo préférée:" #: ../gtk/parameters.ui.h:42 msgid "Video" @@ -1179,8 +1195,8 @@ msgstr "Paramètres multimedia" #: ../gtk/parameters.ui.h:44 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" +"Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de " +"compte SIP" #: ../gtk/parameters.ui.h:45 msgid "Your display name (eg: John Doe):" @@ -1192,7 +1208,7 @@ msgstr "Votre nom d'utilisateur:" #: ../gtk/parameters.ui.h:47 msgid "Your resulting SIP address:" -msgstr "Votre addresse SIP:" +msgstr "Votre adresse SIP:" #: ../gtk/parameters.ui.h:48 msgid "Default identity" @@ -1480,7 +1496,7 @@ msgstr "" msgid "Outgoing call" msgstr "Appel sortant" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Prêt." @@ -1535,11 +1551,11 @@ msgstr "En ligne." msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." @@ -1641,116 +1657,116 @@ msgstr "" "Elle doit être de la forme sip:username@domain, comme par example sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Echec de la connexion en tant que %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Sonnerie distante." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Sonnerie distante..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." -msgstr "Prise d'appel anticipée" +msgstr "Prise d'appel anticipée." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "%s est maintenant en attente." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Appel répondu par %s - en attente" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Appel répondu par %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Reprise..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "L'appel a été repris par le correspondant." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Appel terminé." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Occupé..." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "L'usager est temporairement indisponible." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "L'usager ne souhaite pas être dérangé" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Appel décliné." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Pas de réponse." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Erreur de protocole" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Redirection" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "L'appel a échoué." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Enregistrement sur %s effectué." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Désenregistrement sur %s effectué." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Pas de réponse" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Echec de l'enregistrement sur %s: %s" @@ -1760,7 +1776,7 @@ msgstr "Echec de l'enregistrement sur %s: %s" msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/he.po b/po/he.po index 7439d2651..b8b2895b8 100644 --- a/po/he.po +++ b/po/he.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.5.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2012-12-27 10:14+0200\n" "Last-Translator: Isratine Citizen \n" "Language-Team: Rahut \n" @@ -19,59 +19,82 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.5.4\n" -#: ../gtk/calllogs.c:82 +# צור קשר עם +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "התקשר אל %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "שלח טקסט אל %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "בשיחה כעת" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "לא זמין (n/a)" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "ננטשה" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "הוחמצה" # דחיה -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "לדחות" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "דקה %i" msgstr[1] "%i דקות" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "שניה %i" msgstr[1] "%i שניות" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tאיכות: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tאיכות: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tאיכות: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "ועידה" @@ -84,42 +107,47 @@ msgstr "אני" msgid "Couldn't find pixmap file: %s" msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" +# איש־קשר +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "כתובת sip לא תקפה !" + # cli -#: ../gtk/main.c:88 +#: ../gtk/main.c:92 #, fuzzy msgid "log to stdout some debug information while running." msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמן ביצוע." # cli -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 #, fuzzy msgid "path to a file to write logs into." msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" # cli -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 #, fuzzy msgid "Start only in the system tray, do not show the main interface." msgstr "התחל במגש המערכת בלבד, אל תציג את הממשק הראשי." # cli -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 #, fuzzy msgid "address to call right now" msgstr "כתובת להתקשרות ברגע זה" # cli -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 #, fuzzy msgid "if set automatically answer incoming calls" msgstr "באם אפשרות זו נקבעת ענה אוטומטית לקריאות נכנסות" # cli -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 #, fuzzy msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" @@ -128,14 +156,14 @@ msgstr "" "ציין מדור העבודה (אמור להיות מבוסס על ההתקנה, למשל: c:\\Program Files" "\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "התקשרות באמצעות %s" # הקשר שלהם # אם התשובה -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -148,7 +176,7 @@ msgstr "" "שלך ?\n" "היה ותשובתך תהיה לא, אדם זה יהיה מסומן באופן זמני ברשימה השחורה." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -158,64 +186,64 @@ msgstr "" " בתחום %s:" # שיחה -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "שגיאת קריאה" # Conversation ended -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "שיחה הסתיימה" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "לענות" # דחיה -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "לדחות" # Conversation paused -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "שיחה הושהתה" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Ports utilisés" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "קישור אתר רשת" # ‫Linphone - וידאופון במרשתת -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "‫Linphone - וידאופון אינטרנטי" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "‫%s (משתמטת)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "אנחנו מועברים אל %s" # קריאות שמע -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -223,63 +251,52 @@ msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" "לא תהיה ביכולתך לשלוח או לקבל שיחות שמע." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "וידאופון SIP חופשי" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "הוסף אל ספר כתובות" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "מצב נוכחות" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "שם" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "קריאה" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" # a name or a number -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "חיפוש במדור %s" -# איש־קשר -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "כתובת sip לא תקפה !" - -# צור קשר עם -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "התקשר אל %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "שלח טקסט אל %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "ערוך איש קשר '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "מחק איש קשר '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "הוסף איש קשר חדש מן מדור %s" @@ -384,21 +401,25 @@ msgstr "norsk" msgid "Hebrew" msgstr "" +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + # selected הנבחרת -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "ללא" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -659,121 +680,121 @@ msgstr "" msgid "%.3f seconds" msgstr "שניה %i" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "מתקשר כעת..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "‭00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "טובה" # רגילה -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "ממוצעת" # weak חלשה חלושה רפויה רופפת -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "דלה" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "דלה מאוד" # רעה -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "גרועה מדי" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "לא זמינה" # באמצעות -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "מאובטחת על ידי SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" # set or unset verification state of ZRTP SAS. -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "הגדר כלא מאומתת" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "הגדר כמאומתת" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "בשיחת ועידה" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "שיחה מושהית" # שעות %02i דקות %02i שניות %02i # Force LTR time format (hours::minutes::seconds) with LRO chatacter (U+202D) -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "‭%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "שיחה הסתיימה." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "העברה" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "העברה" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "חזרה" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "השהיה" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "השהיה" @@ -798,159 +819,155 @@ msgstr "שיגור" msgid "End conference" msgstr "בשיחת ועידה" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "תוויות" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "העברה" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "משך זמן" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "אומדן איכות שיחה" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_אפשרויות" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "אפשר ראות-עצמית" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_עזרה" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "הצג חלון ניפוי שגיאות" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_עמוד הבית" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "בדיקת _עדכונים" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "אשף חשבון" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "כתובת SIP או מספר טלפון" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "התחלת שיחה חדשה" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "אנשי קשר" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "הוסף" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "ערוך" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "חיפוש" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "הוסף אנשי קשר מן מדור" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "הוספת איש קשר" # קריאות אחרונות -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "שיחות אחרונות" # הזהות הנוכחית שלי -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "זהותי הנוכחית:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "שם משתמש" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "סיסמה" # מרשתת -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "חיבור אינטרנט:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "חבר אותי אוטומטית" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "מידע התחברות" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "ברוך בואך !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "כל המשתמשים" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "משתמשים מקוונים" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "‫ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "ערוץ סיב" # משתמט -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "ברירת מחדל" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1577,7 +1594,7 @@ msgstr "" msgid "Outgoing call" msgstr "קריאה יוצאת" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "מוכן" @@ -1636,11 +1653,11 @@ msgstr "מקושר." msgid "Call aborted" msgstr "קריאה בוטלה" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "לא ניתן להשהות את השיחה" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "משהה כעת שיחה נוכחית..." @@ -1747,40 +1764,40 @@ msgstr "" "זו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" # בשם כ־ -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "לא ניתן להתחבר בזהות %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "צלצול מרוחק." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "צלצול מרוחק..." # A SIP state -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "מדיה מוקדמת." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "שיחה עם %s מושהית." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "קריאה נענתה על ידי %s - בהמתנה." # renewed -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "קריאה חודשה." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "קריאה נענתה על ידי %s." @@ -1788,89 +1805,89 @@ msgstr "קריאה נענתה על ידי %s." # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "חוסר תאימות, נא לבדוק קודקים..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "חזרנו..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" # באופן מרוחק -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "שיחה עודכנה מרחוק..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "קריאה הסתיימה." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "משתמש עסוק כעת." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "משתמש לא זמין זמנית." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "משתמש לא מעוניין שיפריעו לו." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "קריאה סורבה." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "אין תגובה." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "שגיאת פרוטוקול." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "מכוון מחדש" # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 #, fuzzy msgid "Incompatible media parameters." msgstr "חוסר תאימות, נא לבדוק קודקים..." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "קריאה נכשלה." # הרשמה אצל %s הושלמה בהצלחה. -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "רישום אצל %s הושלם בהצלחה." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "אי רישום אצל %s סוים." # Pas de réponse # no response in defined time -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "אין היענות תוך זמן מוגדר" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "רישום אצל %s נכשל: %s" @@ -1881,13 +1898,16 @@ msgid "Authentication token is %s" msgstr "אות האימות הינה %s" # האם כדאי לחקות את הטלפונים הניידים? שיחות של נענו -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "החמצת שיחה %i." msgstr[1] "החמצת %i שיחות." +#~ msgid "label" +#~ msgstr "תוויות" + #~ msgid "by %s" #~ msgstr "מאת %s" diff --git a/po/hu.po b/po/hu.po index 54f7821a5..256e7ffba 100644 --- a/po/hu.po +++ b/po/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2013-03-26 19:00+0100\n" "Last-Translator: Viktor \n" "Language-Team: \n" @@ -17,53 +17,75 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" "Plural-Forms: nplurals=1; plural=1 == 1 ? 0 : 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "%s hívása" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Szöveg küldése a következőnek: %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "vonalban" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "-" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 msgid "Aborted" msgstr "Megszakítva" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "Nem fogadott" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 msgid "Declined" msgstr "Elutasítva" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i perc" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i másodperc" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" -msgstr "" -"%s\t%s\tMinőség: %s\n" -"%s\t%s %s\t" - -#: ../gtk/calllogs.c:108 -#, c-format -msgid "" -"%s\t%s\t\n" -"%s\t%s" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\t\n" "%s\t%s" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:323 +#, fuzzy, c-format +msgid "" +"%s\tQuality: %s\n" +"%s\t%s\t" +msgstr "" +"%s\t%s\tMinőség: %s\n" +"%s\t%s %s\t" + +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\t\n" +"%s\t%s" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Konferencia" @@ -76,31 +98,35 @@ msgstr "én" msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Érvénytelen sip partner !" + +#: ../gtk/main.c:92 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:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "fájl elérési útja, melybe a naplók kerülnek." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "Linphone indítása, videó kikpacsolva. " -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Csak a tálcaikon indítása, ne mutassa a fő ablakot." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Cím azonnali híváshoz" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Bekapcsolva automatikusan válaszol a bejövő hívásokra" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -108,12 +134,12 @@ 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Hívás %s -el" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -126,7 +152,7 @@ msgstr "" "szeretné adni a partnerlistához?\n" "Ha nemmel válaszol, ez a személy átmenetileg tiltólistára kerül." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -135,59 +161,59 @@ msgstr "" "Kérem, adja meg jelszavát a következő felhasználónévhez: %s\n" "tartomány %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Hívás fogadása" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Elutasítás" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Hívás várakoztatva" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, c-format msgid "by %s" msgstr "a következő által: %s" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s szerené elidítani a videót. Elfogadja?" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Internetes oldal" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - internetes videó telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Alapértelmezett)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Át vagyunk irányítva ide: %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -195,60 +221,51 @@ 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Hozzáadás címjegyzékhez" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Jelenlét státusz" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Név" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Hivás" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "Csevegés" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Keresés ebben a könyvtárban: %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Érvénytelen sip partner !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "%s hívása" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Szöveg küldése a következőnek: %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Kapcsolatinformációk szerkesztése: '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "'%s' partner törlése" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Új partner hozzáadása ebből a könyvtárból: %s" @@ -349,22 +366,26 @@ msgstr "norvég" msgid "Hebrew" msgstr "héber" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Nincs" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -610,105 +631,105 @@ msgstr "" msgid "%.3f seconds" msgstr "%.3f másodperc" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Befejezés" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Hívás folyamatban..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "jó" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "közepes" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "gyenge" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "nagyon gyenge" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "rossz" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "nem elérhető" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "SRTP-vel titkosítva" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Beállítás ellenőrizetlenként" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Beállítás ellenőrzöttként" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "Konferencián" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "vonalban" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Várakoztatott hívás" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Hívás vége." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "Átvitel folyamatban" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "Átvitel befejezve." -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 msgid "Transfer failed." msgstr "Az átvitel sikertelen." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Visszatérés" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Várakoztatás" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" @@ -717,7 +738,7 @@ msgstr "" "Felvétel a következőbe\n" "%s %s" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "(Várakoztatva)" @@ -738,155 +759,151 @@ msgstr "Küld" msgid "End conference" msgstr "Konferencia vége" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "címke" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "Beszélgetés felvétele hangfájlba" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "Videó" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "Elnémítás" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Átvitel" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "vonalban" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Időtartam" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Hívásminőség" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Beállítások" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "Videó indítása mindig" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Saját nézet" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Segítség" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Hibakeresési ablak mutatása" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Honlap" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Frissítések keresése" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Fiók varázsló" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Adja meg a SIP címet vagy a telefonszámot:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Új hívás kezdeményezése" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Partnerek" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Hozzáadás" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Szerkesztés" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Keresés" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Partnerek hozzáadása könyvtárból" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Partner hozzáadása" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Legutóbbi hívások" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Jelenlegi identitásom:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Felhasználónév" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Jelszó" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet kapcsolat:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Jelentkeztessen be automatikusan" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Bejelentkezési információ" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Üdvözöljük !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Minden felhasználó" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Elérhető" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber csatorna" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Alapértelmezett" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "Törlés" @@ -1489,7 +1506,7 @@ msgstr "" msgid "Outgoing call" msgstr "Kimenő hívás" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Kész" @@ -1544,11 +1561,11 @@ msgstr "Kapcsolódva." msgid "Call aborted" msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Jelenlegi hívás várakoztatásának aktiválása..." @@ -1649,115 +1666,115 @@ msgstr "" "Így kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:" "aladar@pelda.hu" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Nem sikerült belépni ezzel: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Távoli csengés." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Távoli csengés..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Korai médiák." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "A hívás a következővel: %s várakoztatva" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "%s fogadta a hívást - várakoztatva." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Hívás visszatért" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "%s válaszolt a hívásra." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 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:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "Visszatértünk." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "Megállítva a másik fél által." -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "A hívás távolról frissítve." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "A hívás befejezve." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "A felhasználó foglalt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "A felhasználó ideiglenesen nem elérhető" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "A felhasználó nem akarja, hogy zavarják." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Hívás elutasítva" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Nincs válasz." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokol hiba." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Átirányítva" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "Nem kompatibilis médiajellemzők." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Nem sikerült a hívás." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "A kiregisztrálás kész a következőn: %s ." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "időtúllépés után nincs válasz" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" @@ -1767,12 +1784,15 @@ msgstr "A regisztáció a %s -n nem sikerült: %s" msgid "Authentication token is %s" msgstr "Hitelesítési jel: %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Van %i nem fogadott hivás." +#~ msgid "label" +#~ msgstr "címke" + #~ msgid "Chat with %s" #~ msgstr "Chat-elés %s -el" diff --git a/po/it.po b/po/it.po index 9e9a1183d..f1c29e8b0 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" "Last-Translator: Matteo Piazza \n" "Language-Team: it \n" @@ -15,54 +15,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Chiamata %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Invia testo a %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "In chiamata con" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "annullato" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "mancante" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Rifiuta" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -78,42 +98,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Contatto SIP non valido" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat con %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -125,128 +149,119 @@ msgstr "" "veda il tuo stato o aggiungerlo alla tua lista dei contatti Se rispondi no " "questo utente sarà momentaneamente bloccato." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, 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:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Cronologia" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Chiamata terminata" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Rifiuta" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "annullato" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porte" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Presenza" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Chiamata %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Cerca contatti nella directory %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Contatto SIP non valido" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Chiamata %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Invia testo a %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Modifica contatto %s" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Elimina contatto %s" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Aggiungi nuovo contatto dalla directory %s" @@ -347,20 +362,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -612,117 +631,117 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Linguaggio" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "In chiamata con" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Termina chiamata" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Chiamata terminata." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Chiamata rifiutata" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -744,167 +763,163 @@ msgstr "Invia" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etichetta" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "In chiamata" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Durata" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Self-view abilitato" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone debug window" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Configuratore di account" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Indirizzo sip o numero." -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "In connessione" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Aggiungi" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Edita" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Trovato %i contatto" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "In chiamata" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Identità corrente" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Username" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Password" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Connessione Internet:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Login Automatico" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Credenziali di accesso" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Benvenuto !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "Tutti gli utenti\n" "Utenti Online" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fibra Ottica" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Default" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1521,7 +1536,7 @@ msgstr "" msgid "Outgoing call" msgstr "Chiamata in uscita" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Pronto" @@ -1580,12 +1595,12 @@ msgstr "Connessione" msgid "Call aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Mostra chiamata corrente" @@ -1686,118 +1701,118 @@ msgstr "" "L'identità sip utilizza è invalida.\n" "Dovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "impossibile login come %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat con %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Chiamata terminata" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Chiamata terminata." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Utente occupato" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Utente non disponibile" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "L'utente non vuole essere disturbato" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 #, fuzzy msgid "No response." msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Rediretto verso %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrazione su %s attiva" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Unregistrazione su %s" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrazione su %s fallita: %s" @@ -1807,13 +1822,16 @@ msgstr "Registrazione su %s fallita: %s" msgid "Authentication token is %s" msgstr "Linphone - Autenticazione richiesta" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" msgstr[1] "" +#~ msgid "label" +#~ msgstr "etichetta" + #~ msgid "Chat with %s" #~ msgstr "Chat con %s" diff --git a/po/ja.po b/po/ja.po index e95879bb8..668018fd1 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2003-01-21 00:05+9000\n" "Last-Translator: YAMAGUCHI YOSHIYA \n" "Language-Team: \n" @@ -17,53 +17,73 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "接続中" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "通話はキャンセルされました。" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "ライン入力" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -76,42 +96,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -120,132 +144,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "通話は拒否されました。" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "ライン入力" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "接続中" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "電話帳" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "状態" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名前" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "通話はキャンセルされました。" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(接続するための情報がありません!)" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -346,21 +361,25 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "ありません。" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -606,118 +625,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "接続中" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "接続中" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "接続中" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "通話は拒否されました。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -740,170 +759,166 @@ msgstr "サウンド" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "情報" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "使用する" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "レジストラサーバーのSIPアドレス" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "接続中" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "追加する" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "コーデックの情報" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "(接続するための情報がありません!)" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "接続中" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "個人情報" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "ユーザーマニュアル" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "パスワード" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "コーデックの情報" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "接続中" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "ライン入力" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "個人情報" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1527,7 +1542,7 @@ msgstr "" msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "準備完了。" @@ -1589,11 +1604,11 @@ msgstr "接続しました。" msgid "Call aborted" msgstr "通話はキャンセルされました。" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1693,121 +1708,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "登録中……" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "登録中……" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "電話をかける\n" "電話に出る" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "ユーザーはビジーです" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "ユーザーは、今出られません。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "ユーザーは手が離せないようです。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "通話はキャンセルされました。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "登録しました。" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "登録しました。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "登録しました。" @@ -1817,7 +1832,7 @@ msgstr "登録しました。" msgid "Authentication token is %s" msgstr "コーデックの情報" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/nb_NO.po b/po/nb_NO.po index c1500d304..8b7f20c28 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-04-05 01:56+0200\n" "Last-Translator: Øyvind Sæther \n" "Language-Team: Norwegian Bokmål \n" @@ -17,54 +17,74 @@ msgstr "" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Ring %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Send tekst til %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "I samtale med" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "avbrutt" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "ubesvart" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Avvis" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -78,31 +98,35 @@ msgstr "Skru mikrofonen av" msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Ugyldig SIP kontakt !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "skriv logg-informasjon under kjøring" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Start skjult i systemkurven, ikke vis programbildet." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "address som skal ringes nå" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "besvarer innkommende samtaler automatisk om valgt" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -110,12 +134,12 @@ msgstr "" "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:" "\\Programfiler\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Ring med %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -128,7 +152,7 @@ msgstr "" "din kontaktliste?\n" "Hvis du svarer nei vil personen bli svartelyst midlertidig." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -137,61 +161,61 @@ msgstr "" "Skriv inn ditt passord for brukernavn %s\n" " på domene %s:i>:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Samtalehistorikk" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Svarer" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avvis" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Samtale avbrutt" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Porter" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Peker til nettsted" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Standard)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Vi er overført til %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -199,61 +223,52 @@ msgstr "" "Klarte ikke å finne noe lydkort på denne datamaskinen.\n" "Du vil ikke kunne sende eller motta lydsamtaler." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Tilstedestatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Navn" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Ring %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Søk i %s katalogen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Ugyldig SIP kontakt !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Ring %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Send tekst til %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Rediger kontakt '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Slett kontakt '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Legg til kontakt fra %s katalogen" @@ -354,20 +369,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -620,114 +639,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "I samtale med" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Pauset samtale" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Samtale avsluttet." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Overfører" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Overfører" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Fortsett" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Pause" @@ -750,157 +769,153 @@ msgstr "Send" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Overfører" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "I samtale" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Varighet" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Alternativer" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Vis video av deg selv" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Hjelp" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Vis avlusningsvindu" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "H_jemmeside" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Sjekk _Oppdateringer" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Sip adresse eller telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Start en ny samtale" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Kontakter" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Legg til" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Rediger" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Søk" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Legg til kontakter fra katalogen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Legg til kontakt" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "I samtale" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Min nåværende identitet:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Brukernavn" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passord" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet forbindelse:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Logg meg på automatisk" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Innlogginsinformasjon" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Velkommen!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Alle brukere" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Tilkoblede brukere" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Fiber Kanal" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Standard" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1514,7 +1529,7 @@ msgstr "" msgid "Outgoing call" msgstr "Utgående samtale" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Klar" @@ -1570,11 +1585,11 @@ msgstr "Tilkoblet" msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" @@ -1676,116 +1691,116 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Ikke ikke logge inn som %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Tidlig media" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Samtalen med %s er pauset." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Samtale besvart av %s - på vent." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Samtale gjenopptatt." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Samtale besvart av %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Vi har blitt gjenopptatt..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Samtale avsluttet." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Brukeren er opptatt." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Brukeren er midlertidig ikke tilgjengelig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Brukeren vil ikke bli forstyrret." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Samtale avvist." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Ikke noe svar." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Protokollfeil." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Omdirigert" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Samtale feilet." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lykkes." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lykkes." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "ingen svar innen angitt tid" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislykkes: %s" @@ -1795,13 +1810,16 @@ msgstr "Registrering hos %s mislykkes: %s" msgid "Authentication token is %s" msgstr "Autorisering kreves" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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 "label" +#~ msgstr "etikett" + #~ msgid "Keypad" #~ msgstr "Tastatur" diff --git a/po/nl.po b/po/nl.po index 926bd7bb6..8cfe7febd 100644 --- a/po/nl.po +++ b/po/nl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: nl\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2007-09-05 10:40+0200\n" "Last-Translator: Hendrik-Jan Heins \n" "Language-Team: Nederlands \n" @@ -19,54 +19,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, fuzzy, c-format +msgid "Call %s" +msgstr "Oproepgeschiedenis" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Contactlijst" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "afgebroken" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "gemist" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "lijn" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -79,42 +99,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat met %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -123,131 +147,122 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Linphone - Oproepgeschiedenis" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Oproep beeindigd" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "lijn" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "afgebroken" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Contactlijst" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Een Vrije SIP video-telefoon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Adresboek" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Aanwezigheidsstatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Naam" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Oproepgeschiedenis" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Chat box" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Oproepgeschiedenis" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Bewerk contactgegevens" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Geen" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -609,118 +628,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Contactlijst" -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Oproep beeindigd" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -743,173 +762,169 @@ msgstr "Geluid" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Inkomende oproep" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informatie" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Video aan" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "_Help" msgstr "Help" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Geef het SIP adres of telefoonnummer in" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Verbinden" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Adres" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Bewerken" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Contact informatie" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Bewerk contactgegevens" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Inkomende oproep" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "SIP-identiteit:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "gebruikersnaam:" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "wachtwoord:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Automatically log me in" msgstr "Automatisch een geldige hostnaam raden" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Contact informatie" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Contactlijst" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "Aanwezig" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "SIP-identiteit:" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1543,7 +1558,7 @@ msgstr "" msgid "Outgoing call" msgstr "Uitgaande oproep" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Gereed." @@ -1602,12 +1617,12 @@ msgstr "Verbonden." msgid "Call aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Kon niet oproepen" @@ -1709,121 +1724,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat met %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Oproep beeindigd" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Oproepen of\n" "beantwoorden" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Oproep beeindigd." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Gebruiker is bezet." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Gebruiker is tijdelijk niet beschikbaar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "De gebruiker wenst niet gestoord te worden." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Oproep geweigerd." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Doorgeschakeld naar %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Oproep geannuleerd." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registratie op %s mislukt (time-out)." @@ -1833,7 +1848,7 @@ msgstr "Registratie op %s mislukt (time-out)." msgid "Authentication token is %s" msgstr "Authorisatie gegevens" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pl.po b/po/pl.po index 7999a657d..4512b7230 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2003-08-22 12:50+0200\n" "Last-Translator: Robert Nasiadek \n" "Language-Team: Polski \n" @@ -15,53 +15,73 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Dzwonie do " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "Połączenie odwołane." -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "linia" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -74,42 +94,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -118,132 +142,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Rozmowa odrzucona." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linia" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Dzwonie do " -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Książka adresowa" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 #, fuzzy msgid "Presence status" msgstr "Obecność" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nazwa" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Połączenie odwołane." -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -344,21 +359,25 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 #, fuzzy msgid "None" msgstr "Brak." -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -604,118 +623,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Dzwonie do " -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Rozmowa odrzucona." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -738,171 +757,167 @@ msgstr "Dźwięk" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informacja" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Włączone" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "SIP address or phone number:" msgstr "Adres serwera rejestracji sip" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Adres" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Informacje o kodeku" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Tożsamość" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Podręcznik" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Twoje hasło:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Informacje o kodeku" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "linia" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Tożsamość" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1526,7 +1541,7 @@ msgstr "" msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Gotowy." @@ -1586,11 +1601,11 @@ msgstr "Połączony" msgid "Call aborted" msgstr "Połączenie odwołane." -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1690,121 +1705,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Zadzwoń lub\n" "Odpowiedz" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 #, fuzzy msgid "Call terminated." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Osoba jest zajęta." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Osoba jest tymczasowo niedostępna." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Osoba nie chce, aby jej przeszkadzać." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Połączenie odwołane." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Rejestracja powiodła się." @@ -1814,7 +1829,7 @@ msgstr "Rejestracja powiodła się." msgid "Authentication token is %s" msgstr "Informacje o kodeku" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pt_BR.po b/po/pt_BR.po index 9cd72ea90..821ba910f 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-1.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2006-07-11 23:30+0200\n" "Last-Translator: Rafael Caesar Lenzi \n" "Language-Team: pt_BR \n" @@ -17,54 +17,74 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, fuzzy, c-format +msgid "Call %s" +msgstr "Histórico de chamadas" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Contatando " + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "Abortado" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "Perdido" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "linha" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,42 +97,46 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, fuzzy, c-format msgid "Call with %s" msgstr "Bate-papo com %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -121,132 +145,123 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Linphone - Histórico de chamadas" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 #, fuzzy msgid "Call ended" msgstr "Chamada cancelada." -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linha" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "Abortado" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Contatando " -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 #, fuzzy msgid "Add to addressbook" msgstr "Catálogo de endereços" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Status de presença" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Histórico de chamadas" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Sala de bate-papo" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk/friendlist.c:807 -#, fuzzy, c-format -msgid "Call %s" -msgstr "Histórico de chamadas" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Edicar informação de contato" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, c-format +msgid "Delete chat history of '%s'" +msgstr "" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "" @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Nenhum" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -608,118 +627,118 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 #, fuzzy msgid "Calling..." msgstr "Contatando " -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "Contatando " -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Contatando " -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 #, fuzzy msgid "Call ended." msgstr "Chamada cancelada." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -742,171 +761,167 @@ msgstr "Som" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 #, fuzzy msgid "In call" msgstr "Camadas recebidas" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 #, fuzzy msgid "Duration" msgstr "Informações" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 #, fuzzy msgid "Enable self-view" msgstr "Ativado" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Contatando " -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 #, fuzzy msgid "Add" msgstr "Endereço" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editar" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contacts from directory" msgstr "Informação de contato" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Edicar informação de contato" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "Camadas recebidas" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 #, fuzzy msgid "My current identity:" msgstr "Identificação SIP:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Usuário" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Senha:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Automatically log me in" msgstr "Adquirir automaticamente um nome de servidor válido." -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" msgstr "Informação de contato" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 #, fuzzy msgid "Welcome !" msgstr "Contatando " -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "linha" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "Identificação SIP:" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1535,7 +1550,7 @@ msgstr "" msgid "Outgoing call" msgstr "Chamadas efetuadas" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 #, fuzzy msgid "Ready" msgstr "Pronto." @@ -1594,11 +1609,11 @@ msgstr "Conectado." msgid "Call aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1688,121 +1703,121 @@ msgid "" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 #, fuzzy msgid "Remote ringing." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Bate-papo com %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Chamada cancelada." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Ligar ou\n" "atender" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Usuário está ocupado." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Usuário está temporáriamente indisponível." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Redirecionado para %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Histórico de chamadas" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registro falhou (tempo esgotado)." @@ -1812,7 +1827,7 @@ msgstr "Registro falhou (tempo esgotado)." msgid "Authentication token is %s" msgstr "Informações de autenticação" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/ru.po b/po/ru.po index a7fd4a832..66419e69a 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2010-01-22 18:43+0300\n" "Last-Translator: Maxim Prokopyev \n" "Language-Team: Russian \n" @@ -17,26 +17,41 @@ msgstr "" "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:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Набрать %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Послать текст к %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "Соединен с" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "отмененный" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "пропущенный" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Отклонить" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -44,7 +59,7 @@ msgstr[0] "%i минута" msgstr[1] "%i минуты" msgstr[2] "%i минут" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -52,25 +67,32 @@ msgstr[0] "%i секунда" msgstr[1] "%i секунды" msgstr[2] "%i секунд" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tКачество: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Конференция" @@ -83,33 +105,37 @@ msgstr "Я" msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Неверный sip-контакт!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "" "Вывод некоторой отладочной информации на устройство стандартного вывода во " "время работы" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "путь к файлу для записи журнала работы." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Запускать только в системном лотке, не показывая главное окно" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "адрес для звонка" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "автоматически принимать входящие вызовы, если включено" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -117,12 +143,12 @@ msgstr "" "Укажите рабочий каталог (должен содержать установленные файлы приложения, " "например: c:\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Чат с %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -135,7 +161,7 @@ msgstr "" "его(её) в свой контактный лист?\n" "Если вы ответите Нет, этот человек будет временно заблокирован." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -144,59 +170,59 @@ msgstr "" "Пожалуйста, введите пароль для пользователя %s\n" " в домене %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Ошибка вызова" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Разговор окончен" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Ответить" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Отклонить" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Вызов приостановлен" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Порты" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Ссылка на сайт" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - видео-телефон для интернета" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (По умолчанию)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Мы переведены на %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -204,61 +230,52 @@ msgstr "" "На этом компьютере не обнаружено ни одной звуковой карты.\n" "Вы не сможете совершать или принимать аудио-вызовы." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Свободный SIP видео-телефон" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Добавить в адресную книгу" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Статус присутствия" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Имя" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Вызов" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 #, fuzzy msgid "Chat" msgstr "Комната чата" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Поиск в директории %s" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Неверный sip-контакт!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Набрать %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Послать текст к %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Редактировать контакт '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Удалить контакт '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Добавить новый контакт из директории '%s'" @@ -359,22 +376,26 @@ msgstr "Норвежский" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Вы должны перезапустить Linphone для того, чтобы языковые настройки вступили " "в силу." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Нет" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ZRTP" @@ -627,114 +648,114 @@ msgstr "" msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Вызов..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "хорошее" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "среднее" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "плохое" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "очень плохое" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "слишком плохое" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Защищено SRTP" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Защищено ZRTP - [токен: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Не проверен" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверен" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "В конференции" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "Соединен с" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Приостановленный вызов" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Звонок закончен." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Перевести" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Перевести" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Продолжить" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Пауза" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Пауза" @@ -757,155 +778,151 @@ msgstr "Отправить" msgid "End conference" msgstr "В конференции" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "метка" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Перевести" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Вызов" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Продолжительность" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Уровень качества звонка" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Настройки" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Включить своё видео" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "_Помощь" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Показать окно отладки" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Домашняя страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Проверить _Обновления" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 msgid "Account assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP-адрес или номер телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Совершить новый вызов" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Контакты" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Добавить" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Редактировать" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Поиск" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Добавить контакты из директории" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Добавить контакт" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Недавние вызовы" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Мой текущий идентификатор:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Имя пользователя" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Пароль" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Интернет-соединение:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Входить автоматически" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Информация для входа" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Добро пожаловать!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Все пользователи" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Пользователи в сети" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Оптоволокно" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "По умолчанию" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1522,7 +1539,7 @@ msgstr "" msgid "Outgoing call" msgstr "Исходящий звонок" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Готов" @@ -1578,11 +1595,11 @@ msgstr "Соединён." msgid "Call aborted" msgstr "Вызов отменён" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Не удалось приостановить вызов" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Приостановление текущего вызова..." @@ -1685,118 +1702,118 @@ msgstr "" "Они должны выглядеть как sip:username@proxydomain, например such as sip:" "alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Невозможно зайти как %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Абонент вызывается." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Абонент вызывается..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Гудки." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Вызов %s приостановлен." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Вызов отвечен %s - в ожидании." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Разговор продолжен." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "Вызов отвечен %s." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Наш вызов продолжен..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Вызов обновлён вызываемым абонентом..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Звонок прерван." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Пользователь занят." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Пользователь временно недоступен." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Абонент не хочет отвечать." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Звонок отклонён." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Нет ответа." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Ошибка протокола." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Переадресован" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 #, fuzzy msgid "Incompatible media parameters." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Не удалось совершить вызов." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Регистрация на %s прошла успешно." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Отмена регистрации на %s завершена." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "время ожидания истекло" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Регистрация на %s не удалась: %s" @@ -1806,7 +1823,7 @@ msgstr "Регистрация на %s не удалась: %s" msgid "Authentication token is %s" msgstr "Аутентификационный токен: %s" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1814,6 +1831,9 @@ msgstr[0] "У вас пропущен %i звонок." msgstr[1] "У вас пропущено %i звонка." msgstr[2] "У вас пропущено %i звонков." +#~ msgid "label" +#~ msgstr "метка" + #~ msgid "by %s" #~ msgstr "со стороны: %s" diff --git a/po/sr.po b/po/sr.po index 4a465ec8e..814b4d050 100644 --- a/po/sr.po +++ b/po/sr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2013-02-11 19:03+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" @@ -16,26 +16,41 @@ msgstr "" "Plural-Forms: nplurals=4; plural=n==1? 3 : 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:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Позови „%s“" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Пошаљи текст за %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "У позиву" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "прекинути" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "пропуштени" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Одбиј" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -44,7 +59,7 @@ msgstr[1] "%i минута" msgstr[2] "%i минута" msgstr[3] "Један минут" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -53,25 +68,32 @@ msgstr[1] "%i секунде" msgstr[2] "%i секунде" msgstr[3] "Једна секунда" -#: ../gtk/calllogs.c:103 -#, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#, fuzzy, c-format +msgid "%s\t%s" msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, fuzzy, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, fuzzy, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" +"%s\t%s\tКвалитет: %s\n" +"%s\t%s %s\t" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Конференција" @@ -84,31 +106,35 @@ msgstr "Ја" msgid "Couldn't find pixmap file: %s" msgstr "Не могу да пронађем датотеку сличице: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "Неисправан сип контакт !" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "бележи у стандардни излаз неке податке за уклањање грешака док ради." -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "путања до датотеке за уписивање бележака." -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "адреса за позивање управо сада" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "ако је подешено сам ће се јављати на долазне позиве" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -116,12 +142,12 @@ msgstr "" "Наводи радни директоријум (треба да буде основа инсталације, нпр: c:" "\\Program Files\\Linphone)" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Позив са корисником %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -134,7 +160,7 @@ msgstr "" "на ваш списак пријатеља ?\n" "Ако одговорите са не, ова особа ће привремено бити стављена на црни списак." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -143,59 +169,59 @@ msgstr "" "Унесите вашу лозинку за корисничко име %s\n" " на домену %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 msgid "Call error" msgstr "Грешка позива" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Позив је завршен" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Јави се" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Одбиј" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 msgid "Call paused" msgstr "Позив је заустављен" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Кодеци" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Веза веб сајта" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Линфон — интернет телефон са снимком" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (основно)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Преселили смо се на %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -203,60 +229,51 @@ msgstr "" "Ниједна звучна картица није откривен ана овом рачунару.\n" "Нећете бити у могућности да шаљете или да примате звучне позиве." -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "Слободан СИП телефон са снимком" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "Додајте у адресар" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Стање присуства" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Име" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 msgid "Call" msgstr "Позови" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Тражи у директоријуму „%s“" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "Неисправан сип контакт !" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Позови „%s“" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Пошаљи текст за %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Уредите контакт „%s“" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Обришите контакт „%s“" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Додајте нови контакт из директоријума „%s“" @@ -357,21 +374,25 @@ msgstr "Норвешки" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Трба поново да покренете линфон да би нови изабрани језик ступио на снагу." -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "Ништа" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "СРТП" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "ЗРТП" @@ -626,114 +647,114 @@ msgstr "" msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Позивам..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "добро" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "просечно" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "оскудно" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "јадно" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "много лоше" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "Осигурано СРТП-ом" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "Непроверено подешавање" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверено подешавање" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "На конференцији" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "У позиву" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "Заустављен позив" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Позив је завршен." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "Пребаци" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Пребаци" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "Настави" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Застани" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "Застани" @@ -756,156 +777,152 @@ msgstr "Пошаљи" msgid "End conference" msgstr "На конференцији" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "натпис" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "Пребаци" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "Долазни позив" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Трајање" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "Оцена квалитета позива" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "_Могућности" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Укључи самовиђење" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "По_моћ" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "Прикажи прозорче прочишћавања" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "_Матична страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "Провери _ажурирања" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "СИП адреса или број телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "Започните нови позив" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "Пријатељи" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Додај" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Уреди" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Тражи" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Додај пријатеље из директоријума" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "Додај пријатеља" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "Recent calls" msgstr "Скорашњи позиви" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Мој тренутни идентитет:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Корисничко име" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Лозинка" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Интернет веза:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Сам ме пријави" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Подаци пријављивања" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Добродошли !" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Сви корисници" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "Корисницима на мрежи" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "АДСЛ" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "Оптички канал" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "Основно" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1517,7 +1534,7 @@ msgstr "" msgid "Outgoing call" msgstr "Одлазни позив" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Спреман" @@ -1573,11 +1590,11 @@ msgstr "Повезан сам." msgid "Call aborted" msgstr "Позив је прекинут" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Не могу да зауставим позив" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Заустављам тренутни позив..." @@ -1678,116 +1695,116 @@ msgstr "" "Треба да изгледа као „sip:корисник@домен-посредника, као што је „sip:" "alice@example.net“" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Не могу да се пријавим као %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Удаљено звоњење." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "Удаљено звоњење..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Ранији медиј." -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "Позив са „%s“ је заустављен." -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "Позив на који је одговорио „%s“ — на чекању." -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "Позив је настављен." -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "На позив је одговорио „%s“." -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "Позив нам је настављен..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 #, fuzzy msgid "Call is updated by remote." msgstr "Позив је ажуриран удаљеним..." -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Позив је завршен." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Корисник је заузет." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Корисник је привремено недоступан." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Корисник не жели да буде узнемираван." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Позив је одбијен." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "Нема одговора." -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "Грешка у протоколу." -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "Преусмерен" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "Позив није успео." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Уписивање на „%s“ је успело." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Исписивање са „%s“ је обављено." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "нема ограничења одговора" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Уписивање на „%s“ није успело: %s" @@ -1797,7 +1814,7 @@ msgstr "Уписивање на „%s“ није успело: %s" msgid "Authentication token is %s" msgstr "Симбол потврђивања идентитета је „%s“" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1806,6 +1823,9 @@ msgstr[1] "Пропустили сте %i позива." msgstr[2] "Пропустили сте %i позива." msgstr[3] "Пропустили сте један позив." +#~ msgid "label" +#~ msgstr "натпис" + #~ msgid "Chat with %s" #~ msgstr "Ћаскајте са „%s“" diff --git a/po/sv.po b/po/sv.po index 0b2882efc..4f7ec762c 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2009-02-17 15:22+0100\n" "Last-Translator: Emmanuel Frécon \n" "Language-Team: SWEDISH \n" @@ -16,54 +16,74 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "Ringer %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "Skicka text till %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "I samtal med" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "avbrytade" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "missade" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "Avböj" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,31 +97,35 @@ msgstr "Mikrofon av" msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "ogiltig SIP kontakt!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "skriv loggning information under körning" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "Starta ikonifierat, visa inte huvudfönstret" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "Samtalsmottagare" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "Om på, besvara automatisk alla inkommande samtal" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -109,12 +133,12 @@ msgstr "" "Välj en arbetskatalog som ska vara basen för installationen, såsom C:" "\\Program\\Linphone" -#: ../gtk/main.c:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "Samtal med %s" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -127,7 +151,7 @@ msgstr "" "henne till din kontaktlista?\n" "Om du svarar nej, personen kommer att vara bannlyst." -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -136,121 +160,112 @@ msgstr "" "Mata in ditt lösenord för användaren %s\n" "vid domänen %s:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "Samtalshistorik" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avböj" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "avbrytade" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "Portar" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "Webbsajt" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 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:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "Närvarostatus" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Namn" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "Ringer %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "Sök i %s katalogen" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "ogiltig SIP kontakt!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "Ringer %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "Skicka text till %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "Ändra kontakt '%s'" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "Ta bort kontakt '%s'" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "Lägg till kontakt ifrån %s katalogen" @@ -351,20 +366,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 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:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -616,116 +635,116 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "I samtal med" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "Lägg på" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "Samtalet slut." -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -747,169 +766,165 @@ msgstr "Skicka" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "etikett" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "I samtal" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "Förlopp" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "Själv bild" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone debug fönster" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "_Homepage" msgstr "Hemsidan" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Check _Updates" msgstr "Letar efter uppdateringar" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "Användarnamn" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 #, fuzzy msgid "Contacts" msgstr "Kontaktar" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Lägg till" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editera" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "Sök" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "Lägg till kontakt ifrån katalogen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "Hittat kontakt %i" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "I samtal" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "Min nuvarande identitet" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Användarnamn" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Lösenord" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "Internet förbindelse:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "Logga mig automatiskt" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Login information" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "Välkommen!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "Alla användare\n" "Online användare" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fiber" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 #, fuzzy msgid "Default" msgstr "%s (Default)" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1519,7 +1534,7 @@ msgstr "" msgid "Outgoing call" msgstr "Utgående samtal" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Redo" @@ -1578,12 +1593,12 @@ msgstr "Kopplad" msgid "Call aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 #, fuzzy msgid "Pausing the current call..." msgstr "Nuvarande samtal" @@ -1684,119 +1699,119 @@ 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:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "Kunde inte logga in som %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "Tidig media" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Samtal med %s" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "Samtalet slut" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "Samtalet slut." -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "Användare upptagen." -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "Användaren temporärt inte tillgänglig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "Användaren vill inte bli störd." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 #, fuzzy msgid "No response." msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 #, fuzzy msgid "Redirected" msgstr "Omdirigerat till %s..." -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 #, fuzzy msgid "Call failed." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lyckades." -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lyckades." -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislyckades: %s" @@ -1806,13 +1821,16 @@ msgstr "Registrering hos %s mislyckades: %s" msgid "Authentication token is %s" msgstr "Linphone - Autentisering krävs" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, 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 "label" +#~ msgstr "etikett" + #~ msgid "Chat with %s" #~ msgstr "Chatta med %s" diff --git a/po/zh_CN.po b/po/zh_CN.po index f03c496d8..7c81df3fc 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-01-08 23:51+0800\n" "Last-Translator: Aron Xu \n" "Language-Team: Chinese (simplified) \n" @@ -18,52 +18,72 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "呼叫 %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "发送消息给 %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "正在呼叫" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "中断" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "丢失" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "拒绝" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -77,42 +97,46 @@ msgstr "静音" msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "无效的 SIP 联系人!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "运行时向标准输出记录调试信息。" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "启动到系统托盘,不显示主界面。" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "现在呼叫的地址" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "是否设置呼叫自动应答" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "与 %s 通话" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -124,68 +148,68 @@ msgstr "" "您是否允许他看到您的在线状态或者将它加为您的联系人允许?\n" "如果您回答否,则会将该人临时性的放入黑名单" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" " at domain %s:" msgstr "请输入 %s@%s 的密码:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "呼叫历史" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "呼入" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒绝" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "中断" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "端口" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "网站" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - 互联网视频电话" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (默认)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -193,61 +217,52 @@ msgstr "" "未在此计算机上检测到声卡。\n" "您无法发送或接收音频呼叫。" -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "免费的 SIP 视频电话" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "在线状态" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名称" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "呼叫 %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "在 %s 目录中查找 " -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "无效的 SIP 联系人!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "呼叫 %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "发送消息给 %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "编辑联系人 %s" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "删除联系人 %s" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "从 %s 目录增加联系人 " @@ -348,20 +363,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重启 linphone 以使语言选择生效。" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -613,116 +632,116 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "正在呼叫..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 #, fuzzy msgid "Incoming call" msgstr "呼入" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 #, fuzzy msgid "In call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 #, fuzzy msgid "Paused call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "通话结束。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "呼叫失败。" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 msgid "(Paused)" msgstr "" @@ -744,167 +763,163 @@ msgstr "发送" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "标签" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "呼入" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "通话时间" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "启用自视" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Show debug window" msgstr "Linphone 调试窗口" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "_Homepage" msgstr "主页" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Check _Updates" msgstr "检查更新" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "帐户设置向导" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP 地址或电话号码:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "联系人" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "添加" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "编辑" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "搜索" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "从目录增加联系人" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Add contact" msgstr "找到 %i 联系方式" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "呼入" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "当前地址:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "用户名" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密码" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "网络连接:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "自动登录" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登录信息" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "欢迎!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 #, fuzzy msgid "Online users" msgstr "" "全部用户\n" "在线用户" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "光纤" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "默认" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1530,7 +1545,7 @@ msgstr "" msgid "Outgoing call" msgstr "呼出" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "就绪" @@ -1588,12 +1603,12 @@ msgstr "已连接。" msgid "Call aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 #, fuzzy msgid "Could not pause the call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "" @@ -1689,116 +1704,116 @@ msgstr "" "您输入的地址无效。\n" "它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "无法登录为 %s" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "响铃。" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 #, fuzzy msgid "Remote ringing..." msgstr "响铃。" -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "与 %s 通话" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 #, fuzzy msgid "Call resumed." msgstr "呼叫结束" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "通话结束。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "被叫正忙。" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "您呼叫的用户暂时无法接通。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "用户已开启免打扰功能。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "呼叫被拒绝。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "没有响应。" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "协议错误。" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "已重定向" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "呼叫失败。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "成功注册到 %s" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "已在 %s 解除注册。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "没有响应,超时" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "注册到 %s 失败: %s" @@ -1808,12 +1823,15 @@ msgstr "注册到 %s 失败: %s" msgid "Authentication token is %s" msgstr "Linphone - 需要认证" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您错过了 %i 个呼叫。" +#~ msgid "label" +#~ msgstr "标签" + #~ msgid "Keypad" #~ msgstr "数字键盘" diff --git a/po/zh_TW.po b/po/zh_TW.po index c65dcb84f..d1b2ce1a7 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-03-07 12:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" "PO-Revision-Date: 2011-04-06 21:24+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: \n" @@ -17,52 +17,72 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:82 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#, c-format +msgid "Call %s" +msgstr "播打給 %s" + +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#, c-format +msgid "Send text to %s" +msgstr "傳送文字給 %s" + +#: ../gtk/calllogs.c:223 +#, fuzzy, c-format +msgid "Recent calls (%i)" +msgstr "通話中" + +#: ../gtk/calllogs.c:300 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:85 +#: ../gtk/calllogs.c:303 #, fuzzy msgid "Aborted" msgstr "已放棄" -#: ../gtk/calllogs.c:88 +#: ../gtk/calllogs.c:306 #, fuzzy msgid "Missed" msgstr "未接" -#: ../gtk/calllogs.c:91 +#: ../gtk/calllogs.c:309 #, fuzzy msgid "Declined" msgstr "拒接" -#: ../gtk/calllogs.c:97 +#: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:100 +#: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:103 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format -msgid "" -"%s\t%s\tQuality: %s\n" -"%s\t%s %s\t" +msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:108 +#: ../gtk/calllogs.c:323 #, c-format msgid "" -"%s\t%s\t\n" -"%s\t%s" +"%s\tQuality: %s\n" +"%s\t%s\t" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:14 +#: ../gtk/calllogs.c:329 +#, c-format +msgid "" +"%s\t\n" +"%s" +msgstr "" + +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "" @@ -76,43 +96,47 @@ msgstr "靜音" msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/main.c:88 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +msgid "Invalid sip contact !" +msgstr "無效的 sip 連絡人!" + +#: ../gtk/main.c:92 msgid "log to stdout some debug information while running." msgstr "執行時將一些除錯資訊記錄到標準輸出。" -#: ../gtk/main.c:95 +#: ../gtk/main.c:99 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:106 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." msgstr "只在系統匣啟動,不要顯示主要介面。" -#: ../gtk/main.c:116 +#: ../gtk/main.c:120 msgid "address to call right now" msgstr "現在要打電話的位址" -#: ../gtk/main.c:123 +#: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "如啟用此項,將會自動接聽來電" -#: ../gtk/main.c:130 +#: ../gtk/main.c:134 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:510 +#: ../gtk/main.c:515 #, c-format msgid "Call with %s" msgstr "和 %s 通話" -#: ../gtk/main.c:941 +#: ../gtk/main.c:946 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -124,7 +148,7 @@ msgstr "" "您是否要允許他看見您的上線狀態或將他加入您的連絡人清單?\n" "如果您回答否,這個人會被暫時列入黑名單。" -#: ../gtk/main.c:1018 +#: ../gtk/main.c:1023 #, c-format msgid "" "Please enter your password for username %s\n" @@ -133,61 +157,61 @@ msgstr "" "請輸入您使用者名稱 %s\n" "於網域 %s 的密碼:" -#: ../gtk/main.c:1121 +#: ../gtk/main.c:1126 #, fuzzy msgid "Call error" msgstr "通話紀錄" -#: ../gtk/main.c:1124 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1127 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "來電" -#: ../gtk/main.c:1129 ../gtk/incall_view.c:498 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "接聽" -#: ../gtk/main.c:1131 ../gtk/main.ui.h:7 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒接" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy msgid "Call paused" msgstr "通話已放棄" -#: ../gtk/main.c:1137 +#: ../gtk/main.c:1142 #, fuzzy, c-format msgid "by %s" msgstr "連接埠" -#: ../gtk/main.c:1186 +#: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1348 +#: ../gtk/main.c:1353 msgid "Website link" msgstr "網站連結" -#: ../gtk/main.c:1388 +#: ../gtk/main.c:1402 msgid "Linphone - a video internet phone" msgstr "Linphone - 網路視訊電話" -#: ../gtk/main.c:1480 +#: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" msgstr "%s (預設值)" -#: ../gtk/main.c:1782 ../coreapi/callbacks.c:806 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "我們被轉接到 %s" -#: ../gtk/main.c:1792 +#: ../gtk/main.c:1806 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -195,61 +219,52 @@ msgstr "" "在這臺電腦中偵測不到音效卡。\n" "您將無法傳送或接收語音電話。" -#: ../gtk/main.c:1896 +#: ../gtk/main.c:1911 msgid "A free SIP video-phone" msgstr "自由的 SIP 視訊電話" -#: ../gtk/friendlist.c:366 +#: ../gtk/friendlist.c:469 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:540 +#: ../gtk/friendlist.c:643 msgid "Presence status" msgstr "上線狀態" -#: ../gtk/friendlist.c:557 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名稱" -#: ../gtk/friendlist.c:569 +#: ../gtk/friendlist.c:673 #, fuzzy msgid "Call" msgstr "播打給 %s" -#: ../gtk/friendlist.c:574 +#: ../gtk/friendlist.c:678 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:604 +#: ../gtk/friendlist.c:708 #, c-format msgid "Search in %s directory" msgstr "在 %s 目錄中搜尋" -#: ../gtk/friendlist.c:762 -msgid "Invalid sip contact !" -msgstr "無效的 sip 連絡人!" - -#: ../gtk/friendlist.c:807 -#, c-format -msgid "Call %s" -msgstr "播打給 %s" - -#: ../gtk/friendlist.c:808 -#, c-format -msgid "Send text to %s" -msgstr "傳送文字給 %s" - -#: ../gtk/friendlist.c:809 +#: ../gtk/friendlist.c:924 #, c-format msgid "Edit contact '%s'" msgstr "編輯連絡人「%s」" -#: ../gtk/friendlist.c:810 +#: ../gtk/friendlist.c:925 #, c-format msgid "Delete contact '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:852 +#: ../gtk/friendlist.c:926 +#, fuzzy, c-format +msgid "Delete chat history of '%s'" +msgstr "刪除連絡人「%s」" + +#: ../gtk/friendlist.c:977 #, c-format msgid "Add new contact from %s directory" msgstr "從 %s 目錄加入新的連絡人" @@ -350,20 +365,24 @@ msgstr "" msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:847 +#: ../gtk/propertybox.c:781 +msgid "Serbian" +msgstr "" + +#: ../gtk/propertybox.c:848 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" -#: ../gtk/propertybox.c:933 +#: ../gtk/propertybox.c:934 msgid "None" msgstr "" -#: ../gtk/propertybox.c:937 +#: ../gtk/propertybox.c:938 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:943 +#: ../gtk/propertybox.c:944 msgid "ZRTP" msgstr "" @@ -614,114 +633,114 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:13 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:477 +#: ../gtk/incall_view.c:476 msgid "Calling..." msgstr "播打..." -#: ../gtk/incall_view.c:480 ../gtk/incall_view.c:690 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:491 +#: ../gtk/incall_view.c:490 msgid "Incoming call" msgstr "來電" -#: ../gtk/incall_view.c:528 +#: ../gtk/incall_view.c:527 msgid "good" msgstr "" -#: ../gtk/incall_view.c:530 +#: ../gtk/incall_view.c:529 msgid "average" msgstr "" -#: ../gtk/incall_view.c:532 +#: ../gtk/incall_view.c:531 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:534 +#: ../gtk/incall_view.c:533 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:535 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:537 ../gtk/incall_view.c:553 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:652 +#: ../gtk/incall_view.c:651 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:658 +#: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:664 +#: ../gtk/incall_view.c:663 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:664 ../gtk/main.ui.h:5 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:685 +#: ../gtk/incall_view.c:684 msgid "In call" msgstr "通話中" -#: ../gtk/incall_view.c:719 +#: ../gtk/incall_view.c:718 msgid "Paused call" msgstr "暫停通話" -#: ../gtk/incall_view.c:732 +#: ../gtk/incall_view.c:731 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:749 +#: ../gtk/incall_view.c:748 msgid "Call ended." msgstr "通話結束。" -#: ../gtk/incall_view.c:779 +#: ../gtk/incall_view.c:778 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:782 +#: ../gtk/incall_view.c:781 #, fuzzy msgid "Transfer done." msgstr "轉接" -#: ../gtk/incall_view.c:785 +#: ../gtk/incall_view.c:784 #, fuzzy msgid "Transfer failed." msgstr "轉接" -#: ../gtk/incall_view.c:829 +#: ../gtk/incall_view.c:828 msgid "Resume" msgstr "繼續" -#: ../gtk/incall_view.c:836 ../gtk/main.ui.h:10 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "暫停" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:901 +#: ../gtk/incall_view.c:900 #, fuzzy msgid "(Paused)" msgstr "暫停" @@ -744,157 +763,153 @@ msgstr "傳送" msgid "End conference" msgstr "" -#: ../gtk/main.ui.h:4 -msgid "label" -msgstr "標籤" - -#: ../gtk/main.ui.h:8 +#: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" msgstr "" -#: ../gtk/main.ui.h:9 +#: ../gtk/main.ui.h:8 msgid "Video" msgstr "" -#: ../gtk/main.ui.h:11 +#: ../gtk/main.ui.h:10 msgid "Mute" msgstr "" -#: ../gtk/main.ui.h:12 +#: ../gtk/main.ui.h:11 msgid "Transfer" msgstr "轉接" -#: ../gtk/main.ui.h:15 +#: ../gtk/main.ui.h:14 msgid "In call" msgstr "通話中" -#: ../gtk/main.ui.h:16 +#: ../gtk/main.ui.h:15 msgid "Duration" msgstr "時間長度" -#: ../gtk/main.ui.h:17 +#: ../gtk/main.ui.h:16 msgid "Call quality rating" msgstr "" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:17 msgid "_Options" msgstr "選項(_O)" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:18 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:19 msgid "Enable self-view" msgstr "啟用自拍檢視" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:20 msgid "_Help" msgstr "求助(_H)" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:21 msgid "Show debug window" msgstr "顯示除錯視窗" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:22 msgid "_Homepage" msgstr "官方網頁(_H)" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:23 msgid "Check _Updates" msgstr "檢查更新(_U)" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Account assistant" msgstr "帳號設定助理" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" msgstr "SIP 位址或電話號碼:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:26 msgid "Initiate a new call" msgstr "打出新電話" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:27 msgid "Contacts" msgstr "連絡人" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "加入" -#: ../gtk/main.ui.h:30 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "編輯" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Search" msgstr "搜尋" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contacts from directory" msgstr "從目錄加入連絡人" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Add contact" msgstr "加入聯絡人" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "Recent calls" msgstr "通話中" -#: ../gtk/main.ui.h:35 +#: ../gtk/main.ui.h:34 msgid "My current identity:" msgstr "我目前的使用者識別:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "使用者名稱" -#: ../gtk/main.ui.h:37 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密碼" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Internet connection:" msgstr "網路連線:" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:38 msgid "Automatically log me in" msgstr "將我自動登入" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登入資訊" -#: ../gtk/main.ui.h:41 +#: ../gtk/main.ui.h:40 msgid "Welcome !" msgstr "歡迎使用!" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:41 msgid "All users" msgstr "所有使用者" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:42 msgid "Online users" msgstr "線上使用者" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:43 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:44 msgid "Fiber Channel" msgstr "光纖通道" -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:45 msgid "Default" msgstr "預設值" -#: ../gtk/main.ui.h:47 +#: ../gtk/main.ui.h:46 msgid "Delete" msgstr "" @@ -1505,7 +1520,7 @@ msgstr "" msgid "Outgoing call" msgstr "去電" -#: ../coreapi/linphonecore.c:1314 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "準備就緒" @@ -1559,11 +1574,11 @@ msgstr "已連線。" msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3351 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3356 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "暫停目前的通話..." @@ -1662,115 +1677,115 @@ msgstr "" "您輸入的 sip 身分是無效的。\n" "它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" -#: ../coreapi/proxy.c:1068 +#: ../coreapi/proxy.c:1069 #, c-format msgid "Could not login as %s" msgstr "無法以 %s 登入" -#: ../coreapi/callbacks.c:283 +#: ../coreapi/callbacks.c:286 msgid "Remote ringing." msgstr "遠端響鈴。" -#: ../coreapi/callbacks.c:303 +#: ../coreapi/callbacks.c:306 msgid "Remote ringing..." msgstr "遠端響鈴..." -#: ../coreapi/callbacks.c:314 +#: ../coreapi/callbacks.c:317 msgid "Early media." msgstr "早期媒體。" -#: ../coreapi/callbacks.c:365 +#: ../coreapi/callbacks.c:368 #, c-format msgid "Call with %s is paused." msgstr "和 %s 的通話已暫停。" -#: ../coreapi/callbacks.c:378 +#: ../coreapi/callbacks.c:381 #, c-format msgid "Call answered by %s - on hold." msgstr "通話由 %s 接聽 - 保留中。" -#: ../coreapi/callbacks.c:389 +#: ../coreapi/callbacks.c:392 msgid "Call resumed." msgstr "通話已繼續。" -#: ../coreapi/callbacks.c:394 +#: ../coreapi/callbacks.c:397 #, c-format msgid "Call answered by %s." msgstr "通話由 %s 接聽。" -#: ../coreapi/callbacks.c:409 +#: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:457 +#: ../coreapi/callbacks.c:460 #, fuzzy msgid "We have been resumed." msgstr "我們要繼續了..." -#: ../coreapi/callbacks.c:466 +#: ../coreapi/callbacks.c:469 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:472 +#: ../coreapi/callbacks.c:475 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:541 +#: ../coreapi/callbacks.c:544 msgid "Call terminated." msgstr "通話已終止。" -#: ../coreapi/callbacks.c:552 +#: ../coreapi/callbacks.c:555 msgid "User is busy." msgstr "使用者現正忙碌。" -#: ../coreapi/callbacks.c:553 +#: ../coreapi/callbacks.c:556 msgid "User is temporarily unavailable." msgstr "使用者暫時無法聯繫。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:558 msgid "User does not want to be disturbed." msgstr "使用者不想要被打擾。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:559 msgid "Call declined." msgstr "通話被拒接。" -#: ../coreapi/callbacks.c:568 +#: ../coreapi/callbacks.c:571 msgid "No response." msgstr "沒有回應。" -#: ../coreapi/callbacks.c:572 +#: ../coreapi/callbacks.c:575 msgid "Protocol error." msgstr "通訊協定錯誤。" -#: ../coreapi/callbacks.c:588 +#: ../coreapi/callbacks.c:591 msgid "Redirected" msgstr "已重新導向" -#: ../coreapi/callbacks.c:624 +#: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:630 +#: ../coreapi/callbacks.c:633 msgid "Call failed." msgstr "通話失敗。" -#: ../coreapi/callbacks.c:733 +#: ../coreapi/callbacks.c:737 #, c-format msgid "Registration on %s successful." msgstr "在 %s 註冊成功。" -#: ../coreapi/callbacks.c:734 +#: ../coreapi/callbacks.c:738 #, c-format msgid "Unregistration on %s done." msgstr "在 %s 取消註冊完成。" -#: ../coreapi/callbacks.c:754 +#: ../coreapi/callbacks.c:758 msgid "no response timeout" msgstr "沒有回應逾時" -#: ../coreapi/callbacks.c:757 +#: ../coreapi/callbacks.c:761 #, c-format msgid "Registration on %s failed: %s" msgstr "在 %s 註冊失敗:%s" @@ -1780,12 +1795,15 @@ msgstr "在 %s 註冊失敗:%s" msgid "Authentication token is %s" msgstr "驗證失敗" -#: ../coreapi/linphonecall.c:2314 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您有 %i 通未接來電。" +#~ msgid "label" +#~ msgstr "標籤" + #~ msgid "Keypad" #~ msgstr "撥號盤" From 99f6bdec72f21b04220979f19584404b8b87f864 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 9 Apr 2013 14:06:02 +0200 Subject: [PATCH 229/909] improve call quality indicator (takes into account video) add accessors to late and loss rate in LinphoneCallStats. --- coreapi/linphonecall.c | 56 ++++++++++++++++++++++++++++++++++-------- coreapi/linphonecore.c | 1 + coreapi/linphonecore.h | 6 +++-- mediastreamer2 | 2 +- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6c01c65bd..ab917920c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1857,9 +1857,13 @@ void linphone_call_delete_upnp_session(LinphoneCall *call){ } #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); +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; + } } void linphone_call_stop_audio_stream(LinphoneCall *call) { @@ -1877,7 +1881,8 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { lp_config_set_string(call->core->config,"sound","ec_state",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); } @@ -1893,6 +1898,7 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); call->videostream_app_evq=NULL; + linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); video_stream_stop(call->videostream); call->videostream=NULL; } @@ -2009,10 +2015,20 @@ float linphone_call_get_record_volume(LinphoneCall *call){ * 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; } /** @@ -2027,18 +2043,34 @@ 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); + } +} + /** * 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]; +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); + } + return stats; } /** @@ -2242,6 +2274,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; evd->packet = NULL; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); 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) { @@ -2250,6 +2283,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; evd->packet = NULL; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); 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) @@ -2283,6 +2317,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; evd->packet = NULL; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream); 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) { @@ -2291,6 +2326,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; evd->packet = NULL; + update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream); 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) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7b4d6a998..f4782908a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -116,6 +116,7 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro cl->from=from; cl->to=to; cl->status=LinphoneCallAborted; /*default status*/ + cl->quality=-1; return cl; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fefd050e7..37001d367 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -343,14 +343,16 @@ struct _LinphoneCallStats { LinphoneUpnpState upnp_state; /**< State of uPnP processing. */ float download_bandwidth; /** Date: Tue, 9 Apr 2013 14:12:21 +0200 Subject: [PATCH 230/909] french translation --- po/fr.po | 244 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 126 insertions(+), 118 deletions(-) diff --git a/po/fr.po b/po/fr.po index d4cb84c52..48e85b46b 100644 --- a/po/fr.po +++ b/po/fr.po @@ -7,20 +7,22 @@ msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-08 16:59+0200\n" -"PO-Revision-Date: 2013-04-08 16:46+0100\n" -"Last-Translator: Simon Morlat \n" +"PO-Revision-Date: 2013-04-09 13:57+0100\n" +"Last-Translator: Simon Morlat \n" "Language-Team: french \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 +#: ../gtk/friendlist.c:922 #, c-format msgid "Call %s" msgstr "Appeler %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 +#: ../gtk/friendlist.c:923 #, c-format msgid "Send text to %s" msgstr "Chatter avec %s" @@ -60,7 +62,8 @@ msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:321 +#: ../gtk/calllogs.c:327 #, c-format msgid "%s\t%s" msgstr "" @@ -71,6 +74,8 @@ msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" +"%s\tQualité: %s\n" +"%s\t%s\t" #: ../gtk/calllogs.c:329 #, c-format @@ -79,7 +84,8 @@ msgid "" "%s" msgstr "" -#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 +#: ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conférence" @@ -87,12 +93,15 @@ msgstr "Conférence" 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/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:324 +#: ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Contact sip invalide !" @@ -102,7 +111,7 @@ msgstr "affiche des informations de debogage" #: ../gtk/main.c:99 msgid "path to a file to write logs into." -msgstr "" +msgstr "chemin vers le fichier de logs." #: ../gtk/main.c:106 msgid "Start linphone with video disabled." @@ -114,19 +123,15 @@ msgstr "Démarre iconifié, sans interface principale." #: ../gtk/main.c:120 msgid "address to call right now" -msgstr "addresse à appeler maintenant" +msgstr "adresse à appeler maintenant" #: ../gtk/main.c:127 msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" #: ../gtk/main.c:134 -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)" +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:515 #, c-format @@ -137,15 +142,12 @@ msgstr "Appel avec %s" #, 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" +"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 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'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." #: ../gtk/main.c:1023 #, c-format @@ -160,19 +162,24 @@ msgstr "" msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 +#: ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 +#: ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1134 +#: ../gtk/incall_view.c:497 +#: ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1136 +#: ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" @@ -183,12 +190,12 @@ msgstr "Appel en pause" #: ../gtk/main.c:1142 #, c-format msgid "by %s" -msgstr "" +msgstr "b>par %s" #: ../gtk/main.c:1191 #, 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:1353 msgid "Website link" @@ -203,7 +210,8 @@ msgstr "Linphone - un téléphone video pour l'internet" msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:1796 +#: ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" @@ -228,7 +236,9 @@ msgstr "Ajouter au carnet d'adresse" msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 +#: ../gtk/propertybox.c:367 +#: ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" @@ -281,11 +291,13 @@ msgstr "Débit min. (kbit/s)" msgid "Parameters" msgstr "Paramètres" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:435 +#: ../gtk/propertybox.c:578 msgid "Enabled" msgstr "Activé" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:437 +#: ../gtk/propertybox.c:578 msgid "Disabled" msgstr "Désactivé" @@ -366,11 +378,8 @@ msgid "Serbian" msgstr "Serbe" #: ../gtk/propertybox.c:848 -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." +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:934 msgid "None" @@ -390,10 +399,12 @@ 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" @@ -450,13 +461,14 @@ msgstr "Entrez votre identifiant linphone.org" msgid "Username:" msgstr "Nom d'utilisateur:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:94 +#: ../gtk/password.ui.h:4 msgid "Password:" msgstr "Mot de passe:" #: ../gtk/setupwizard.c:114 msgid "Enter your account informations" -msgstr "" +msgstr "Entrez les informations concernant votre compte" #: ../gtk/setupwizard.c:121 msgid "Username*" @@ -499,41 +511,44 @@ 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:380 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:388 msgid "" -"Please validate your account by clicking on the link we just sent you by " -"email.\n" +"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:564 msgid "Welcome to the account setup assistant" -msgstr "" +msgstr "Bienvenue dans l'assistant de configuration de compte." #: ../gtk/setupwizard.c:569 msgid "Account setup assistant" -msgstr "" +msgstr "Assistant de configuration de compte." #: ../gtk/setupwizard.c:575 msgid "Configure your account (step 1/1)" -msgstr "Configurez votre compte" +msgstr "Configurez votre compte (étape 1/1)" #: ../gtk/setupwizard.c:580 msgid "Enter your sip username (step 1/1)" -msgstr "" +msgstr "Entrez votre identifiant sip (étape 1/1)" #: ../gtk/setupwizard.c:584 msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "Entrez les informations concernant votre compte (étape 1/2)" #: ../gtk/setupwizard.c:593 msgid "Validation (step 2/2)" -msgstr "" +msgstr "Validation (étape 2/2)" #: ../gtk/setupwizard.c:598 msgid "Error" @@ -541,9 +556,10 @@ msgstr "Erreur" #: ../gtk/setupwizard.c:602 msgid "Terminating" -msgstr "" +msgstr "En cours d’arrêt." -#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 +#: ../gtk/incall_view.c:70 +#: ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "Appel #%i" @@ -553,14 +569,15 @@ msgstr "Appel #%i" msgid "Transfer to call #%i with %s" msgstr "Transférer vers l'appel #%i avec %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:210 +#: ../gtk/incall_view.c:213 #, fuzzy msgid "Not used" msgstr "Non trouvé" #: ../gtk/incall_view.c:220 msgid "ICE not activated" -msgstr "" +msgstr "ICE non activé" #: ../gtk/incall_view.c:222 #, fuzzy @@ -569,11 +586,11 @@ msgstr "L'appel a échoué." #: ../gtk/incall_view.c:224 msgid "ICE in progress" -msgstr "" +msgstr "Négociation ICE en cours" #: ../gtk/incall_view.c:226 msgid "Going through one or more NATs" -msgstr "" +msgstr "Via un ou plusieurs NATs" #: ../gtk/incall_view.c:228 #, fuzzy @@ -582,36 +599,35 @@ msgstr "Redirection" #: ../gtk/incall_view.c:230 msgid "Through a relay server" -msgstr "" +msgstr "Via un serveur relais" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" msgstr "uPnP non activé" #: ../gtk/incall_view.c:240 -#, fuzzy msgid "uPnP in progress" -msgstr "Découverte STUN en cours" +msgstr "uPnP en cours" #: ../gtk/incall_view.c:242 -#, fuzzy msgid "uPnp not available" -msgstr "indisponible" +msgstr "uPnP est indisponible" #: ../gtk/incall_view.c:244 msgid "uPnP is running" -msgstr "" +msgstr "uPnP en cours d’exécution" #: ../gtk/incall_view.c:246 -#, fuzzy msgid "uPnP failed" -msgstr "L'appel a échoué." +msgstr "uPnP a échoué." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:256 +#: ../gtk/incall_view.c:257 msgid "Direct or through server" -msgstr "" +msgstr "Directe ou via un serveur" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:259 +#: ../gtk/incall_view.c:265 #, c-format msgid "" "download: %f\n" @@ -623,7 +639,8 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:384 +#: ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Raccrocher" @@ -631,7 +648,8 @@ msgstr "Raccrocher" msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:479 +#: ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" @@ -659,7 +677,8 @@ msgstr "très faible" msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:536 +#: ../gtk/incall_view.c:552 msgid "unavailable" msgstr "indisponible" @@ -676,7 +695,8 @@ msgstr "Sécurisé par ZRTP- [jeton: %s]" msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:663 +#: ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" @@ -717,7 +737,8 @@ msgstr "Transfert échoué" msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:835 +#: ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" @@ -752,7 +773,7 @@ msgstr "Fin de conférence" #: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" -msgstr "" +msgstr "Enregistrement de l'appel dans un fichier audio." #: ../gtk/main.ui.h:8 msgid "Video" @@ -760,7 +781,7 @@ msgstr "Vidéo" #: ../gtk/main.ui.h:10 msgid "Mute" -msgstr "" +msgstr "Couper le son" #: ../gtk/main.ui.h:11 msgid "Transfer" @@ -808,7 +829,7 @@ msgstr "" #: ../gtk/main.ui.h:24 msgid "Account assistant" -msgstr "" +msgstr "Assistant de compte" #: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" @@ -822,11 +843,13 @@ msgstr "Démarrer un nouvel appel" msgid "Contacts" msgstr "Contacts" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 +#: ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Ajouter" -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 +#: ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editer" @@ -850,17 +873,19 @@ msgstr "Appels récents" msgid "My current identity:" msgstr "Mon identité sip:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 +#: ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Nom d'utilisateur" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 +#: ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Mot de passe" #: ../gtk/main.ui.h:37 msgid "Internet connection:" -msgstr "" +msgstr "Connexion internet:" #: ../gtk/main.ui.h:38 msgid "Automatically log me in" @@ -1041,7 +1066,8 @@ msgstr "Codecs audio" msgid "Video codecs" msgstr "Codecs vidéo" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:7 +#: ../gtk/keypad.ui.h:5 msgid "C" msgstr "" @@ -1091,7 +1117,7 @@ msgstr "" #: ../gtk/parameters.ui.h:19 msgid "DSCP fields" -msgstr "" +msgstr "Champs DSCP" #: ../gtk/parameters.ui.h:20 msgid "Fixed" @@ -1127,14 +1153,12 @@ msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Derrière un pare-feu (utiliser STUN)" #: ../gtk/parameters.ui.h:28 -#, fuzzy msgid "Behind NAT / Firewall (use ICE)" -msgstr "Derrière un pare-feu (utiliser STUN)" +msgstr "Derrière un pare-feu (utiliser ICE)" #: ../gtk/parameters.ui.h:29 -#, fuzzy msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Derrière un pare-feu (utiliser STUN)" +msgstr "Derrière un pare-feu (utiliser uPnP)" #: ../gtk/parameters.ui.h:30 msgid "Stun server:" @@ -1194,9 +1218,7 @@ msgstr "Paramètres multimedia" #: ../gtk/parameters.ui.h:44 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" +msgstr "Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de compte SIP" #: ../gtk/parameters.ui.h:45 msgid "Your display name (eg: John Doe):" @@ -1238,11 +1260,13 @@ msgstr "Sécurité" msgid "Manage SIP Accounts" msgstr "Gérer mes comptes SIP" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:57 +#: ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Activer" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:58 +#: ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Désactiver" @@ -1267,13 +1291,8 @@ msgid "Enable adaptive rate control" msgstr "Activer le control de débit adaptatif." #: ../gtk/parameters.ui.h:64 -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." +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:65 msgid "Bandwidth control" @@ -1324,9 +1343,8 @@ msgid "Please wait" msgstr "En attente" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy msgid "Dscp settings" -msgstr "Réglages" +msgstr "Réglages Dscp" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1346,10 +1364,9 @@ msgstr "" #: ../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" @@ -1380,9 +1397,8 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 -#, fuzzy msgid "Call statistics and information" -msgstr "Information sur le contact" +msgstr "Statistiques de l'appel et informations" #: ../gtk/tunnel_config.ui.h:1 #, fuzzy @@ -1509,11 +1525,8 @@ msgid "Could not resolve this number." msgstr "La destination n'a pu être trouvée." #: ../coreapi/linphonecore.c:2231 -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 à " +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:2432 msgid "Contacting" @@ -1626,7 +1639,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" @@ -1641,12 +1654,8 @@ msgid "Unknown-bug" msgstr "Bug inconnu" #: ../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." +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:210 msgid "" @@ -1654,8 +1663,7 @@ msgid "" "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:username@domain, comme par example sip:alice@example.net" #: ../coreapi/proxy.c:1069 #, c-format @@ -1801,7 +1809,7 @@ msgstr[1] "Vous avez manqué %i appels" #~ 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" +#~ "Entrez un nom d'utilisateur, un numéro de téléphone, ou une adresse SIP" #~ msgid "Lookup:" #~ msgstr "Rechercher:" From d8aa6f93e427d9b0e46eddab56179220f8d54cea Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 9 Apr 2013 15:52:30 +0200 Subject: [PATCH 231/909] add jni and java accessors for realtime late and loss rates --- coreapi/linphonecore_jni.cc | 18 ++++++++++++++- .../org/linphone/core/LinphoneCallStats.java | 20 +++++++++++++---- .../org/linphone/core/LinphoneCallImpl.java | 2 ++ .../linphone/core/LinphoneCallStatsImpl.java | 22 +++++++++++++++++++ mediastreamer2 | 2 +- 5 files changed, 58 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 6b6c3f5ce..ddc26f657 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1578,6 +1578,23 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getJitterBufferSi 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; @@ -1702,7 +1719,6 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getAverageQuality( JNI return (jfloat)linphone_call_get_average_quality((LinphoneCall*)ptr); } - //LinphoneFriend extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env ,jobject thiz 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/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 30bcd528f..041acaef2 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -68,9 +68,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() { 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/mediastreamer2 b/mediastreamer2 index abf2a7ec4..4f93003c1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit abf2a7ec461ac411703233e3554e985d62fa0b9c +Subproject commit 4f93003c1eade1442fdedd8dee10f18c98ec47c3 From bf2d6d78ea74874d712f36d8004c7ddf4f165449 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Apr 2013 17:56:49 +0200 Subject: [PATCH 232/909] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 35f5efbfb..9f51aa254 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 35f5efbfbf7814bd0403249431a6b94d6c4286b4 +Subproject commit 9f51aa254fc5c24834614612036485406a8d06a7 From 9bf210452464b8acde764d445472bd62792c984e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Apr 2013 18:07:53 +0200 Subject: [PATCH 233/909] Change API to set log handler and log level. - Deprecate linphone_core_enable_logs(), linphone_core_enable_logs_with_cb() and linphone_core_disable_logs() functions. - Introduce linphone_core_set_log_handler(), linphone_core_set_log_file() and linphone_core_set_log_level() functions. --- coreapi/linphonecore.c | 32 +++++++++++++++++++++++++++++--- coreapi/linphonecore.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f4782908a..5f70f45e1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -407,10 +407,29 @@ const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _Lin return linphone_call_get_remote_address(call); } +void linphone_core_set_log_handler(OrtpLogFunc logfunc) { + 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) { + ortp_set_log_level_mask(loglevel); + if (loglevel == 0) { + sal_disable_logs(); + } else { + sal_enable_logs(); + } +} + /** * 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. * @@ -425,6 +444,7 @@ void linphone_core_enable_logs(FILE *file){ * 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); @@ -439,6 +459,7 @@ void linphone_core_enable_logs_with_cb(OrtpLogFunc 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); @@ -1197,6 +1218,7 @@ 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); + linphone_core_set_log_level((OrtpLogLevel)lp_config_get_int(config,"misc","log_level",0)); } @@ -2152,9 +2174,13 @@ void linphone_core_iterate(LinphoneCore *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 (ortp_get_log_level_mask() != lp_config_get_int(lc->config, "misc", "log_level", 0)) { + lp_config_set_int(lc->config, "misc", "log_level", ortp_get_log_level_mask()); + } + if (lp_config_needs_commit(lc->config)) { + lp_config_sync(lc->config); + } } /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 37001d367..f8e1dcb88 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -874,6 +874,35 @@ typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *contex /* THE main API */ +/** + * Define a log handler. + * + * @ingroup misc + * + * @param logfunc The function pointer of the log handler. + */ +void linphone_core_set_log_handler(OrtpLogFunc logfunc); +/** + * Define a log file. + * + * @ingroup misc + * + * If the file pointer passed as an argument is NULL, stdout is used instead. + * + * @param file A pointer to the FILE structure of the file to write to. + */ +void linphone_core_set_log_file(FILE *file); +/** + * Define the log level. + * + * @ingroup misc + * + * The loglevel parameter is a bitmask parameter. Therefore to enable only warning and error + * messages, use ORTP_WARNING | ORTP_ERROR. To disable logs, simply set loglevel to 0. + * + * @param loglevel A bitmask of the log levels to set. + */ +void linphone_core_set_log_level(OrtpLogLevel loglevel); void linphone_core_enable_logs(FILE *file); void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); void linphone_core_disable_logs(void); From 372df24dd624ce5b70ceedcbf7150895fae26815 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Apr 2013 18:15:58 +0200 Subject: [PATCH 234/909] Add missing exports. --- coreapi/linphonecore.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ed128a464..7bb466ad6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -892,7 +892,7 @@ typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *contex * * @param logfunc The function pointer of the log handler. */ -void linphone_core_set_log_handler(OrtpLogFunc logfunc); +LINPHONE_PUBLIC void linphone_core_set_log_handler(OrtpLogFunc logfunc); /** * Define a log file. * @@ -902,7 +902,7 @@ void linphone_core_set_log_handler(OrtpLogFunc logfunc); * * @param file A pointer to the FILE structure of the file to write to. */ -void linphone_core_set_log_file(FILE *file); +LINPHONE_PUBLIC void linphone_core_set_log_file(FILE *file); /** * Define the log level. * @@ -913,10 +913,10 @@ void linphone_core_set_log_file(FILE *file); * * @param loglevel A bitmask of the log levels to set. */ -void linphone_core_set_log_level(OrtpLogLevel loglevel); +LINPHONE_PUBLIC void linphone_core_set_log_level(OrtpLogLevel loglevel); LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file); LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); -void linphone_core_disable_logs(void); +LINPHONE_PUBLIC void linphone_core_disable_logs(void); const char *linphone_core_get_version(void); const char *linphone_core_get_user_agent_name(void); const char *linphone_core_get_user_agent_version(void); From 3d9d5962022a47d46abf2600a256e7eb8644c27f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Apr 2013 18:25:12 +0200 Subject: [PATCH 235/909] Fix compilation (missing }). --- coreapi/linphonecore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5f70f45e1..cb1808836 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2181,6 +2181,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lp_config_needs_commit(lc->config)) { lp_config_sync(lc->config); } + } } /** From bf082a2db519d43611232143e95cf782bcde8b2a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 10 Apr 2013 09:20:13 +0200 Subject: [PATCH 236/909] Fix compilation. --- coreapi/linphonecore.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cb1808836..e1d88b292 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -418,11 +418,6 @@ void linphone_core_set_log_file(FILE *file) { void linphone_core_set_log_level(OrtpLogLevel loglevel) { ortp_set_log_level_mask(loglevel); - if (loglevel == 0) { - sal_disable_logs(); - } else { - sal_enable_logs(); - } } /** From 3ff0ef4d0a8bd207e2c8d1a153e64a7cce5b554c Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 10 Apr 2013 14:05:20 +0200 Subject: [PATCH 237/909] Use static lib for xml2lpc and lpc2xml --- build/android/common.mk | 5 +++++ build/android/lpc2xml.mk | 8 ++++---- build/android/xml2lpc.mk | 8 ++++---- java/impl/org/linphone/tools/Lpc2Xml.java | 2 +- java/impl/org/linphone/tools/Xml2Lpc.java | 2 +- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index 543a9dc19..584649735 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -95,6 +95,11 @@ LOCAL_STATIC_LIBRARIES := \ libeXosip2 \ libosip2 \ libgsm +ifeq ($(BUILD_REMOTE_PROVISIONING),1) +LOCAL_STATIC_LIBRARIES += \ + libxml2lpc \ + liblpc2xml +endif ifeq ($(BUILD_TUNNEL),1) LOCAL_CFLAGS +=-DTUNNEL_ENABLED diff --git a/build/android/lpc2xml.mk b/build/android/lpc2xml.mk index b5757ad99..91038adce 100644 --- a/build/android/lpc2xml.mk +++ b/build/android/lpc2xml.mk @@ -39,10 +39,10 @@ LOCAL_C_INCLUDES = \ $(LOCAL_PATH)/../../externals/build/libxml2 \ LOCAL_SHARED_LIBRARIES = \ - libxml2 \ - liblinphonenoneon \ - liblinphone \ + libxml2 +# liblinphonenoneon \ +# liblinphone \ LOCAL_MODULE := liblpc2xml -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk index 449251cc8..e89ab383b 100644 --- a/build/android/xml2lpc.mk +++ b/build/android/xml2lpc.mk @@ -39,10 +39,10 @@ LOCAL_C_INCLUDES = \ $(LOCAL_PATH)/../../externals/build/libxml2 \ LOCAL_SHARED_LIBRARIES = \ - libxml2 \ - liblinphonenoneon \ - liblinphone \ + libxml2 +# liblinphonenoneon \ +# liblinphone \ LOCAL_MODULE := libxml2lpc -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) 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..5e0a81880 100644 --- a/java/impl/org/linphone/tools/Xml2Lpc.java +++ b/java/impl/org/linphone/tools/Xml2Lpc.java @@ -63,7 +63,7 @@ public class Xml2Lpc { static { try { System.loadLibrary("xml2"); - System.loadLibrary("xml2lpc"); + //System.loadLibrary("xml2lpc"); mAvailable = true; } catch (Throwable e) { mAvailable = false; From f5c2a77ac930675766832d47bfd100592bef6ef7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 10 Apr 2013 15:11:43 +0200 Subject: [PATCH 238/909] Added missing export --- coreapi/linphonecore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7bb466ad6..f61dffe7d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -538,7 +538,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *o LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); -LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); From b90e57d4c84517eebbcf077b79fc70415aa5c684 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 10 Apr 2013 17:26:38 +0200 Subject: [PATCH 239/909] compile Android xml2lpc/lpc2xml into module liblinphone --- build/android/common.mk | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build/android/common.mk b/build/android/common.mk index a997c26ab..5b04d13d3 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -202,6 +202,16 @@ else LOCAL_STATIC_LIBRARIES += libsrtp-static endif endif +ifeq ($(BUILD_REMOTE_PROVISIONING),1) +LOCAL_SRC_FILES += ../tools/xml2lpc.c \ + ../tools/xml2lpc_jni.cc \ + ../tools/lpc2xml.c \ + ../tools/lpc2xml_jni.cc +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 +LOCAL_STATIC_LIBRARIES += libxml2 +endif LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) From edf037fa37b980cdba898d129163261bbec0fd3d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 10 Apr 2013 17:35:51 +0200 Subject: [PATCH 240/909] no longer manually loas lib xml on Android --- java/impl/org/linphone/tools/Xml2Lpc.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/impl/org/linphone/tools/Xml2Lpc.java b/java/impl/org/linphone/tools/Xml2Lpc.java index 5e0a81880..8e3a9faa0 100644 --- a/java/impl/org/linphone/tools/Xml2Lpc.java +++ b/java/impl/org/linphone/tools/Xml2Lpc.java @@ -61,8 +61,9 @@ public class Xml2Lpc { // Load library static { - try { - System.loadLibrary("xml2"); + try { + new Xml2Lpc(); + //System.loadLibrary("xml2"); //System.loadLibrary("xml2lpc"); mAvailable = true; } catch (Throwable e) { From bffae8bdf47ac81f94c989b29b8d31d35fc16bdf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Apr 2013 09:18:12 +0200 Subject: [PATCH 241/909] transfer full control of registration to refresher --- .cproject | 1 + coreapi/bellesip_sal/sal_impl.c | 23 +++- coreapi/bellesip_sal/sal_impl.h | 14 ++- coreapi/bellesip_sal/sal_op_call.c | 8 +- coreapi/bellesip_sal/sal_op_impl.c | 26 +++-- coreapi/bellesip_sal/sal_op_message.c | 1 + coreapi/bellesip_sal/sal_op_presence.c | 1 + coreapi/bellesip_sal/sal_op_registration.c | 120 ++++++++------------- coreapi/callbacks.c | 2 +- coreapi/proxy.c | 3 +- gtk/logging.c | 1 + include/sal/sal.h | 1 + tester/register_tester.c | 2 +- tools/Makefile.am | 1 + 14 files changed, 111 insertions(+), 93 deletions(-) diff --git a/.cproject b/.cproject index ed10f0f5e..d4a5780c3 100644 --- a/.cproject +++ b/.cproject @@ -37,6 +37,7 @@ + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 5dcfeac3b..a4f4aac96 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -56,7 +56,7 @@ void sal_enable_logs(){ void sal_disable_logs() { belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); } -static void sal_add_pending_auth(Sal *sal, SalOp *op){ +void sal_add_pending_auth(Sal *sal, SalOp *op){ if (ms_list_find(sal->pending_auths,op)==NULL){ sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op)); } @@ -99,9 +99,7 @@ void sal_process_authentication(SalOp *op) { } if (op->auth_info) sal_auth_info_delete(op->auth_info); auth_event=(belle_sip_auth_event_t*)(auth_list->data); - op->auth_info=sal_auth_info_new(); - op->auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(auth_event)) ; - op->auth_info->username = ms_strdup(belle_sip_auth_event_get_username(auth_event)) ; + op->auth_info=sal_auth_info_create(auth_event); belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); } @@ -640,3 +638,20 @@ void sal_set_dns_timeout(Sal* sal,int timeout) { int sal_get_dns_timeout(const Sal* sal) { return belle_sip_stack_get_dns_timeout(sal->stack); } + +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)) ; + return auth_info; +} +const char* sal_op_type_to_string(const SalOpType_t type) { + switch(type) { + case SalOpRegister: return "SalOpRegister"; + case SalOpCall: return "SalOpCall"; + case SalOpMessage: return "SalOpMessage"; + case SalOpPresence: return "SalOpPresence"; + default: + return "SalOpUnknown"; + } +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 56b5bd514..cb5459864 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -55,13 +55,21 @@ typedef enum SalOpDir { SalOpDirIncoming=0 ,SalOpDirOutgoing }SalOpDir_t; +typedef enum SalOpType { + SalOpUnknown, + SalOpRegister, + SalOpCall, + SalOpMessage, + SalOpPresence +}SalOpType_t; +const char* sal_op_type_to_string(const SalOpType_t type); struct SalOp{ SalOpBase base; belle_sip_listener_callbacks_t callbacks; belle_sip_client_transaction_t *pending_auth_transaction; belle_sip_server_transaction_t* pending_server_trans; - belle_sip_client_transaction_t* pending_inv_client_trans; + belle_sip_client_transaction_t* pending_client_trans; SalAuthInfo* auth_info; belle_sip_refresher_t* registration_refresher; bool_t sdp_offering; @@ -76,6 +84,7 @@ struct SalOp{ SalOpDir_t dir; belle_sip_refresher_t* refresher; int ref; + SalOpType_t type; }; belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); @@ -108,4 +117,7 @@ void sal_op_message_fill_cbs(SalOp*op); /*call transfert*/ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); +/*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); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 7f360710f..0bf1f2440 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -183,7 +183,7 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { static void cancelling_invite(SalOp* op ){ belle_sip_request_t* cancel; ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); - cancel = belle_sip_client_transaction_create_cancel(op->pending_inv_client_trans); + cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans); sal_op_send_request(op,cancel); op->state=SalOpStateTerminating; } @@ -527,6 +527,7 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { 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); @@ -553,6 +554,7 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_transaction_terminated=call_process_transaction_terminated; op->callbacks.process_request_event=process_request_event; op->callbacks.process_dialog_terminated=process_dialog_terminated; + op->type=SalOpCall; } static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) { if (op->base.local_media){ @@ -702,8 +704,8 @@ int sal_call_terminate(SalOp *op){ if (op->dir == SalOpDirIncoming) { sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; - } else if (op->pending_inv_client_trans - && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_inv_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ + } else if (op->pending_client_trans + && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ cancelling_invite(op); break; } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 2f9b8484d..e42c827f1 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -23,33 +23,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new0(SalOp,1); __sal_op_init(op,sal); + op->type=SalOpUnknown; sal_op_ref(op); return op; } void sal_op_release(SalOp *op){ op->state=SalOpStateTerminated; + sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/ + if (op->registration_refresher) belle_sip_refresher_stop(op->registration_refresher); + 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]",op); + ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type)); if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); if (op->auth_info) sal_auth_info_delete(op->auth_info); if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); if (op->registration_refresher) { belle_sip_refresher_stop(op->registration_refresher); belle_sip_object_unref(op->registration_refresher); + op->registration_refresher=NULL; } if(op->replaces) belle_sip_object_unref(op->replaces); if(op->referred_by) belle_sip_object_unref(op->referred_by); - if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); + if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); __sal_op_free(op); return ; } void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ - /*for sure auth info will be accesible from the provider*/ - sal_process_authentication(op); + 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 ; } @@ -165,10 +175,10 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req 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 ( strcmp("INVITE",belle_sip_request_get_method(request))==0) { - if (op->pending_inv_client_trans) belle_sip_object_unref(op->pending_inv_client_trans); - op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ - belle_sip_object_ref(op->pending_inv_client_trans); + if ( strcmp("INVITE",belle_sip_request_get_method(request))==0 || strcmp("REGISTER",belle_sip_request_get_method(request))==0) { + 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 (add_contact) { contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 826246a28..a1e8a3e54 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -151,4 +151,5 @@ void sal_op_message_fill_cbs(SalOp*op) { op->callbacks.process_response_event=process_response_event; op->callbacks.process_timeout=process_timeout; op->callbacks.process_request_event=process_request_event; + op->type=SalOpMessage; } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index fe0597c20..dd5e7917c 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -573,6 +573,7 @@ void sal_op_presence_fill_cbs(SalOp*op) { op->callbacks.process_transaction_terminated=presence_process_transaction_terminated; op->callbacks.process_request_event=presence_process_request_event; op->callbacks.process_dialog_terminated=presence_process_dialog_terminated; + op->type=SalOpPresence; } /*presence publish */ diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 5ae44d93e..20b753330 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -19,15 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" - -static void register_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - SalOp* op = (SalOp*)user_ctx; - ms_error("register_process_io_error io error reported for [%s]",sal_op_get_proxy(op)); - if (op->registration_refresher) { - op->base.root->callbacks.register_failure(op,SalErrorFailure,SalErrorFailure,"io error"); - } -} - static void register_refresher_listener ( const belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code @@ -35,79 +26,49 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher SalOp* op = (SalOp*)user_pointer; SalError sal_err; SalReason sal_reason; + belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))); ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); - if(status_code ==200) { - op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->registration_refresher)>0); - } else if (status_code>=400) { - sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); - op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); - } else { - ms_warning("Register refresher know what to do with this status code"); + /*fix contact if needed*/ + if (op->base.root->nat_helper_enabled && belle_sip_refresher_get_nated_contact(refresher)) { + belle_sip_header_address_t* contact_address = BELLE_SIP_HEADER_ADDRESS(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_refresher_get_nated_contact(refresher)))); + sal_op_set_contact_address(op,(SalAddress*)contact_address); + belle_sip_object_unref(contact_address); } -} - -static void register_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); - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_response_t* response = belle_sip_response_event_get_response(event); - belle_sip_header_service_route_t* service_route; - belle_sip_header_address_t* service_route_address=NULL; - - int response_code = belle_sip_response_get_status_code(response); - if (response_code<200) return;/*nothing to do*/ - - - switch (response_code) { - case 200: { - + if(status_code ==200) { /*check service route rfc3608*/ + belle_sip_header_service_route_t* service_route; + belle_sip_header_address_t* service_route_address=NULL; if ((service_route=belle_sip_message_get_header_by_type(response,belle_sip_header_service_route_t))) { service_route_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(service_route))); } sal_op_set_service_route(op,(const SalAddress*)service_route_address); if (service_route_address) belle_sip_object_unref(service_route_address); - - op->base.root->callbacks.register_success(op,TRUE); - - if (/*expires>0 &&*/ !op->registration_refresher) { - op->registration_refresher = belle_sip_client_transaction_create_refresher(client_transaction); - belle_sip_refresher_set_listener(op->registration_refresher,register_refresher_listener,op); - } - - break; - } - - default:{ - + op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->registration_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. */ + 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); - ms_error("Unexpected answer [%s] for registration request bound to [%s]",belle_sip_response_get_reason_phrase(response),op->base.from); - op->base.root->callbacks.register_failure(op,SalErrorFailure,SalReasonUnknown,belle_sip_response_get_reason_phrase(response)); - break; - } -} -} -static void register_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { - SalOp* op = (SalOp*)user_ctx; - ms_error("register_process_timeout timeout error reported for [%s]",sal_op_get_proxy(op)); - if (!op->registration_refresher) { - op->base.root->callbacks.register_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout"); + sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); + if (belle_sip_refresher_get_auth_events(refresher) && (status_code == 401 || status_code==407)) { + /*add pending auth*/ + sal_add_pending_auth(op->base.root,op); + 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)); + } + op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); } else { - /*refresher will report error*/ + ms_warning("Register refresher know what to do with this status code"); } } -static void register_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - /*ms_error("register_process_transaction_terminated not implemented yet");*/ -} @@ -126,19 +87,30 @@ static int send_register_request_with_expires(SalOp* op, belle_sip_request_t* re int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; belle_sip_uri_t* req_uri; + op->type=SalOpRegister; sal_op_set_from(op,from); sal_op_set_to(op,from); sal_op_set_route(op,proxy); - op->callbacks.process_io_error=register_process_io_error; - op->callbacks.process_response_event=register_response_event; - op->callbacks.process_timeout=register_process_timeout; - op->callbacks.process_transaction_terminated=register_process_transaction_terminated; - 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*/ - return send_register_request_with_expires(op,req,expires); + if (send_register_request_with_expires(op,req,expires)) { + return -1; + } else { + if (op->registration_refresher) { + belle_sip_refresher_stop(op->registration_refresher); + belle_sip_object_unref(op->registration_refresher); + } + if ((op->registration_refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { + belle_sip_refresher_enable_nat_helper(op->registration_refresher,op->base.root->nat_helper_enabled); + belle_sip_refresher_set_listener(op->registration_refresher,register_refresher_listener,op); + return 0; + } else { + return -1; + } + + } } int sal_register_refresh(SalOp *op, int expires){ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index d4bfd43dc..7323573d4 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -726,7 +726,7 @@ static void register_success(SalOp *op, bool_t registered){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; - if (cfg->deletion_date!=0){ + if (!cfg || cfg->deletion_date!=0){ ms_message("Registration success for removed proxy config, ignored"); return; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8995fd069..e655bf9d7 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -246,7 +246,8 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ /* unregister */ - if (obj->state == LinphoneRegistrationOk) { + if (obj->state == LinphoneRegistrationOk + || obj->state == LinphoneRegistrationProgress) { sal_unregister(obj->op); } } diff --git a/gtk/logging.c b/gtk/logging.c index 15bef85e0..26027251f 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; diff --git a/include/sal/sal.h b/include/sal/sal.h index 0f78a4c8d..37068c4cd 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -478,6 +478,7 @@ int sal_call_notify_refer_state(SalOp *h, SalOp *newcall); /*Registration*/ int sal_register(SalOp *op, const char *proxy, const char *from, int expires); +/*refresh a register, -1 mean use the last known value*/ int sal_register_refresh(SalOp *op, int expires); int sal_unregister(SalOp *h); diff --git a/tester/register_tester.c b/tester/register_tester.c index 3d2afa1d0..fc74fe74f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -95,7 +95,7 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,late_auth_info?1:0); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); } diff --git a/tools/Makefile.am b/tools/Makefile.am index a93d809f1..8757ab27f 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -8,6 +8,7 @@ AM_CPPFLAGS=\ COMMON_CFLAGS=\ -DIN_LINPHONE \ $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) From 92caf1807cbee4ab4a2ac151412f360bbff0c218 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 11 Apr 2013 11:55:14 +0200 Subject: [PATCH 242/909] Fix dependency order for linphone tester WP8 project. --- build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index ff1e6eade..01b71d0c2 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -46,8 +46,16 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\windows\libilbc-rfc3951\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows\msilbc\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\windows\mssilk\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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From d18d8ff1230d33c81eed770bea017dfc8dbc2616 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 11 Apr 2013 12:06:35 +0200 Subject: [PATCH 243/909] Add AMR to the liblinphone tester WP8 project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 3 + .../LibLinphoneTester-wp8.sln | 86 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 1ffbcd88a..ee6923ae6 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -218,6 +218,9 @@ {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} + {072fad20-7007-4da2-b2e7-16ce2b219f67} diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index 01b71d0c2..6dab53c7a 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -57,6 +57,20 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\ms {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\windows\msamr\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\windows\msamr\vo-amrwbenc\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrnb\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrwb\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -389,6 +403,78 @@ Global {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32 {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.ActiveCfg = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.ActiveCfg = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.ActiveCfg = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Mixed Platforms.Build.0 = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.ActiveCfg = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Mixed Platforms.Build.0 = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.ActiveCfg = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Mixed Platforms.Build.0 = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a186e1670d9a01e5dfe0000a73389a2f3ed3976a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 11 Apr 2013 14:10:41 +0200 Subject: [PATCH 244/909] Add exports. --- coreapi/linphonecore.h | 2 +- coreapi/lpconfig.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ede4008b1..e9d29de99 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -936,7 +936,7 @@ LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable * callbacks) using linphone_core_get_user_data(). * @see linphone_core_new **/ -LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata); +LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata); /* function to be periodically called in a main loop */ /* For ICE to work properly it should be called every 20ms */ diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 02a4fe3c8..b3d2aa892 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -72,7 +72,7 @@ extern "C" { * @param filename the filename of the config file to read to fill the instantiated LpConfig * @see lp_config_new_with_factory */ -LpConfig * lp_config_new(const char *filename); +LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); /** * Instantiates a LpConfig object from a user config file and a factory config file. @@ -86,7 +86,7 @@ LpConfig * lp_config_new(const char *filename); * Therefore the configuration parameters defined in the user config file will be overwritten by the parameters * defined in the factory config file. */ -LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); +LINPHONE_PUBLIC LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); int lp_config_read_file(LpConfig *lpconfig, const char *filename); /** From 9186b3bb6fb61862a1c0ff69378dd5e9c26e436f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Apr 2013 14:25:46 +0200 Subject: [PATCH 245/909] check stream direction in session description --- coreapi/bellesip_sal/sal_sdp.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index a0586e824..2f1b763f0 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -168,7 +168,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal int valid_count = 0; char tmp[256], tmp2[256]; int nb=0; - + SalStreamDir stream_dir=SalStreamSendRecv; desc->n_active_streams = 0; desc->n_total_streams = 0; @@ -178,6 +178,18 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal if (belle_sdp_session_description_get_bandwidth(session_desc,"AS") >0) { desc->bandwidth=belle_sdp_session_description_get_bandwidth(session_desc,"AS"); } + /*in some very rare case, session attribute may set stream dir*/ + if (belle_sdp_session_description_get_attribute(session_desc,"sendrecv")) { + stream_dir=SalStreamSendRecv; + } else if (belle_sdp_session_description_get_attribute(session_desc,"sendonly")) { + stream_dir=SalStreamSendOnly; + } else if (belle_sdp_session_description_get_attribute(session_desc,"recvonly")) { + stream_dir=SalStreamRecvOnly; + } else if (belle_sdp_session_description_get_attribute(session_desc,"inactive")) { + stream_dir=SalStreamInactive; + } + + for(media_desc_it=belle_sdp_session_description_get_media_descriptions(session_desc) ;media_desc_it!=NULL ;media_desc_it=media_desc_it->next) { @@ -229,7 +241,7 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal } else if (belle_sdp_media_description_get_attribute(media_desc,"inactive")) { stream->dir=SalStreamInactive; } else { - stream->dir=SalStreamSendRecv; + stream->dir=stream_dir; /*takes default value if not present*/ } /* for each payload type */ From 9bbb1743b4d53dfe2f70d4ca9a3d853769aa9284 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Apr 2013 15:59:05 +0200 Subject: [PATCH 246/909] implement LinphoneAddress.setDomain & setUsername --- coreapi/linphonecore_jni.cc | 20 +++++++++++++++++-- .../linphone/core/LinphoneAddressImpl.java | 10 +++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 5046d83bb..4c96d7e9d 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1338,14 +1338,14 @@ 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; } @@ -1410,6 +1410,22 @@ extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDisplayName(JNIEnv linphone_address_set_display_name((LinphoneAddress*)address,displayName); if (displayName != NULL) env->ReleaseStringUTFChars(jdisplayName, displayName); } +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setUserName(JNIEnv* env + ,jobject thiz + ,jlong address + ,jstring juserName) { + const char* userName = juserName!= NULL?env->GetStringUTFChars(juserName, NULL):NULL; + linphone_address_set_username((LinphoneAddress*)address,userName); + if (userName != NULL) env->ReleaseStringUTFChars(juserName, userName); +} +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* env + ,jobject thiz + ,jlong address + ,jstring jdomain) { + const char* domain = jdomain!= NULL?env->GetStringUTFChars(jdomain, NULL):NULL; + linphone_address_set_domain((LinphoneAddress*)address,domain); + if (domain != NULL) env->ReleaseStringUTFChars(jdomain, domain); +} //CallLog diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index b9d290971..000ae52ab 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -30,6 +30,8 @@ public class LinphoneAddressImpl implements LinphoneAddress { private native String getDomain(long ptr); private native String toUri(long ptr); private native void setDisplayName(long ptr,String name); + private native void setDomain(long ptr,String domain); + private native void setUserName(long ptr,String username); private native String toString(long ptr); protected LinphoneAddressImpl(String identity) { @@ -37,7 +39,9 @@ public class LinphoneAddressImpl implements LinphoneAddress { } 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; @@ -85,7 +89,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { return getPortInt(); } public void setDomain(String domain) { - throw new RuntimeException("Not implemented"); + setDomain(nativePtr,domain); } public void setPort(String port) { throw new RuntimeException("Not implemented"); @@ -94,7 +98,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { throw new RuntimeException("Not implemented"); } public void setUserName(String username) { - throw new RuntimeException("Not implemented"); + setUserName(nativePtr,username); } } From 8b0cd3355750804aff64dc54e0642519a14d2204 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 11 Apr 2013 14:24:06 +0200 Subject: [PATCH 247/909] fix bug when choosing SDP connection address restore logs --- coreapi/linphonecall.c | 4 ++-- coreapi/linphonecore.c | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ab917920c..db3190bbb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -469,7 +469,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->op=sal_op_new(lc->sal); sal_op_set_user_pointer(call->op,call); call->core=lc; - linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); + linphone_core_get_local_ip(lc,NULL,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); sal_op_set_custom_header(call->op,call->params.custom_headers); @@ -528,7 +528,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } linphone_address_clean(from); - linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); + linphone_core_get_local_ip(lc,NULL,call->localip); linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e1d88b292..729df1fc6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1211,9 +1211,8 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const } 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); - linphone_core_set_log_level((OrtpLogLevel)lp_config_get_int(config,"misc","log_level",0)); + 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); } @@ -2170,9 +2169,6 @@ void linphone_core_iterate(LinphoneCore *lc){ } if (one_second_elapsed) { - if (ortp_get_log_level_mask() != lp_config_get_int(lc->config, "misc", "log_level", 0)) { - lp_config_set_int(lc->config, "misc", "log_level", ortp_get_log_level_mask()); - } if (lp_config_needs_commit(lc->config)) { lp_config_sync(lc->config); } From 6bd36ceb669bb63017c78a9d1f152f1a2de64108 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 11 Apr 2013 14:34:04 +0200 Subject: [PATCH 248/909] Added GetTime method to LinphoneChatMessage java impl --- coreapi/linphonecore_jni.cc | 6 ++++++ java/common/org/linphone/core/LinphoneChatMessage.java | 6 ++++++ java/impl/org/linphone/core/LinphoneChatMessageImpl.java | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index ddc26f657..5046d83bb 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1871,6 +1871,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(J 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" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env ,jobject thiz ,jlong ptr diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 3a2a45718..b6b6c30ec 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -106,4 +106,10 @@ 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(); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 1373708ca..2a256f2f5 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -8,6 +8,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { 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); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -64,4 +65,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public String getCustomHeader(String name) { return getCustomHeader(nativePtr,name); } + + public long getTime() { + return getTime(nativePtr); + } } From dfb316ea7cc1b3a193f53e12b7e45b69616c22e0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 11 Apr 2013 15:39:25 +0200 Subject: [PATCH 249/909] Add the linphone_core_new_with_config() function to instantiate a LinphoneCore given an already existing LpConfig. This enables the creation of the LpConfig before creating the LinphoneCore. It is useful on some systems to read some configuration parameters and perform some customization before creating the LinphoneCore. The LpConfig can now also be created given a factory config filename using the new lp_config_new_with_factory() function. --- coreapi/linphonecore.c | 20 +++++++++++--------- coreapi/linphonecore.h | 14 ++++++++++++++ coreapi/lpconfig.c | 19 +++++++++++++------ coreapi/lpconfig.h | 22 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 729df1fc6..edf11a407 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1218,11 +1218,11 @@ static void misc_config_read (LinphoneCore *lc) { -static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, - const char *factory_config_path, void * userdata) +static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata) { ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); + lc->config=config; lc->data=userdata; lc->ringstream_autorelease=TRUE; @@ -1299,10 +1299,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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); @@ -1348,13 +1344,19 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta * 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(). - * + * @see linphone_core_new_with_config **/ 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); + LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path); + return linphone_core_new_with_config(vtable, config, userdata); +} + +LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) +{ + LinphoneCore *core = ms_new(LinphoneCore, 1); + linphone_core_init(core, vtable, config, userdata); return core; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f8e1dcb88..5ae73cc4d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -913,6 +913,20 @@ const char *linphone_core_get_user_agent_version(void); LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config, void* userdata); +/** + * Instantiates a LinphoneCore object with a given LpConfig. + * @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 a pointer to an LpConfig object holding the configuration of the LinphoneCore to be instantiated. + * @param userdata an opaque user pointer that can be retrieved at any time (for example in + * callbacks) using linphone_core_get_user_data(). + * @see linphone_core_new +**/ +LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata); + /* function to be periodically called in a main loop */ /* For ICE to work properly it should be called every 20ms */ void linphone_core_iterate(LinphoneCore *lc); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index dd3de63db..ca65fd1ff 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -211,19 +211,23 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ } LpConfig * lp_config_new(const char *filename){ + return lp_config_new_with_factory(filename, NULL); +} + +LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); - if (filename!=NULL){ - ms_message("Using (r/w) config information from %s", filename); - lpconfig->filename=ortp_strdup(filename); - lpconfig->file=fopen(filename,"r+"); + if (config_filename!=NULL){ + ms_message("Using (r/w) config information from %s", config_filename); + lpconfig->filename=ortp_strdup(config_filename); + lpconfig->file=fopen(config_filename,"r+"); if (lpconfig->file!=NULL){ struct stat fileStat; lp_config_parse(lpconfig,lpconfig->file); fclose(lpconfig->file); #if !defined(_WIN32_WCE) - if ((stat(filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { + if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { /* make existing configuration files non-group/world-accessible */ - if (chmod(filename, S_IRUSR | S_IWUSR) == -1) { + if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) { ms_warning("unable to correct permissions on " "configuration file: %s", strerror(errno)); } @@ -233,6 +237,9 @@ LpConfig * lp_config_new(const char *filename){ lpconfig->modified=0; } } + if (factory_config_filename != NULL) { + lp_config_read_file(lpconfig, factory_config_filename); + } return lpconfig; } diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 310baaff3..43f761adb 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -65,7 +65,29 @@ extern "C" { (config) ? (lp_config_get_float(config, "default_values", name, default)) : (default) +/** + * Instantiates a LpConfig object from a user config file. + * + * @ingroup misc + * @param filename the filename of the config file to read to fill the instantiated LpConfig + * @see lp_config_new_with_factory + */ LpConfig * lp_config_new(const char *filename); + +/** + * Instantiates a LpConfig object from a user config file and a factory config file. + * + * @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. + */ +LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_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. From c06e9c7060dbbbf7daa0847efdf951d8ec2d91c2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 11 Apr 2013 16:36:40 +0200 Subject: [PATCH 250/909] try to fix date issues --- coreapi/sal_eXosip2.c | 2 +- coreapi/sal_eXosip2_presence.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index b86fc26e0..1bbbe36e6 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1798,7 +1798,7 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; } - ret.tm_isdst=-1; + ret.tm_isdst=0; }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent."); content_type= osip_message_get_content_type(ev->request); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index ffa7ed920..1b64fe429 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -81,23 +81,28 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); } -#ifdef WIN32 +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 inline char *my_ctime_r(const time_t *t, char *buf){ - strcpy(buf,ctime(t)); - return buf; +static void msg_add_current_date(osip_message_t *msg){ + char tmp[64]={0}; + time_t curtime=time(NULL); + struct tm *ret; +#ifndef WIN32 + struct tm gmt; + ret=gmtime_r(&curtime,&gmt); +#else + ret=gmtime(&curtime); +#endif + /*cannot use strftime because it is locale dependant*/ + snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", + days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); + osip_message_replace_header(msg,"Date",tmp); } -#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; - char t[26]; - time_t curtime=time(NULL); - - my_ctime_r(&curtime,t); if(op->cid == -1) { @@ -113,7 +118,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co 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,t); + msg_add_current_date(sip); osip_message_set_content_type(sip,content_type); if (msg) osip_message_set_body(sip,msg,strlen(msg)); sal_add_other(op->base.root,op,sip); @@ -136,7 +141,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co return -1; } sal_exosip_add_custom_headers(sip,op->base.custom_headers); - osip_message_set_date(sip,t); + msg_add_current_date(sip); osip_message_set_content_type(sip,content_type); if (msg) osip_message_set_body(sip,msg,strlen(msg)); eXosip_call_send_request(op->did,sip); From 4a395bfb7280d1c8344e80f76876d2b9275c0fe5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Apr 2013 17:47:30 +0200 Subject: [PATCH 251/909] make sure terminate call does nothing if call in state LinphoneCallReleased or LinphoneCallEnd --- coreapi/linphonecore.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9731d773e..bb257e60b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3269,14 +3269,26 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { call = the_call; } + switch (call->state) { + case LinphoneCallReleased: + case LinphoneCallEnd: + ms_warning("No need to terminate a call [%p] in sate [%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; + } - if (call->state != LinphoneCallOutgoingInit) + default: sal_call_terminate(call->op); - else { - /* In state OutgoingInit, op has to be destroyed */ - sal_op_release(call->op); - call->op = NULL; + break; } + terminate_call(lc,call); return 0; } From e31fbfa473b7df360eb8626f7ca269a7a2cf9df0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 11 Apr 2013 18:02:53 +0200 Subject: [PATCH 252/909] Fix java impl for LinphoneMessage.GetTime --- java/impl/org/linphone/core/LinphoneChatMessageImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 2a256f2f5..8162f67bf 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -67,6 +67,6 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { } public long getTime() { - return getTime(nativePtr); + return getTime(nativePtr) * 1000; // Need milliseconds, not seconds } } From 746044621139bbbeb9d1bbea2a6e884ef1737bbf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Apr 2013 21:04:34 +0200 Subject: [PATCH 253/909] log mask must not be declared static --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 9f51aa254..1172caa98 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 9f51aa254fc5c24834614612036485406a8d06a7 +Subproject commit 1172caa98c7fc70d98bf6e508699a9bead5e9592 From 7d4a50043e3f39735f85d9491470d9c5d8229252 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Apr 2013 08:58:57 +0200 Subject: [PATCH 254/909] fix various compilation issue --- gtk/logging.c | 1 + oRTP | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/logging.c b/gtk/logging.c index 15bef85e0..26027251f 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; diff --git a/oRTP b/oRTP index 9f51aa254..1172caa98 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 9f51aa254fc5c24834614612036485406a8d06a7 +Subproject commit 1172caa98c7fc70d98bf6e508699a9bead5e9592 From e2b864ace969ba2052b4ecf792eaf0bdccce347a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 12 Apr 2013 10:26:57 +0200 Subject: [PATCH 255/909] Set UTC time in received chat messages. --- coreapi/sal_eXosip2.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 1bbbe36e6..75ee46298 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1771,6 +1771,26 @@ static bool_t comes_from_local_if(osip_message_t *msg){ static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; +static int utc_offset() { + time_t ref = 24 * 60 * 60L; + struct tm * timeptr; + int gmtime_hours; + + /* get the local reference time for Jan 2, 1900 00:00 UTC */ + timeptr = localtime(&ref); + gmtime_hours = timeptr->tm_hour; + + /* if the local time is the "day before" the UTC, subtract 24 hours + from the hours to get the UTC offset */ + if (timeptr->tm_mday < 2) gmtime_hours -= 24; + + return gmtime_hours; +} + +time_t mktime_utc(struct tm *timeptr) { + return mktime(timeptr) + utc_offset() * 3600; +} + static void text_received(Sal *sal, eXosip_event_t *ev){ osip_body_t *body=NULL; char *from=NULL,*msg=NULL; @@ -1842,7 +1862,7 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ 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); + salmsg.time=date!=NULL ? mktime_utc(&ret) : time(NULL); sal->callbacks.text_received(op,&salmsg); sal_op_release(op); osip_free(from); From 71a7738d39aac992ffc4b69c777e61f1374fd258 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 12 Apr 2013 15:42:22 +0200 Subject: [PATCH 256/909] Fix belle-sip logs (restore code that was erased by merge). --- coreapi/linphonecore.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bb257e60b..e8a5fc3dc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -424,6 +424,11 @@ void linphone_core_set_log_file(FILE *file) { void linphone_core_set_log_level(OrtpLogLevel loglevel) { ortp_set_log_level_mask(loglevel); + if (loglevel == 0) { + sal_disable_logs(); + } else { + sal_enable_logs(); + } } /** From 08e97faec539341e057a87f0c50f011d0964e421 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 15 Apr 2013 11:41:49 +0200 Subject: [PATCH 257/909] Fix the "TCP register compatibility mode" test. --- tester/register_tester.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tester/register_tester.c b/tester/register_tester.c index fc74fe74f..22237066a 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -170,10 +170,12 @@ static void simple_tcp_register(){ } static void simple_tcp_register_compatibility_mode(){ + char route[256]; LinphoneCore* lc; LCSipTransports transport = {0,5070,0,0}; + sprintf(route,"sip:%s",test_route); lc = create_lc(); - register_with_refresh_base_2(lc,FALSE,test_domain,NULL,FALSE,transport); + register_with_refresh_base_2(lc,FALSE,test_domain,route,FALSE,transport); } From 37fe205a03dcd098f12ee13443a8fdcb8be7f276 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 15 Apr 2013 11:42:33 +0200 Subject: [PATCH 258/909] Execute the "TLS register" test on Android. --- tester/register_tester.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tester/register_tester.c b/tester/register_tester.c index 22237066a..3522617bb 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -343,9 +343,7 @@ test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, -#ifndef ANDROID { "TLS register", simple_tls_register }, -#endif { "Simple authenticated register", simple_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, From 09c72b6ecb14b8d6185803223580bcd90ee2909f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 15 Apr 2013 12:12:50 +0200 Subject: [PATCH 259/909] Fix the "Text message compatibility mode" test. --- tester/message_tester.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index 140a369f9..47ab8d1cc 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -73,6 +73,7 @@ static void text_message(void) { linphone_core_manager_destroy(pauline); } static void text_message_compatibility_mode(void) { + char route[256]; LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneProxyConfig* proxy; @@ -88,7 +89,8 @@ static void text_message_compatibility_mode(void) { linphone_address_clean(proxy_address); tmp=linphone_address_as_string_uri_only(proxy_address); linphone_proxy_config_set_server_addr(proxy,tmp); - linphone_proxy_config_set_route(proxy,NULL); + 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); From 5690d65d0bdd7f3a0e53df6dc1918744b89d4a69 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 15 Apr 2013 12:18:39 +0200 Subject: [PATCH 260/909] Fix the "Simple call compatibility mode" test. --- tester/call_tester.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 64d19c2cb..65de848ec 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -198,6 +198,7 @@ static void simple_call(void) { linphone_core_manager_destroy(pauline); } static void simple_call_compatibility_mode(void) { + char route[256]; LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -220,7 +221,8 @@ static void simple_call_compatibility_mode(void) { linphone_address_clean(proxy_address); tmp=linphone_address_as_string_uri_only(proxy_address); linphone_proxy_config_set_server_addr(proxy,tmp); - linphone_proxy_config_set_route(proxy,NULL); + 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); From f8f00c09e333a0e80e80d4cc49d14388d4d03667 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Apr 2013 13:00:34 +0200 Subject: [PATCH 261/909] fix memory leak in gtk fix indentation (had spaces instead of tabs) update ms2 --- gtk/chat.c | 90 +++++++++++++++++++++++++------------------------- mediastreamer2 | 2 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 4fa1c917c..58f1a23ce 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -148,12 +148,13 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, 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_buffer_insert(buffer,&iter,"\n",-1); + ms_free(from_message); g_object_set_data(G_OBJECT(w),"from_message",from_str); } - gtk_text_buffer_get_end_iter(buffer,&iter); + gtk_text_buffer_get_end_iter(buffer,&iter); gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,linphone_chat_message_get_text(msg),-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_end_iter(buffer,&iter); + gtk_text_buffer_insert(buffer,&iter,"\n",-1); gtk_text_buffer_get_end_iter(buffer,&iter); t=linphone_chat_message_get_time(msg); switch (linphone_chat_message_get_state (msg)){ @@ -260,9 +261,9 @@ static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageS } void linphone_gtk_send_text(){ - GtkWidget *main_window=linphone_gtk_get_main_window(); + 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"); GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry"); const gchar *entered; LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); @@ -271,7 +272,7 @@ void linphone_gtk_send_text(){ LinphoneChatMessage *msg; 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(), + linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), TRUE,cr,msg,FALSE); gtk_entry_set_text(GTK_ENTRY(entry),""); } @@ -438,58 +439,57 @@ void linphone_gtk_chat_close(GtkWidget *button){ } -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"); - char *from=linphone_address_as_string(linphone_chat_message_get_from(msg)); - - w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - if(w!=NULL){ - char *from_chatview=(char *)g_object_get_data(G_OBJECT(friendlist),"from"); - if(g_strcmp0(from,from_chatview)==0){ + GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" ); + char *from=linphone_address_as_string ( linphone_chat_message_get_from ( msg ) ); + + w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); + if ( w!=NULL ) { + char *from_chatview= ( char * ) g_object_get_data ( G_OBJECT ( friendlist ),"from" ); + if ( g_strcmp0 ( from,from_chatview ) ==0 ) { send=TRUE; } else { - if(!linphone_gtk_friend_list_is_contact(linphone_chat_message_get_from(msg))){ - linphone_gtk_chat_add_contact(linphone_chat_message_get_from(msg)); - } + 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 { + } + } else { send=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)); - } - w=linphone_gtk_init_chatroom(room,linphone_chat_message_get_from(msg)); - g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)w); - g_object_set_data(G_OBJECT(friendlist),"from",from); - } - get_display_name(linphone_chat_message_get_from(msg)); - - #ifdef HAVE_GTK_OSXs + 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 ); + g_object_set_data ( G_OBJECT ( friendlist ),"from",from ); + } + +#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)); + 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)); + g_object_set_data ( G_OBJECT ( w ),"is_notified",GINT_TO_POINTER ( FALSE ) ); } } - #endif - if(send){ - if(gtk_notebook_get_current_page(notebook)!=gtk_notebook_page_num(notebook,w)){ +#endif + if ( send ) { + if ( gtk_notebook_get_current_page ( notebook ) !=gtk_notebook_page_num ( notebook,w ) ) { linphone_gtk_show_friends(); } else { - linphone_chat_room_mark_as_read(room); + linphone_chat_room_mark_as_read ( room ); } - linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), - FALSE,room,msg,FALSE); + linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), + FALSE,room,msg,FALSE ); } else { linphone_gtk_show_friends(); } diff --git a/mediastreamer2 b/mediastreamer2 index 4f93003c1..25b0496db 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4f93003c1eade1442fdedd8dee10f18c98ec47c3 +Subproject commit 25b0496dbc62183f195528481fe44c73e0d201e9 From 2062792139a01be162cac734d9dba013871e1ec4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 17 Apr 2013 12:00:17 +0200 Subject: [PATCH 262/909] add support for dtmfs in SIP INFO --- coreapi/bellesip_sal/sal_op_call.c | 19 +++++++++++++++++-- coreapi/bellesip_sal/sal_op_impl.c | 5 ++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 0bf1f2440..b21a3ea75 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -687,10 +687,25 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ } return h->result; } + int sal_call_send_dtmf(SalOp *h, char dtmf){ - ms_fatal("sal_call_send_dtmf not implemented yet"); - return -1; + if (h->dialog){ + belle_sip_request_t *req=belle_sip_dialog_create_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; /*no dialog = dialog in NULL state*/ op->state=SalOpStateTerminating; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index e42c827f1..634e93cd5 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -86,6 +86,7 @@ belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_fro belle_sip_object_unref(req_uri); return contact_header; } + 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; @@ -109,7 +110,6 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_via_new(), 70); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->base.root->user_agent)); return req; } @@ -180,6 +180,9 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_object_ref(op->pending_client_trans); } + if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); + if (add_contact) { contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT); From da89be1d127cc89640830795ba71f7f841b9ecf6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 17 Apr 2013 14:41:27 +0200 Subject: [PATCH 263/909] Added missing LINPHONE_EXPORTS --- build/vsx/LibLinphone/LibLinphone.vcxproj | 4 +- coreapi/linphone_tunnel.h | 42 ++-- coreapi/linphonecore.h | 260 +++++++++++----------- coreapi/linphonecore_utils.h | 6 +- coreapi/linphonefriend.h | 2 +- 5 files changed, 158 insertions(+), 156 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index ee6923ae6..269e5351f 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -125,7 +125,7 @@ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false false - Async + SyncCThrow Console @@ -189,6 +189,7 @@ + @@ -206,6 +207,7 @@ + diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index e42a054dc..54b598b71 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -53,7 +53,7 @@ typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig; /** * Create a new tunnel configuration */ -LinphoneTunnelConfig *linphone_tunnel_config_new(); +LINPHONE_PUBLIC LinphoneTunnelConfig *linphone_tunnel_config_new(); /** * Set address of server. @@ -61,14 +61,14 @@ LinphoneTunnelConfig *linphone_tunnel_config_new(); * @param tunnel configuration object * @param host tunnel server ip address */ -void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host); +LINPHONE_PUBLIC void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host); /** * Get address of server. * * @param tunnel configuration object */ -const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); /** * Set tls port of server. @@ -76,14 +76,14 @@ const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); * @param tunnel configuration object * @param port tunnel server tls port, recommended value is 443 */ -void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port); +LINPHONE_PUBLIC void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port); /** * Get tls port of server. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); /** * Set the remote port on the tunnel server side used to test udp reachability. @@ -91,14 +91,14 @@ int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); * @param tunnel configuration object * @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability, set to -1 to disable the feature */ -void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port); +LINPHONE_PUBLIC void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port); /** * Get the remote port on the tunnel server side used to test udp reachability. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel); /** * Set the udp packet round trip delay in ms for a tunnel configuration. @@ -106,21 +106,21 @@ int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig * @param tunnel configuration object * @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms. */ -void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay); +LINPHONE_PUBLIC void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay); /** * Get the udp packet round trip delay in ms for a tunnel configuration. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); /** * Destroy a tunnel configuration * * @param tunnel configuration object */ -void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); /** * Add tunnel server configuration @@ -128,7 +128,7 @@ void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); * @param tunnel object * @param tunnel_config object */ -void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); +LINPHONE_PUBLIC void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); /** * Remove tunnel server configuration @@ -136,19 +136,19 @@ void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tu * @param tunnel object * @param tunnel_config object */ -void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); +LINPHONE_PUBLIC void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); /** * @param tunnel object * returns a string of space separated list of host:port of tunnel server addresses * */ -const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel); /** * @param tunnel object * Removes all tunnel server address previously entered with addServer() **/ -void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); /** * Sets whether tunneling of SIP and RTP is required. @@ -157,13 +157,13 @@ void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode. * **/ -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); +LINPHONE_PUBLIC void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); /** * @param tunnel object * Returns a boolean indicating whether tunneled operation is enabled. **/ -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); /** * @param tunnel object @@ -172,7 +172,7 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); * won't be notified promptly that its connection is now zombie, so it is recommended to call this method that will cause * the lost connection to be closed and new connection to be issued. **/ -void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); /** * Start tunnel need detection. @@ -181,7 +181,7 @@ void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); *
In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on. *
Call this method each time to run the auto detection algorithm */ -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); /** * Set an optional http proxy to go through when connecting to tunnel server. @@ -191,7 +191,7 @@ void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. * @param password optional http proxy password. Use NULL if not needed. **/ -void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); +LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); /** * Retrieve optional http proxy configuration previously set with linphone_tunnel_set_http_proxy(). @@ -201,9 +201,9 @@ void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, in * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. * @param password optional http proxy password. Use NULL if not needed. **/ -void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd); +LINPHONE_PUBLIC void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd); -void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); +LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e9d29de99..6c7a8843e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -111,12 +111,12 @@ LINPHONE_PUBLIC 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 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); +LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, const char *port); +LINPHONE_PUBLIC 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); @@ -189,8 +189,8 @@ LINPHONE_PUBLIC void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, voi LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl); +LINPHONE_PUBLIC const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl); LINPHONE_PUBLIC const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl); LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl); @@ -203,24 +203,24 @@ struct _LinphoneCallParams; **/ 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 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp); +LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp); +LINPHONE_PUBLIC void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e); +LINPHONE_PUBLIC void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled); +LINPHONE_PUBLIC bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp); +LINPHONE_PUBLIC bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp); +LINPHONE_PUBLIC void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw); +LINPHONE_PUBLIC void linphone_call_params_destroy(LinphoneCallParams *cp); +LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp); +LINPHONE_PUBLIC void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); +LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path); +LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); +LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); +LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); /** * Enum describing failure reasons. * @ingroup initializing @@ -406,28 +406,28 @@ bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); -const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); bool_t linphone_call_camera_enabled(const LinphoneCall *lc); int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); -const char *linphone_call_get_remote_user_agent(LinphoneCall *call); +LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call); LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call); -float linphone_call_get_play_volume(LinphoneCall *call); -float linphone_call_get_record_volume(LinphoneCall *call); -float linphone_call_get_current_quality(LinphoneCall *call); -float linphone_call_get_average_quality(LinphoneCall *call); -const char* linphone_call_get_authentication_token(LinphoneCall *call); -bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); -void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); +LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_get_average_quality(LinphoneCall *call); +LINPHONE_PUBLIC const char* linphone_call_get_authentication_token(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); LINPHONE_PUBLIC void linphone_call_send_vfu_request(LinphoneCall *call); LINPHONE_PUBLIC void *linphone_call_get_user_pointer(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); -void linphone_call_start_recording(LinphoneCall *call); -void linphone_call_stop_recording(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); /** * Return TRUE if this call is currently part of a conference *@param call #LinphoneCall @@ -435,7 +435,7 @@ void linphone_call_stop_recording(LinphoneCall *call); * @ingroup call_control */ -bool_t linphone_call_is_in_conference(const LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_is_in_conference(const LinphoneCall *call); /** * Enables or disable echo cancellation for this call * @param call @@ -443,13 +443,13 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call); * * @ingroup media_parameters **/ -void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; +LINPHONE_PUBLIC void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; /** * Returns TRUE if echo cancellation is enabled. * * @ingroup media_parameters **/ -bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); +LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); /** * Enables or disable echo limiter for this call * @param call @@ -457,13 +457,13 @@ bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); * * @ingroup media_parameters **/ -void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); +LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); /** * Returns TRUE if echo limiter is enabled. * * @ingroup media_parameters **/ -bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); /*keep this in sync with mediastreamer2/msvolume.h*/ @@ -544,17 +544,17 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxy LINPHONE_PUBLIC 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 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); +LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC 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); +LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); 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); +LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); /* @@ -917,9 +917,9 @@ LINPHONE_PUBLIC void linphone_core_set_log_level(OrtpLogLevel loglevel); LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file); LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); LINPHONE_PUBLIC void linphone_core_disable_logs(void); -const char *linphone_core_get_version(void); -const char *linphone_core_get_user_agent_name(void); -const char *linphone_core_get_user_agent_version(void); +LINPHONE_PUBLIC const char *linphone_core_get_version(void); +LINPHONE_PUBLIC const char *linphone_core_get_user_agent_name(void); +LINPHONE_PUBLIC const char *linphone_core_get_user_agent_version(void); LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config, void* userdata); @@ -961,17 +961,17 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc); #endif /*sets the user-agent string in sip messages, ideally called just after linphone_core_new() or linphone_core_init() */ -void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const char *version); +LINPHONE_PUBLIC void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const char *version); -LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); +LINPHONE_PUBLIC LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); LINPHONE_PUBLIC LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); -LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); -LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); @@ -979,75 +979,75 @@ LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, Lin LINPHONE_PUBLIC bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); -bool_t linphone_core_in_call(const LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_in_call(const LinphoneCore *lc); LINPHONE_PUBLIC LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri); -int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); +LINPHONE_PUBLIC int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); LINPHONE_PUBLIC int linphone_core_terminate_all_calls(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_pause_all_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_pause_all_calls(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); LINPHONE_PUBLIC int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); -int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); /** * @ingroup media_parameters * Get default call parameters reflecting current linphone core configuration * @param LinphoneCore object * @return LinphoneCallParams */ -LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); -LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); +LINPHONE_PUBLIC LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); LINPHONE_PUBLIC void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); -int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); +LINPHONE_PUBLIC int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); -const char *linphone_core_get_primary_contact(LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_primary_contact(LinphoneCore *lc); -const char * linphone_core_get_identity(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); -bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); -void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); -LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc); -const char * linphone_core_get_identity(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); /*0= no bandwidth limit*/ -void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw); -void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); +LINPHONE_PUBLIC void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw); +LINPHONE_PUBLIC void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); -int linphone_core_get_download_bandwidth(const LinphoneCore *lc); -int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_download_bandwidth(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled); bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc); -void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); -int linphone_core_get_download_ptime(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); +LINPHONE_PUBLIC int linphone_core_get_download_ptime(LinphoneCore *lc); -void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); +LINPHONE_PUBLIC void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); -int linphone_core_get_upload_ptime(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *lc); /* returns a MSList of PayloadType */ LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); @@ -1091,11 +1091,11 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadT */ LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; -int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); +LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); -const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); +LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); -bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); +LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); /** * @ingroup proxy @@ -1147,37 +1147,37 @@ int linphone_core_get_video_jittcomp(LinphoneCore *lc); void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value); -int linphone_core_get_audio_port(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_audio_port(const LinphoneCore *lc); -void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port); +LINPHONE_PUBLIC void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port); -int linphone_core_get_video_port(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_video_port(const LinphoneCore *lc); -void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port); +LINPHONE_PUBLIC void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port); -int linphone_core_get_nortp_timeout(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_nortp_timeout(const LinphoneCore *lc); -void linphone_core_set_audio_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_audio_port(LinphoneCore *lc, int port); -void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port); +LINPHONE_PUBLIC void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port); -void linphone_core_set_video_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_video_port(LinphoneCore *lc, int port); -void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port); +LINPHONE_PUBLIC void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port); -void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); -void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); +LINPHONE_PUBLIC void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); -bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc); -void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833); +LINPHONE_PUBLIC void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833); -bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); -void linphone_core_set_sip_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_sip_port(LinphoneCore *lc, int port); -int linphone_core_get_sip_port(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_sip_port(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); @@ -1190,21 +1190,21 @@ 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); +LINPHONE_PUBLIC void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); -const char * linphone_core_get_stun_server(const LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *lc); /** * @ingroup network_parameters @@ -1240,9 +1240,9 @@ void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); const char *linphone_core_get_nat_address(const LinphoneCore *lc); -void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol); +LINPHONE_PUBLIC void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol); -LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); const char * linphone_core_get_relay_addr(const LinphoneCore *lc); @@ -1254,16 +1254,16 @@ 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); +LINPHONE_PUBLIC int linphone_core_get_ring_level(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_play_level(LinphoneCore *lc); int linphone_core_get_rec_level(LinphoneCore *lc); -void linphone_core_set_ring_level(LinphoneCore *lc, int level); -void linphone_core_set_play_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC void linphone_core_set_ring_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC void linphone_core_set_play_level(LinphoneCore *lc, int level); -void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level); -float linphone_core_get_mic_gain_db(LinphoneCore *lc); -void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level); -float linphone_core_get_playback_gain_db(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level); +LINPHONE_PUBLIC float linphone_core_get_mic_gain_db(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level); +LINPHONE_PUBLIC float linphone_core_get_playback_gain_db(LinphoneCore *lc); void linphone_core_set_rec_level(LinphoneCore *lc, int level); const char * linphone_core_get_ringer_device(LinphoneCore *lc); @@ -1287,11 +1287,11 @@ void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *); const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc); int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); -void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); -bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); -void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); -bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); +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); @@ -1371,13 +1371,13 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show); /*play/record support: use files instead of soundcard*/ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); -void linphone_core_set_play_file(LinphoneCore *lc, const char *file); +LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file); void linphone_core_set_record_file(LinphoneCore *lc, const char *file); LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); -int linphone_core_get_current_call_duration(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_current_call_duration(const LinphoneCore *lc); int linphone_core_get_mtu(const LinphoneCore *lc); @@ -1400,12 +1400,12 @@ 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_set_user_data(LinphoneCore *lc, void *userdata); @@ -1464,12 +1464,12 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); const LinphoneCall* linphone_core_find_call_from_uri(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); 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); @@ -1481,7 +1481,7 @@ int linphone_core_stop_conference_recording(LinphoneCore *lc); * @param lc core * @return max number of simultaneous calls */ -int linphone_core_get_max_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_max_calls(LinphoneCore *lc); /** * Set the maximum number of simultaneous calls Linphone core can manage at a time. All new call above this limit are declined with a busy answer * @ingroup initializing @@ -1490,9 +1490,9 @@ int linphone_core_get_max_calls(LinphoneCore *lc); */ LINPHONE_PUBLIC void linphone_core_set_max_calls(LinphoneCore *lc, int max); -bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); -bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); +LINPHONE_PUBLIC bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); /** * Choose media encryption policy to be used for RTP packets @@ -1500,28 +1500,28 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone 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); +LINPHONE_PUBLIC 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 */ -void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); +LINPHONE_PUBLIC void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); /** * Init call params using LinphoneCore's current configuration */ -void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params); +LINPHONE_PUBLIC void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params); /** * True if tunnel support was compiled. */ -bool_t linphone_core_tunnel_available(void); +LINPHONE_PUBLIC bool_t linphone_core_tunnel_available(void); typedef struct _LinphoneTunnel LinphoneTunnel; /** * get tunnel instance if available */ -LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp); int linphone_core_get_sip_dscp(const LinphoneCore *lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index cc0a6f692..f387a7277 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -69,7 +69,7 @@ typedef void (*LinphoneEcCalibrationCallback)(LinphoneCore *lc, LinphoneEcCalibr * * 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, 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 +93,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 abe21b5a2..b8a041b14 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -222,7 +222,7 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); * @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved * @param os #LinphoneOnlineStatus */ -void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); +LINPHONE_PUBLIC 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 From 1f9b0812a080b91ff4d1e2dc67b612996370e23d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 17 Apr 2013 15:49:34 +0200 Subject: [PATCH 264/909] fix publish request, whose request uri must identify the resources for which the event is to be published. --- coreapi/sal_eXosip2.c | 8 ++++---- coreapi/sal_eXosip2.h | 2 ++ coreapi/sal_eXosip2_presence.c | 11 +++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 75ee46298..e577b6422 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -2317,7 +2317,7 @@ static void register_set_contact(osip_message_t *msg, const char *contact){ osip_uri_uparam_add(ct->url,osip_strdup("line"),line); } -static void sal_register_add_route(osip_message_t *msg, const char *proxy){ +void sal_message_add_route(osip_message_t *msg, const char *proxy){ osip_route_t *route; osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free); @@ -2364,7 +2364,7 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ 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_message_add_route(msg,proxy); sal_add_register(h->base.root,h); }else{ ms_error("Could not build initial register."); @@ -2374,7 +2374,7 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ }else{ eXosip_lock(); eXosip_register_build_register(h->rid,expires,&msg); - sal_register_add_route(msg,proxy); + sal_message_add_route(msg,proxy); } if (msg){ eXosip_register_send_register(h->rid,msg); @@ -2412,7 +2412,7 @@ int sal_register_refresh(SalOp *op, int expires){ 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)); + sal_message_add_route(msg,sal_op_get_route(op)); eXosip_register_send_register(op->rid,msg); }else ms_error("Could not build REGISTER refresh message."); eXosip_unlock(); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 68a2d05ef..e00dd64d9 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -99,4 +99,6 @@ SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg); void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)); +void sal_message_add_route(osip_message_t *msg, const char *proxy); + #endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 1b64fe429..c81910986 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -637,23 +637,26 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p osip_message_t *pub; int i; char buf[1024]; + const char *route=sal_op_get_route(op); mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - i = eXosip_build_publish(&pub,from, to, sal_op_get_route(op), "presence", "300", + i = eXosip_build_publish(&pub,to, from, NULL, "presence", "600", presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); if (i<0){ ms_warning("Failed to build publish request."); return -1; } - + if (route) + sal_message_add_route(pub,route); + eXosip_lock(); i = eXosip_publish(pub, to); /* should update the sip-if-match parameter from sip-etag from last 200ok of PUBLISH */ eXosip_unlock(); if (i<0){ - ms_message("Failed to send publish request."); - return -1; + ms_message("Failed to send publish request."); + return -1; } sal_add_other(sal_op_get_sal(op),op,pub); return 0; From 8b571c2edfb8e05f9e822c7c0516f000efd27fd8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 18 Apr 2013 10:57:09 +0200 Subject: [PATCH 265/909] Added missing export --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6c7a8843e..28272fe51 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -355,8 +355,8 @@ struct _LinphoneCallStats { * @} **/ -const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); -const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); /** Callback prototype */ From 46bf8a0684a8cac925bd0664b1d007c0628e894f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 18 Apr 2013 15:43:47 +0200 Subject: [PATCH 266/909] add ICE support to SDP parser/writer. add a test to check basic ICE functionality. --- coreapi/bellesip_sal/sal_sdp.c | 517 +++++++++++++++++++++------------ tester/call_tester.c | 47 ++- 2 files changed, 382 insertions(+), 182 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 2f1b763f0..9efb449fb 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -19,128 +19,221 @@ 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)) -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; + +static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){ + char buffer[1024]; + const SalIceCandidate *candidate; + int nb; + int i; + + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { + candidate = &desc->ice_candidates[i]; + if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; + nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", + candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + if (candidate->raddr[0] != '\0') { + nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + } + belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("candidate",buffer)); + } +} + +static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){ + char buffer[1024]; + char *ptr = buffer; + const SalIceRemoteCandidate *candidate; + int offset = 0; + int i; + + buffer[0] = '\0'; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { + candidate = &desc->ice_remote_candidates[i]; + if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { + offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); + if (offset < 0) { + ms_error("Cannot add ICE remote-candidates attribute!"); + return; + } + ptr += offset; + } + } + if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer)); +} + +static belle_sdp_media_description_t *stream_description_to_sdp ( const SalStreamDescription *stream ) { belle_sdp_mime_parameter_t* mime_param; belle_sdp_media_description_t* media_desc; - int i,j; + int j; MSList* pt_it; PayloadType* pt; char buffer[1024]; char* dir=NULL; + const char *rtp_addr; + const char *rtcp_addr; + int rtp_port; + int rtcp_port; + bool_t different_rtp_and_rtcp_addr; + + rtp_addr=stream->rtp_addr; + rtcp_addr=stream->rtcp_addr; + rtp_port=stream->rtp_port; + rtcp_port=stream->rtcp_port; + + media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type ) + ,stream->rtp_port + ,1 + ,sal_media_proto_to_string ( stream->proto ) + ,NULL ); + for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { + pt= ( PayloadType* ) pt_it->data; + mime_param= belle_sdp_mime_parameter_create ( pt->mime_type + , payload_type_get_number ( pt ) + , pt->clock_rate + ,stream->type==SalAudio?1:-1 ); + belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp ); + if ( stream->ptime>0 ) { + belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime ); + } + belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param ); + belle_sip_object_unref ( mime_param ); + } + if ( stream->bandwidth>0 ) + belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); - if (strchr(desc->addr,':')!=NULL){ - inet6=1; - }else inet6=0; - belle_sdp_session_description_set_version(session_desc,belle_sdp_version_create(0)); + if ( stream->proto == SalProtoRtpSavp ) { + /* add crypto lines */ + for ( j=0; jusername - ,desc->session_id - ,desc->session_ver - ,"IN" - , inet6 ? "IP6" :"IP4" - ,desc->addr); + switch ( stream->crypto[j].algo ) { + case AES_128_SHA1_80: + snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", + stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key ); + belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); + break; + case AES_128_SHA1_32: + snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", + stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key ); + belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); + break; + case AES_128_NO_AUTH: + ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); + break; + case NO_CIPHER_SHA1_80: + ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" ); + break; + default: + j = SAL_CRYPTO_ALGO_MAX; + /* no break */ + } + } + } + switch ( stream->dir ) { + case SalStreamSendRecv: + /*dir="sendrecv";*/ + dir=NULL; + break; + case SalStreamRecvOnly: + dir="recvonly"; + break; + case SalStreamSendOnly: + dir="sendonly"; + break; + case SalStreamInactive: + dir="inactive"; + break; + } + if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) ); + + if (rtp_port != 0) { + different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); + if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { + if (different_rtp_and_rtcp_addr == TRUE) { + snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); + } else { + snprintf(buffer, sizeof(buffer), "%u",rtcp_port); + } + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer)); + } + } + if (stream->ice_completed == TRUE) { + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes")); + } + if (stream->ice_mismatch == TRUE) { + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL)); + } else { + if (rtp_port != 0) { + if (stream->ice_pwd[0] != '\0') + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd)); + if (stream->ice_ufrag[0] != '\0') + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag)); + add_ice_candidates(media_desc,stream); + add_ice_remote_candidates(media_desc,stream); + } + } + + return media_desc; +} - belle_sdp_session_description_set_origin(session_desc,origin); +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; - belle_sdp_session_description_set_session_name(session_desc,belle_sdp_session_name_create("Talk")); + if ( strchr ( desc->addr,':' ) !=NULL ) { + inet6=1; + } else inet6=0; + belle_sdp_session_description_set_version ( session_desc,belle_sdp_version_create ( 0 ) ); - if(!sal_media_description_has_dir (desc,SalStreamSendOnly) && !sal_media_description_has_dir (desc,SalStreamInactive)) { - belle_sdp_session_description_set_connection(session_desc - ,belle_sdp_connection_create("IN",inet6 ? "IP6" :"IP4",desc->addr)); + origin = belle_sdp_origin_create ( desc->username + ,desc->session_id + ,desc->session_ver + ,"IN" + , inet6 ? "IP6" :"IP4" + ,desc->addr ); + + belle_sdp_session_description_set_origin ( session_desc,origin ); + + belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) ); + + if ( !sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive ) ) { + 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_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)); + 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->bandwidth>0 ) { + belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth ); } - - for (i=0; in_total_streams;i++) { - media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type) - ,desc->streams[i].rtp_port - ,1 - ,sal_media_proto_to_string(desc->streams[i].proto) - ,NULL); - for (pt_it=desc->streams[i].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 - ,desc->streams[i].type==SalAudio?1:-1); - belle_sdp_mime_parameter_set_parameters(mime_param,pt->recv_fmtp); - if (desc->streams[i].ptime>0) { - belle_sdp_mime_parameter_set_ptime(mime_param,desc->streams[i].ptime); - } - belle_sdp_media_description_append_values_from_mime_parameter(media_desc,mime_param); - belle_sip_object_unref(mime_param); - } - if (desc->streams[i].bandwidth>0) - belle_sdp_media_description_set_bandwidth(media_desc,"AS",desc->streams[i].bandwidth); - - if (desc->streams[i].proto == SalProtoRtpSavp) { - /* add crypto lines */ - for(j=0; jstreams[i].crypto[j].algo) { - case AES_128_SHA1_80: - snprintf(buffer, sizeof(buffer), "%d %s inline:%s", - desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", desc->streams[i].crypto[j].master_key); - belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); - break; - case AES_128_SHA1_32: - snprintf(buffer, sizeof(buffer), "%d %s inline:%s", - desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", desc->streams[i].crypto[j].master_key); - belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); - break; - case AES_128_NO_AUTH: - ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); - break; - case NO_CIPHER_SHA1_80: - ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); - break; - default: - j = SAL_CRYPTO_ALGO_MAX; - /* no break */ - } - } - - } - switch(desc->streams[i].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)); - - belle_sdp_session_description_add_media_description(session_desc,media_desc); - + + if (desc->ice_completed == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes")); + if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd)); + if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag)); + + for ( i=0; in_total_streams; i++ ) { + belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(&desc->streams[i])); } return session_desc; - } -int sdp_to_media_description(belle_sdp_session_description_t *session_desc, SalMediaDescription *desc) { +int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { /* typedef struct SalMediaDescription{ int refcount; @@ -164,154 +257,218 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal belle_sdp_mime_parameter_t* mime_param; PayloadType *pt; belle_sip_list_t* attribute_it; - belle_sdp_attribute_t* attribute; + const belle_sdp_attribute_t* attribute; int valid_count = 0; char tmp[256], tmp2[256]; int nb=0; SalStreamDir stream_dir=SalStreamSendRecv; + const char* value; + int nb_ice_candidates=0; + desc->n_active_streams = 0; desc->n_total_streams = 0; - if ((cnx=belle_sdp_session_description_get_connection(session_desc)) && belle_sdp_connection_get_address(cnx)) { - strncpy(desc->addr,belle_sdp_connection_get_address(cnx),sizeof(desc->addr)); + if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { + strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) ); } - if (belle_sdp_session_description_get_bandwidth(session_desc,"AS") >0) { - desc->bandwidth=belle_sdp_session_description_get_bandwidth(session_desc,"AS"); + 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")) { + if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { stream_dir=SalStreamSendRecv; - } else if (belle_sdp_session_description_get_attribute(session_desc,"sendonly")) { + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { stream_dir=SalStreamSendOnly; - } else if (belle_sdp_session_description_get_attribute(session_desc,"recvonly")) { + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { stream_dir=SalStreamRecvOnly; - } else if (belle_sdp_session_description_get_attribute(session_desc,"inactive")) { + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { stream_dir=SalStreamInactive; } - - for(media_desc_it=belle_sdp_session_description_get_media_descriptions(session_desc) - ;media_desc_it!=NULL - ;media_desc_it=media_desc_it->next) { - media_desc=BELLE_SDP_MEDIA_DESCRIPTION(media_desc_it->data); + /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); + if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag)); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); + if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); + if (value) desc->ice_lite = TRUE; + + for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) + ; media_desc_it!=NULL + ; media_desc_it=media_desc_it->next ) { + media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); stream=&desc->streams[desc->n_total_streams]; - media=belle_sdp_media_description_get_media(media_desc); + media=belle_sdp_media_description_get_media ( media_desc ); - memset(stream,0,sizeof(*stream)); + memset ( stream,0,sizeof ( *stream ) ); - proto = belle_sdp_media_get_protocol(media); + proto = belle_sdp_media_get_protocol ( media ); stream->proto=SalProtoUnknown; - if (proto){ - if (strcasecmp(proto,"RTP/AVP")==0) + if ( proto ) { + if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) stream->proto=SalProtoRtpAvp; - else if (strcasecmp(proto,"RTP/SAVP")==0){ + else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { stream->proto=SalProtoRtpSavp; } } - if ((cnx=belle_sdp_media_description_get_connection(media_desc)) && belle_sdp_connection_get_address(cnx)) { - strncpy(stream->rtp_addr,belle_sdp_connection_get_address(cnx),sizeof(stream->rtp_addr)); + if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { + strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); } - stream->rtp_port=belle_sdp_media_get_media_port(media); + stream->rtp_port=belle_sdp_media_get_media_port ( media ); stream->rtcp_port = stream->rtp_port + 1; - if (stream->rtp_port > 0) - desc->n_active_streams++; + if ( stream->rtp_port > 0 ) + desc->n_active_streams++; - mtype = belle_sdp_media_get_media_type(media); - if (strcasecmp("audio", mtype) == 0){ + mtype = belle_sdp_media_get_media_type ( media ); + if ( strcasecmp ( "audio", mtype ) == 0 ) { stream->type=SalAudio; - }else if (strcasecmp("video", mtype) == 0){ + } else if ( strcasecmp ( "video", mtype ) == 0 ) { stream->type=SalVideo; - }else { + } else { stream->type=SalOther; - strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1); + 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_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")) { + if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) { stream->dir=SalStreamSendRecv; - } else if (belle_sdp_media_description_get_attribute(media_desc,"sendonly")) { + } 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")) { + } 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")) { + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) { stream->dir=SalStreamInactive; } else { stream->dir=stream_dir; /*takes default value if not present*/ } /* for each payload type */ - mime_params=belle_sdp_media_description_build_mime_parameters(media_desc); - for(mime_param_it=mime_params - ;mime_param_it!=NULL - ;mime_param_it=mime_param_it->next) { - mime_param=BELLE_SDP_MIME_PARAMETER(mime_param_it->data) + mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); + for ( mime_param_it=mime_params + ; mime_param_it!=NULL + ; mime_param_it=mime_param_it->next ) { + mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data ) - pt=payload_type_new(); - payload_type_set_number(pt,belle_sdp_mime_parameter_get_media_format(mime_param)); - pt->clock_rate=belle_sdp_mime_parameter_get_rate(mime_param); - pt->mime_type=ms_strdup(belle_sdp_mime_parameter_get_type(mime_param)); - pt->channels=belle_sdp_mime_parameter_get_channel_count(mime_param); - payload_type_set_send_fmtp(pt,belle_sdp_mime_parameter_get_parameters(mime_param)); - stream->payloads=ms_list_append(stream->payloads,pt); - stream->ptime=belle_sdp_mime_parameter_get_ptime(mime_param); - ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, - pt->send_fmtp ? pt->send_fmtp : ""); + pt=payload_type_new(); + payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) ); + pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param ); + pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); + pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); + payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); + stream->payloads=ms_list_append ( stream->payloads,pt ); + stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); + ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : "" ); } - if (mime_params) belle_sip_list_free_with_data(mime_params,belle_sip_object_unref); + if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref ); + + + /* Get media specific RTCP attribute */ + stream->rtcp_port = stream->rtp_port + 1; + snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); + attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + char tmp[256]; + int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); + if (nb == 1) { + /* SDP rtcp attribute only contains the port */ + } else if (nb == 2) { + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); + } else { + ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); + } + } + /* read crypto lines if any */ - if (stream->proto == SalProtoRtpSavp) { + if ( stream->proto == SalProtoRtpSavp ) { + 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 ); - memset(&stream->crypto, 0, sizeof(stream->crypto)); - for (attribute_it=belle_sdp_media_description_get_attributes(media_desc) - ;valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; - attribute_it=attribute_it->next){ - attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); - - if (keywordcmp("crypto",belle_sdp_attribute_get_name(attribute))==0 && belle_sdp_attribute_get_value(attribute)!=NULL){ - nb = sscanf(belle_sdp_attribute_get_value(attribute), "%d %256s inline:%256s", - &stream->crypto[valid_count].tag, - tmp, - tmp2); - ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - tmp2); - if (nb == 3) { - if (keywordcmp("AES_CM_128_HMAC_SHA1_80",tmp) == 0) + if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { + nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2 ); + ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + tmp2 ); + if ( nb == 3 ) { + if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ) stream->crypto[valid_count].algo = AES_128_SHA1_80; - else if (keywordcmp("AES_CM_128_HMAC_SHA1_32",tmp) == 0) + else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ) stream->crypto[valid_count].algo = AES_128_SHA1_32; else { - ms_warning("Failed to parse crypto-algo: '%s'", tmp); + 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); + 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); + 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_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); + ms_message ( "Found: %d valid crypto lines", valid_count ); + } + + /* Get ICE candidate attributes if any */ + for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { + attribute=(belle_sdp_attribute_t*)attribute_it->data; + const char *att_name=belle_sdp_attribute_get_name(attribute); + value=belle_sdp_attribute_get_value(attribute); + if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { + SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; + int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", + candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, + candidate->type, candidate->raddr, &candidate->rport); + if ((nb == 6) || (nb == 8)) nb_ice_candidates++; + else memset(candidate, 0, sizeof(*candidate)); + } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { + SalIceRemoteCandidate candidate; + unsigned int componentID; + int offset; + const char *ptr = value; + 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", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)); + } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); + } else if (keywordcmp("ice-mismatch", att_name) == 0) { + stream->ice_mismatch = TRUE; + } } desc->n_total_streams++; } - return 0; } + diff --git a/tester/call_tester.c b/tester/call_tester.c index 65de848ec..043f8d774 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -371,7 +371,7 @@ static void call_declined(void) { static void call_terminated_by_caller(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - + CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); @@ -382,6 +382,48 @@ static void call_terminated_by_caller(void) { linphone_core_manager_destroy(pauline); } +static void call_with_ice(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + int i; + LinphoneCall *c1,*c2; + bool_t success=FALSE; + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + c1=linphone_core_get_current_call(marie->lc); + c2=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + for (i=0;i<100;i++){ + if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && + linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ + success=TRUE; + break; + } + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + ms_usleep(100000); + } + + CU_ASSERT_TRUE(success); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_paused_resumed(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -736,7 +778,8 @@ test_t call_tests[] = { #endif { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, - { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call } + { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, + { "Call with ICE", call_with_ice }, }; test_suite_t call_test_suite = { From 82c498a7119d8106cdd1c7354652be53ade3579b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 18 Apr 2013 10:28:50 +0200 Subject: [PATCH 267/909] Port tunnel to belle-sip. --- coreapi/Makefile.am | 3 +++ coreapi/TunnelManager.cc | 24 +++++++++++++++++++++++- coreapi/TunnelManager.hh | 5 +++++ coreapi/bellesip_sal/sal_impl.c | 15 +++++++++++++++ coreapi/linphonecore.c | 6 +++--- include/sal/sal.h | 2 ++ 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 8a42e8733..3dd43c0db 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -126,6 +126,9 @@ AM_CFLAGS=\ if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD endif +if USE_BELLESIP +AM_CFLAGS+= -DUSE_BELLESIP +endif AM_CXXFLAGS=$(AM_CFLAGS) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index d1020b1b2..baf1454e3 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -18,6 +18,7 @@ #include "linphonecore_utils.h" #include "eXosip2/eXosip_transport_hook.h" #include "tunnel/udp_mirror.hh" +#include "private.h" #ifdef ANDROID #include @@ -27,6 +28,8 @@ using namespace belledonnecomm; using namespace ::std; +#ifndef USE_BELLESIP + Mutex TunnelManager::sMutex; int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){ @@ -99,6 +102,7 @@ int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, return select(max_fds,s1,s2,s3,tv); } } +#endif void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) { @@ -181,7 +185,9 @@ void TunnelManager::start() { } mTunnelClient->start(); +#ifndef USE_BELLESIP if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060); +#endif } bool TunnelManager::isStarted() { @@ -209,17 +215,21 @@ int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flag TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mCore(lc) +#ifndef USE_BELLESIP ,mSipSocket(NULL) +#endif ,mCallback(NULL) ,mEnabled(false) ,mTunnelClient(NULL) ,mAutoDetectStarted(false) ,mHttpProxyPort(0){ +#ifndef USE_BELLESIP mExosipTransport.data=this; mExosipTransport.recvfrom=eXosipRecvfrom; mExosipTransport.sendto=eXosipSendto; mExosipTransport.select=eXosipSelect; +#endif linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); mTransportFactories.audio_rtcp_func=sCreateRtpTransport; mTransportFactories.audio_rtcp_func_data=this; @@ -236,6 +246,9 @@ TunnelManager::~TunnelManager(){ } void TunnelManager::stopClient(){ +#ifdef USE_BELLESIP + sal_disable_tunnel(mCore->sal); +#else eXosip_transport_hook_register(NULL); if (mSipSocket != NULL){ sMutex.lock(); @@ -243,6 +256,7 @@ void TunnelManager::stopClient(){ mSipSocket = NULL; sMutex.unlock(); } +#endif if (mTunnelClient){ delete mTunnelClient; mTunnelClient=NULL; @@ -257,6 +271,9 @@ void TunnelManager::processTunnelEvent(const Event &ev){ ms_message("Tunnel is up, registering now"); linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall); linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories); +#ifdef USE_BELLESIP + sal_enable_tunnel(mCore->sal, mTunnelClient); +#else eXosip_transport_hook_register(&mExosipTransport); //force transport to udp LCSipTransports lTransport; @@ -267,6 +284,7 @@ void TunnelManager::processTunnelEvent(const Event &ev){ lTransport.dtls_port=0; linphone_core_set_sip_transports(mCore, &lTransport); +#endif //register if (lProxy) { linphone_proxy_config_done(lProxy); @@ -320,7 +338,11 @@ void TunnelManager::enable(bool isEnable) { linphone_core_set_rtp_transport_factories(mCore,NULL); +#ifdef USE_BELLESIP + sal_disable_tunnel(mCore->sal); +#else eXosip_transport_hook_register(NULL); +#endif //Restore transport and firewall policy linphone_core_set_sip_transports(mCore, &mRegularTransport); linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy); @@ -387,7 +409,7 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) { #ifdef ANDROID else SetLogHandler(linphone_android_tunnel_log_handler); #else - else SetLogHandler(default_log_handler); + else SetLogHandler(tunnel_default_log_handler); #endif if (isEnabled) { diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index d4c1458fc..0e8ae3745 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -15,9 +15,12 @@ #include "tunnel/client.hh" #include "linphonecore.h" +#ifndef USE_BELLESIP extern "C" { #include "eXosip2/eXosip_transport_hook.h" } +#endif + namespace belledonnecomm { class TunnelClient; class UdpMirrorClient; @@ -159,8 +162,10 @@ class UdpMirrorClient; void postEvent(const Event &ev); LinphoneCore* mCore; LCSipTransports mRegularTransport; +#ifndef USE_BELLESIP TunnelSocket *mSipSocket; eXosip_transport_hooks_t mExosipTransport; +#endif StateCallback mCallback; void * mCallbackData; bool mEnabled; diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index a4f4aac96..ab41a46b3 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -515,6 +515,21 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ } return ; } +int sal_enable_tunnel(Sal *ctx, void *tunnelclient) { + int result; + + sal_unlisten_ports(ctx); + belle_sip_listening_point_t* lp = belle_sip_tunnel_listening_point_new(ctx->stack, tunnelclient); + if (lp == NULL) return -1; + + belle_sip_listening_point_set_keep_alive(lp, ctx->keep_alive); + result = belle_sip_provider_add_listening_point(ctx->prov, lp); + set_tls_properties(ctx); + return result; +} +void sal_disable_tunnel(Sal *ctx) { + sal_unlisten_ports(ctx); +} /** * returns keepalive period in ms * 0 desactiaved diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e8a5fc3dc..55f64905f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5366,6 +5366,9 @@ static void linphone_core_uninit(LinphoneCore *lc) video_preview_stop(lc->previewstream); lc->previewstream=NULL; } +#endif +#ifdef TUNNEL_ENABLED + if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); #endif ms_event_queue_destroy(lc->msevq); lc->msevq=NULL; @@ -5414,9 +5417,6 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_message_storage_close(lc); ortp_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); -#ifdef TUNNEL_ENABLED - if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); -#endif } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ diff --git a/include/sal/sal.h b/include/sal/sal.h index 37068c4cd..aa4099825 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -383,6 +383,8 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent); /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value); void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled); +int sal_enable_tunnel(Sal *ctx, void *tunnelclient); +void sal_disable_tunnel(Sal *ctx); /** * returns keepalive period in ms * 0 desactiaved From bd6d249f268c586497da5db6a185fb81f7251164 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 19 Apr 2013 09:19:58 +0200 Subject: [PATCH 268/909] Define variables at the beginning of a block and do not call tunnel stuff is tunnel compilation is not enabled. --- coreapi/bellesip_sal/sal_impl.c | 9 ++++++++- coreapi/bellesip_sal/sal_sdp.c | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ab41a46b3..6ef7a2cdf 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -516,19 +516,26 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ return ; } int sal_enable_tunnel(Sal *ctx, void *tunnelclient) { +#ifdef TUNNEL_ENABLED + belle_sip_listening_point_t *lp; int result; sal_unlisten_ports(ctx); - belle_sip_listening_point_t* lp = belle_sip_tunnel_listening_point_new(ctx->stack, tunnelclient); + lp = belle_sip_tunnel_listening_point_new(ctx->stack, tunnelclient); if (lp == NULL) return -1; belle_sip_listening_point_set_keep_alive(lp, ctx->keep_alive); result = belle_sip_provider_add_listening_point(ctx->prov, lp); set_tls_properties(ctx); return result; +#else + return 0; +#endif } void sal_disable_tunnel(Sal *ctx) { +#ifdef TUNNEL_ENABLED sal_unlisten_ports(ctx); +#endif } /** * returns keepalive period in ms diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 9efb449fb..1aa7f004c 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -431,8 +431,9 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /* Get ICE candidate attributes if any */ for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { + const char *att_name; attribute=(belle_sdp_attribute_t*)attribute_it->data; - const char *att_name=belle_sdp_attribute_get_name(attribute); + att_name=belle_sdp_attribute_get_name(attribute); value=belle_sdp_attribute_get_value(attribute); if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; From 239a7881c2e9a8846cab2ad8403e4586af985a63 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 19 Apr 2013 11:41:56 +0200 Subject: [PATCH 269/909] Added missing ekports --- coreapi/linphonecore.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 28272fe51..57369545d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -701,7 +701,7 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore * LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); void linphone_chat_room_destroy(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); -const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); @@ -709,27 +709,27 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); void linphone_chat_room_delete_history(LinphoneChatRoom *cr); int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); -void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); -void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); +LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); +LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); -LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); +LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); void linphone_chat_message_destroy(LinphoneChatMessage* msg); void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); -const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); -time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); -void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); -void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); +LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); -const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); -LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); -void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); -const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); +LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); +LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); +LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); /** * @} From 541413ce2075174a7fb88540027e11096bdd5f3c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 19 Apr 2013 10:21:36 +0200 Subject: [PATCH 270/909] Do not include eXosip header when compiling with bellesip. --- coreapi/TunnelManager.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index baf1454e3..17e1e5f98 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -16,7 +16,9 @@ #include "ortp/rtpsession.h" #include "linphonecore.h" #include "linphonecore_utils.h" +#ifndef USE_BELLESIP #include "eXosip2/eXosip_transport_hook.h" +#endif #include "tunnel/udp_mirror.hh" #include "private.h" From 90d30b20c7c3d001832d1c57d859088091d4c694 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 19 Apr 2013 14:57:07 +0200 Subject: [PATCH 271/909] Enable tunnel on Windows Phone 8. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 269e5351f..b52044b7c 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -67,7 +67,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing @@ -91,7 +91,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default @@ -117,7 +117,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing @@ -147,7 +147,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default @@ -189,7 +189,8 @@ - + + @@ -200,6 +201,7 @@ + @@ -240,6 +242,9 @@ true false + + {59500dd1-b192-4ddf-a402-8a8e3739e032} + @@ -250,6 +255,9 @@ false + + + From 3a3a5e478da4e6af7bed67b0e7a1b200079ca775 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 19 Apr 2013 15:39:40 +0200 Subject: [PATCH 272/909] wrap DSCP API for java --- coreapi/linphonecore_jni.cc | 24 +++++++++++ .../org/linphone/core/LinphoneCore.java | 40 +++++++++++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 35 ++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 5046d83bb..b721c6892 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2143,6 +2143,14 @@ extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env 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); @@ -2447,6 +2455,22 @@ 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" 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); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 144b7dfe2..d76acad9a 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -637,6 +637,20 @@ public interface LinphoneCore { * @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 @@ -1146,6 +1160,19 @@ public interface LinphoneCore { */ 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. **/ @@ -1156,6 +1183,19 @@ public interface LinphoneCore { */ 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 diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 0b4c984d6..f9a7abf39 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -913,4 +913,39 @@ class LinphoneCoreImpl implements LinphoneCore { public PayloadType findPayloadType(String mime) { return findPayloadType(mime, FIND_PAYLOAD_IGNORE_RATE); } + + private native void setSipDscp(long nativePtr, int dscp); + @Override + public void setSipDscp(int dscp) { + setSipDscp(nativePtr,dscp); + } + + private native int getSipDscp(long nativePtr); + @Override + public int getSipDscp() { + return getSipDscp(nativePtr); + } + private native void setAudioDscp(long nativePtr, int dscp); + @Override + public void setAudioDscp(int dscp) { + setAudioDscp(nativePtr, dscp); + } + + private native int getAudioDscp(long nativePtr); + @Override + public int getAudioDscp() { + return getAudioDscp(nativePtr); + } + + private native void setVideoDscp(long nativePtr, int dscp); + @Override + public void setVideoDscp(int dscp) { + setVideoDscp(nativePtr,dscp); + } + + private native int getVideoDscp(long nativePtr); + @Override + public int getVideoDscp() { + return getVideoDscp(nativePtr); + } } From f0ac752704d01f1f3d2edf359c888aa7bb2d333b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 19 Apr 2013 15:43:51 +0200 Subject: [PATCH 273/909] fix crash in gtk chat --- gtk/chat.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 58f1a23ce..b1da70822 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -61,12 +61,17 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { 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"); + gchar *from; g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); 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); g_object_set_data(G_OBJECT(friendlist),"from",NULL); gtk_widget_destroy(w); @@ -128,7 +133,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, GtkTextIter iter,begin; int off; char *from_str=linphone_address_as_string_uri_only(from); - char *from_message=(char *)g_object_get_data(G_OBJECT(w),"from_message"); + gchar *from_message=(gchar *)g_object_get_data(G_OBJECT(w),"from_message"); GList *list=g_object_get_data(G_OBJECT(w),"list"); time_t t; char buf[80]; @@ -148,8 +153,8 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, 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_buffer_insert(buffer,&iter,"\n",-1); - ms_free(from_message); - g_object_set_data(G_OBJECT(w),"from_message",from_str); + 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_insert_with_tags_by_name(buffer,&iter,linphone_chat_message_get_text(msg),-1,"margin",me ? "bg":NULL,NULL); @@ -193,6 +198,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, 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); + ms_free(from_str); } const LinphoneAddress* linphone_gtk_get_used_identity(){ @@ -292,6 +298,7 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon 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)); @@ -301,7 +308,11 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon strcmp(from_str,with_str)==0? FALSE : TRUE, linphone_chat_message_get_chat_room(msg),msg,TRUE); } - g_object_set_data(G_OBJECT(chat_view),"from_message",NULL); + 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); + } ms_free(from_str); ms_free(with_str); linphone_gtk_free_list(messages); @@ -420,7 +431,7 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, g_object_set_data(G_OBJECT(chat_view),"cr",cr); 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",uri_str); + g_object_set_data(G_OBJECT(chat_view),"from_message",g_strdup(uri_str)); display_history_message(chat_view,messages,uri); } ms_free(from_str); From 94c6883b8bbb68483db86b248290a97246ed9be7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 19 Apr 2013 16:52:40 +0200 Subject: [PATCH 274/909] update ms2 for ringstream bugfix --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 25b0496db..9fa2247c2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 25b0496dbc62183f195528481fe44c73e0d201e9 +Subproject commit 9fa2247c2446d4b06f4a60b72eee65dc591764da From ae4ad91a00b19b9335d90756a4f3a3c4d900618e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 20 Apr 2013 08:59:24 +0200 Subject: [PATCH 275/909] update ms2 (repair build) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 9fa2247c2..2720ab1d1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9fa2247c2446d4b06f4a60b72eee65dc591764da +Subproject commit 2720ab1d1568ced6f0bf63e454a35f340d8ace64 From cc671644bea7dd3426316636ab6ce24526683374 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Sun, 21 Apr 2013 22:06:07 +0200 Subject: [PATCH 276/909] Add aac-eld paylaod type to linphone core. - add two configurations with their respective fmtp config string --- coreapi/linphonecore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index edf11a407..e967b5737 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1291,6 +1291,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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_assign_payload_type(lc,&payload_type_aaceld_nb,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_wb,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); linphone_core_handle_static_payloads(lc); ms_init(); From bb255673e346364e5c255e12b4b3ea7abe6bfe12 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 22 Apr 2013 11:04:48 +0200 Subject: [PATCH 277/909] Rename aac-eld modes to 22k and 44k --- coreapi/linphonecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e967b5737..24515d33d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1291,8 +1291,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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_assign_payload_type(lc,&payload_type_aaceld_nb,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_wb,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); linphone_core_handle_static_payloads(lc); ms_init(); From d14f627659e74da40dbd8f7fc2f07ce09b7e7b5d Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 22 Apr 2013 11:11:25 +0200 Subject: [PATCH 278/909] Add oRTP with aac-eld payload changes --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 1172caa98..26ee84a1e 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 1172caa98c7fc70d98bf6e508699a9bead5e9592 +Subproject commit 26ee84a1e3053b7b4426033ddc273cc60bf43902 From 6d682291e9cedec4baa3d49f09bd6dd5cdf1303c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 22 Apr 2013 11:16:00 +0200 Subject: [PATCH 279/909] Fix registration when disabling tunnel. --- coreapi/TunnelManager.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 17e1e5f98..2d5ea1854 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -342,6 +342,13 @@ void TunnelManager::enable(bool isEnable) { #ifdef USE_BELLESIP sal_disable_tunnel(mCore->sal); + // Set empty transports to force the setting of regular transport, otherwise it is not applied + LCSipTransports lTransport; + lTransport.udp_port = 0; + lTransport.tcp_port = 0; + lTransport.tls_port = 0; + lTransport.dtls_port = 0; + linphone_core_set_sip_transports(mCore, &lTransport); #else eXosip_transport_hook_register(NULL); #endif From d09307827cb9cc19153bb7b44016d07fd39c4ac1 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 22 Apr 2013 11:26:57 +0200 Subject: [PATCH 280/909] Typo in oRTP aac-eld payload type name --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 26ee84a1e..bd64df514 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 26ee84a1e3053b7b4426033ddc273cc60bf43902 +Subproject commit bd64df5148bdfd4a2ff5153927676fc497118279 From 93c48ae1686d54a65f502c3f73fde11e497941df Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 22 Apr 2013 12:57:44 +0200 Subject: [PATCH 281/909] Save DTMFs settings immediately. --- coreapi/linphonecore.c | 20 ++++++++------------ coreapi/private.h | 2 -- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 24515d33d..a17543d22 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -598,9 +598,6 @@ static void sip_config_read(LinphoneCore *lc) 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); } @@ -610,9 +607,6 @@ static void sip_config_read(LinphoneCore *lc) 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){ ipv6=0; @@ -1725,7 +1719,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); } /** @@ -1735,7 +1729,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()) { + lp_config_set_int(lc->config, "sip", "use_info", use_info); + } } /** @@ -1745,7 +1741,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); } /** @@ -1755,7 +1751,9 @@ 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()) { + lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833); + } } /** @@ -5128,8 +5126,6 @@ void sip_config_uninit(LinphoneCore *lc) 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); diff --git a/coreapi/private.h b/coreapi/private.h index 5e265c616..d80607ca9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -438,8 +438,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; From 1d4f910cff252ef82eff3810ea2f4f22ac54bed9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 22 Apr 2013 13:11:27 +0200 Subject: [PATCH 282/909] Oops... Forgot the lc parameter. --- coreapi/linphonecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a17543d22..559048c59 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1729,7 +1729,7 @@ 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) { - if (linphone_core_ready()) { + if (linphone_core_ready(lc)) { lp_config_set_int(lc->config, "sip", "use_info", use_info); } } @@ -1751,7 +1751,7 @@ 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) { - if (linphone_core_ready()) { + if (linphone_core_ready(lc)) { lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833); } } From 933b6559b31574d71a1e28e5c010b5d31ba87525 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 22 Apr 2013 23:11:10 +0200 Subject: [PATCH 283/909] update ms2 and cleanup dead function --- coreapi/linphonecore.c | 20 -------------------- mediastreamer2 | 2 +- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 559048c59..bb2b4a83c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4927,26 +4927,6 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ 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 -**/ -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; - } - memset(&def,0,sizeof(def)); - def.duration=300; - def.frequencies[0]=500; - def.amplitude=1; - def.interval=2000; - ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); -} - void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ if (linphone_core_tone_indications_enabled(lc)){ MSFilter *f=get_dtmf_gen(lc); diff --git a/mediastreamer2 b/mediastreamer2 index 2720ab1d1..23b802c46 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2720ab1d1568ced6f0bf63e454a35f340d8ace64 +Subproject commit 23b802c4631fdf909a218a0dd0a77c6cf6d4d5a9 From 91310ca98fce5fd8135e9cf506d2d2bd1f6d5daa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 23 Apr 2013 09:17:36 +0200 Subject: [PATCH 284/909] Improve echo canceller calibrator. - Use the void source filter instead of the file player. - Handle the number of channels. --- coreapi/ec-calibrator.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index e19559fc4..d724669a4 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -29,6 +29,8 @@ 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; @@ -37,9 +39,13 @@ static void ecc_init_filters(EcCalibrator *ecc){ ecc->sndread=ms_snd_card_create_reader(ecc->play_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); @@ -50,7 +56,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); @@ -58,8 +64,12 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); From 18cdaef2e38563fdfafa4a68ff1f04e42eb25224 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 23 Apr 2013 10:45:01 +0200 Subject: [PATCH 285/909] Add callbacks for audio (un)initialization in the echo canceller calibrator. --- coreapi/ec-calibrator.c | 19 +++++++++++++++---- coreapi/linphonecore_jni.cc | 2 ++ coreapi/linphonecore_utils.h | 5 ++++- coreapi/private.h | 2 ++ coreapi/test_ecc.c | 2 +- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index d724669a4..223fb087d 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -77,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); @@ -232,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); @@ -253,13 +263,14 @@ 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){ if (lc->ecc!=NULL){ ms_error("Echo calibration is still on going !"); return -1; } unsigned int rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); - 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/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b721c6892..02ac62c7a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -996,6 +996,8 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI ,jobject data) { return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc , LinphoneCoreData::ecCalibrationStatus + , NULL + , NULL , data?env->NewGlobalRef(data):NULL); } diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index cc0a6f692..b80992ad1 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); +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 diff --git a/coreapi/private.h b/coreapi/private.h index d80607ca9..b5312bd60 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -662,6 +662,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; diff --git a/coreapi/test_ecc.c b/coreapi/test_ecc.c index 43ae0dcb2..38ba72765 100644 --- a/coreapi/test_ecc.c +++ b/coreapi/test_ecc.c @@ -45,7 +45,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); From dee209f13ba95ed55e1c6d298aaf7e9968678012 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 23 Apr 2013 11:39:03 +0200 Subject: [PATCH 286/909] Change the README for linphone desktop (linux) --- README | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/README b/README index 658f07ae0..db78b72e5 100644 --- a/README +++ b/README @@ -2,24 +2,64 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. ******************Building linphone *********************************** + +- Install build time dependencies + - libtool + - intltool + - 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 + - libosip2>=3.0.3 + - libeXosip2>=3.0.3 + - speex>=1.2.0 (including libspeexdsp part) + + + if you want the gtk/glade interface: + - libgtk >=2.16.0 + if you want video support: - SDL>=1.2.10 - libavcodec (ffmpeg) - libswscale (part of ffmpeg too) for better scaling performance + - libxv (x11 video extension) + - ligl1-mesa (OpenGL API -- GLX development files) + - libglew (OpenGL Extension Wrangler library) + - libv4l (Video for linux) + - libx11 (x11) - theora (optional) - + if you want uPnP support: + + + gsm codec (gsm source package or libgsm-dev or gsm-devel) (optional) + + libreadline (optional: for convenient command line in linphonec) + + libsoup (optional: for wizard - account creation assistant) + + libsqlite3 (optional : for a local history of messages) + + if you want uPnP support (optional): - libupnp (version 1.6 branch (not patched with 18-url-upnpstrings.patch)) + + + Install srtp (optional) for call encryption : + $ git clone git://git.linphone.org/srtp.git + $ cd srtp && autoconf && ./configure && make + $ sudo make install + + + Install zrtpcpp (optional), for unbreakable call encryption + $ sudo apt-get install cmake libssl-dev + $ git clone git://git.linphone.org/zrtpcpp.git + $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make + $ sudo make install with their corresponding -dev or -devel package if you don't use source packages. +- Compile linphone + + $ ./autogen.sh + $ ./configure + $ sudo make install + $ sudo ldconfig + +- Command line for Ubuntu && Debian + + $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libvx-dev ligl1-mesa-dev libglew-dev libv4l-dev + + + for optional library + $ sudo apt-get install libreadline-dev liggsm1-dev libtheora-dev libsoup2.4-dev libsqlit3-dev libupnp6-dev + + For windows compilation see README.mingw. For macOS X, see README.macos From fcb7ec2b4b548ff686faa1a3eb0697fe37127556 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 23 Apr 2013 12:38:58 +0200 Subject: [PATCH 287/909] update chat state message changed --- gtk/chat.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index b1da70822..2cba0754f 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -62,6 +62,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); GtkWidget *w=g_object_get_data(G_OBJECT(friendlist),"chatview"); gchar *from; + GHashTable *table=g_object_get_data(G_OBJECT(w),"table"); g_return_if_fail(w!=NULL); gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w)); @@ -72,6 +73,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_object_set_data(G_OBJECT(w),"from_message",NULL); g_free(from); } + g_hash_table_destroy(table); g_object_set_data(G_OBJECT(w),"cr",NULL); g_object_set_data(G_OBJECT(friendlist),"from",NULL); gtk_widget_destroy(w); @@ -134,7 +136,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, int off; char *from_str=linphone_address_as_string_uri_only(from); gchar *from_message=(gchar *)g_object_get_data(G_OBJECT(w),"from_message"); - GList *list=g_object_get_data(G_OBJECT(w),"list"); + GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(w),"table"); time_t t; char buf[80]; time_t tnow; @@ -165,10 +167,10 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, switch (linphone_chat_message_get_state (msg)){ case LinphoneChatMessageStateInProgress: { - list=g_list_append(list,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); + 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, "right","small","italic","font_grey","bg",NULL); - g_object_set_data(G_OBJECT(w),"list",list); + g_object_set_data(G_OBJECT(w),"table",table); break; } case LinphoneChatMessageStateDelivered: @@ -213,7 +215,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag 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")); @@ -222,21 +224,20 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag GtkTextIter end; GtkTextIter start; gchar *result; + gint line; + line=GPOINTER_TO_INT(g_hash_table_lookup(table,msg)); - gtk_text_buffer_get_iter_at_line(b,&iter, - GPOINTER_TO_INT(g_list_nth_data(list,0))); + 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, - GPOINTER_TO_INT(g_list_nth_data(list,0)), - gtk_text_iter_get_chars_in_line(&iter)-1); + 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, - GPOINTER_TO_INT(g_list_nth_data(list,0)),0); + gtk_text_buffer_get_iter_at_line_offset(b,&start,line,0); } - gtk_text_buffer_get_iter_at_line_offset(b,&end, - GPOINTER_TO_INT(g_list_nth_data(list,0)),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,GPOINTER_TO_INT(g_list_nth_data(list,0))); + gtk_text_buffer_get_iter_at_line(b,&iter,line); + switch (state) { case LinphoneChatMessageStateInProgress: result="Sending "; @@ -251,14 +252,14 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag break; } case LinphoneChatMessageStateNotDelivered: - result="Error "; + result="Message not sent"; break; default : result="Sending .."; } gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1, "right","small","italic","font_grey","bg",NULL); - list=g_list_remove(list,g_list_nth_data(list,0)); - g_object_set_data(G_OBJECT(page),"list",list); + g_hash_table_remove(table,msg); + g_object_set_data(G_OBJECT(page),"table",table); } } @@ -320,7 +321,6 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon } void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ - //LinphoneAddress *addr=(LinphoneAddress *)data; LinphoneFriend *lf=NULL; char *uri=linphone_address_as_string(addr); lf=linphone_friend_new_with_addr(uri); @@ -352,8 +352,8 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres int idx; GtkWidget *button; GtkWidget *entry; - GList *list=NULL; MSList *messages; + GHashTable *table; char *with_str; color.red = 32512; @@ -372,9 +372,10 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres 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),"from_message",NULL); - g_object_set_data(G_OBJECT(chat_view),"list",list); + g_object_set_data(G_OBJECT(chat_view),"table",table); 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)), From 9f1fbf40b5d0b29b2225ae848bfa9064090f58d9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Apr 2013 14:05:48 +0200 Subject: [PATCH 288/909] add presence status tester --- coreapi/bellesip_sal/sal_op_impl.c | 1 + coreapi/bellesip_sal/sal_op_presence.c | 16 ++++-- coreapi/sal.c | 17 +++++++ include/sal/sal.h | 2 + tester/call_tester.c | 2 +- tester/liblinphone_tester.h | 17 ++++++- tester/presence_tester.c | 67 +++++++++++++++++++++++++- 7 files changed, 114 insertions(+), 8 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 634e93cd5..fc7cc6a4c 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -48,6 +48,7 @@ void sal_op_release_impl(SalOp *op){ 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); __sal_op_free(op); return ; } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index dd5e7917c..0fcc0af86 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -475,7 +475,7 @@ static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_eve 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_error("presence_process_timeout not implemented yet"); + ms_message("presence_process_transaction_terminated not implemented yet"); } static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; @@ -537,7 +537,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques }else{ estatus=SalPresenceOffline; } - ms_message("We are notified that [%s] has online status %i",sal_op_get_from(op),estatus); + ms_message("We are notified that [%s] has online status [%s]",sal_op_get_from(op),sal_presence_status_to_string(estatus)); 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("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); @@ -578,8 +578,16 @@ void sal_op_presence_fill_cbs(SalOp*op) { /*presence publish */ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ - ms_error("sal_publish not implemented yet"); - return -1; + 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); + req=sal_op_build_request(op,"PUBLISH"); + add_presence_info(BELLE_SIP_MESSAGE(req),status); + return sal_op_send_request(op,req); } /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ diff --git a/coreapi/sal.c b/coreapi/sal.c index 1c1a30701..fa7277261 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -595,3 +595,20 @@ void sal_op_set_service_route(SalOp *op,const SalAddress* 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"; + } + +} diff --git a/include/sal/sal.h b/include/sal/sal.h index aa4099825..f66413b8f 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -287,6 +287,8 @@ typedef enum SalPresenceStatus{ SalPresenceAltService, }SalPresenceStatus; +const char* sal_presence_status_to_string(const SalPresenceStatus status); + typedef enum SalReferStatus{ SalReferTrying, SalReferSuccess, diff --git a/tester/call_tester.c b/tester/call_tester.c index 043f8d774..e56866294 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -92,7 +92,7 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { counters->number_of_IframeDecoded++; } -static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { +bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { LinphoneProxyConfig* proxy; int retry=0; stats initial_caller=caller_mgr->stat; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index f9d73765b..d33ac9f64 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -117,11 +117,24 @@ typedef struct _stats { int number_of_LinphoneMessageNotDelivered; + int number_of_IframeDecoded; int number_of_NewSubscriptionRequest; int number_of_NotifyReceived; + int number_of_LinphoneStatusOffline; + int number_of_LinphoneStatusOnline; + int number_of_LinphoneStatusBusy; + int number_of_LinphoneStatusBeRightBack; + int number_of_LinphoneStatusAway; + int number_of_LinphoneStatusOnThePhone; + int number_of_LinphoneStatusOutToLunch; + int number_of_LinphoneStatusDoNotDisturb; + int number_of_LinphoneStatusMoved; + int number_of_LinphoneStatusAltService; + int number_of_LinphoneStatusPending; + int number_of_LinphoneStatusEnd; + - int number_of_IframeDecoded; }stats; typedef struct _LinphoneCoreManager { @@ -152,6 +165,6 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c 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 call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 9d804ac55..59372cdbe 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -40,19 +40,66 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { ms_free(from); counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_NotifyReceived++; + + switch(linphone_friend_get_status(lf)) { + case LinphoneStatusOffline: counters->number_of_LinphoneStatusOffline++; break; + case LinphoneStatusOnline: counters->number_of_LinphoneStatusOnline++; break; + case LinphoneStatusBusy: counters->number_of_LinphoneStatusBusy++; break; + case LinphoneStatusBeRightBack: counters->number_of_LinphoneStatusBeRightBack++; break; + case LinphoneStatusAway: counters->number_of_LinphoneStatusAway++; break; + case LinphoneStatusOnThePhone: counters->number_of_LinphoneStatusOnThePhone++; break; + case LinphoneStatusOutToLunch: counters->number_of_LinphoneStatusOutToLunch++; break; + case LinphoneStatusDoNotDisturb: counters->number_of_LinphoneStatusDoNotDisturb++; break; + case LinphoneStatusMoved: counters->number_of_LinphoneStatusMoved++; break; + case LinphoneStatusAltService: counters->number_of_LinphoneStatusMoved++; break; + case LinphoneStatusPending: counters->number_of_LinphoneStatusPending++; break; + case LinphoneStatusEnd: counters->number_of_LinphoneStatusEnd++; break; + + } } static void simple_publish(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneProxyConfig* proxy; + int i=0; linphone_core_get_default_proxy(marie->lc,&proxy); linphone_proxy_config_edit(proxy); linphone_proxy_config_enable_publish(proxy,TRUE); linphone_proxy_config_done(proxy); - linphone_core_iterate(marie->lc); + for (i=0;i<10;i++) { + linphone_core_iterate(marie->lc); + ms_usleep(100000); + } linphone_core_manager_destroy(marie); } +static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + stats initial_caller=caller_mgr->stat; + stats initial_callee=callee_mgr->stat; + LinphoneProxyConfig* proxy; + bool_t result=FALSE; + + LinphoneFriend * friend; + linphone_core_get_default_proxy(callee_mgr->lc,&proxy); + if (!proxy) return 0; + + friend=linphone_friend_new_with_addr(linphone_proxy_config_get_identity(proxy)); + 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,&callee_mgr->stat.number_of_LinphoneStatusOnline,initial_callee.number_of_LinphoneStatusOnline+1); + result&=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneStatusOnline,initial_caller.number_of_LinphoneStatusOnline+1); + + CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1); + CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1); + + return result; + +} static void simple_subscribe(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -84,10 +131,28 @@ static void unsubscribe_while_subscribing(void) { linphone_core_manager_destroy(marie); } +static void call_with_presence(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + + CU_ASSERT_TRUE(call(marie,pauline)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneStatusOnThePhone,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneStatusOnThePhone,1); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneStatusOnline,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneStatusOnline,1)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} test_t presence_tests[] = { { "Simple Subscribe", simple_subscribe }, { "Simple Publish", simple_publish }, + { "Call with Presence", call_with_presence }, { "Unsubscribe while subscribing", unsubscribe_while_subscribing }, }; From 06a9ea3cde36068a87265732eb24375c690cfee3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 18 Apr 2013 15:53:44 +0200 Subject: [PATCH 289/909] implement publish --- coreapi/Makefile.am | 1 + coreapi/bellesip_sal/sal_impl.c | 2 +- coreapi/bellesip_sal/sal_impl.h | 11 ++-- coreapi/bellesip_sal/sal_op_call.c | 23 ++++++--- coreapi/bellesip_sal/sal_op_impl.c | 58 ++++++++++++++++++---- coreapi/bellesip_sal/sal_op_presence.c | 21 +++----- coreapi/bellesip_sal/sal_op_publish.c | 46 +++++++++++++++++ coreapi/bellesip_sal/sal_op_registration.c | 37 ++------------ tester/call_tester.c | 15 ++---- tester/empty_rc | 5 +- tester/presence_tester.c | 37 +++++++------- 11 files changed, 152 insertions(+), 104 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_publish.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 3dd43c0db..fd0c31eb4 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -60,6 +60,7 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_sdp.c \ bellesip_sal/sal_op_message.c \ bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_publish.c \ bellesip_sal/sal_op_call_transfer.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 6ef7a2cdf..5e1d197bf 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -345,7 +345,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } else { ms_error("Unhandled transaction terminated [%p]",trans); } - if (op) sal_op_unref(op); /*no longuer need to ref op*/ + if (op && client_transaction) sal_op_unref(op); /*because every client transaction ref op*/ } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index cb5459864..487eb046a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -50,6 +50,7 @@ typedef enum SalOpSate { ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ ,SalOpStateTerminated }SalOpSate_t; +const char* sal_op_state_to_string(const SalOpSate_t value); typedef enum SalOpDir { SalOpDirIncoming=0 @@ -60,7 +61,8 @@ typedef enum SalOpType { SalOpRegister, SalOpCall, SalOpMessage, - SalOpPresence + SalOpPresence, + SalOpPublish }SalOpType_t; const char* sal_op_type_to_string(const SalOpType_t type); @@ -71,7 +73,6 @@ struct SalOp{ belle_sip_server_transaction_t* pending_server_trans; belle_sip_client_transaction_t* pending_client_trans; SalAuthInfo* auth_info; - belle_sip_refresher_t* registration_refresher; bool_t sdp_offering; belle_sip_dialog_t* dialog; belle_sip_header_replaces_t *replaces; @@ -103,8 +104,10 @@ 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 ); + void sal_process_authentication(SalOp *op); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; @@ -120,4 +123,6 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even /*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_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index b21a3ea75..2401df88c 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -146,7 +146,7 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat case 401: case 407: if (op->state!=SalOpStateTerminating) { - /*normal termination for chalanged dialog */ + /*normal termination for challenged dialog */ break; } default: @@ -182,7 +182,7 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { } static void cancelling_invite(SalOp* op ){ belle_sip_request_t* cancel; - ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); + 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; @@ -211,12 +211,16 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t case BELLE_SIP_DIALOG_EARLY: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { if ( op->state == SalOpStateTerminating) { - if (code <200) { - cancelling_invite(op); - } else if (code<400) { - sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { + if (code <200) { + cancelling_invite(op); + } else if (code<400) { + sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + } else { + /*nop ?*/ + } } else { - /*nop ?*/ + /*nop, already cancelled*/ } break; } else if (code >= 180 && code<300) { @@ -708,7 +712,10 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ 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; /*no dialog = dialog in NULL state*/ - op->state=SalOpStateTerminating; + 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")); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index fc7cc6a4c..57e8149ee 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -30,7 +30,6 @@ SalOp * sal_op_new(Sal *sal){ void sal_op_release(SalOp *op){ op->state=SalOpStateTerminated; sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/ - if (op->registration_refresher) belle_sip_refresher_stop(op->registration_refresher); if (op->refresher) belle_sip_refresher_stop(op->refresher); sal_op_unref(op); } @@ -39,10 +38,9 @@ void sal_op_release_impl(SalOp *op){ if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); if (op->auth_info) sal_auth_info_delete(op->auth_info); if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); - if (op->registration_refresher) { - belle_sip_refresher_stop(op->registration_refresher); - belle_sip_object_unref(op->registration_refresher); - op->registration_refresher=NULL; + if (op->refresher) { + belle_sip_object_unref(op->refresher); + op->refresher=NULL; } if(op->replaces) belle_sip_object_unref(op->replaces); if(op->referred_by) belle_sip_object_unref(op->referred_by); @@ -131,6 +129,17 @@ void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { } } + +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); @@ -176,14 +185,13 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req 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 ( strcmp("INVITE",belle_sip_request_get_method(request))==0 || strcmp("REGISTER",belle_sip_request_get_method(request))==0) { - 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 (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); + op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ + belle_sip_object_ref(op->pending_client_trans); + if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); - + if (add_contact) { contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT); @@ -308,3 +316,31 @@ void* sal_op_unref(SalOp* 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)) { + return -1; + } else { + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + } + if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { + belle_sip_refresher_enable_nat_helper(op->refresher,op->base.root->nat_helper_enabled); + belle_sip_refresher_set_listener(op->refresher,listener,op); + return 0; + } else { + return -1; + } + } +} + +const char* sal_op_state_to_string(const SalOpSate_t value) { + switch(value) { + case SalOpStateEarly: return"SalOpStateEarly"; + case SalOpStateActive: return "SalOpStateActive"; + case SalOpStateTerminating: return "SalOpStateTerminating"; + case SalOpStateTerminated: return "SalOpStateTerminated"; + default: + return "Unknon"; + } +} diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 0fcc0af86..434c73a81 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -381,7 +381,7 @@ entity=\"%s\">\n\ } -static void add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status) { +void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status) { char buf[1000]; char *contact_info; size_t content_length; @@ -576,19 +576,7 @@ void sal_op_presence_fill_cbs(SalOp*op) { op->type=SalOpPresence; } -/*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ - 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); - req=sal_op_build_request(op,"PUBLISH"); - add_presence_info(BELLE_SIP_MESSAGE(req),status); - return sal_op_send_request(op,req); -} /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ belle_sip_request_t *req=NULL; @@ -631,15 +619,18 @@ int sal_subscribe_decline(SalOp *op){ } int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); - add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*FIXME, what about expires ??*/ + sal_add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*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_close(SalOp *op){ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); - add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*FIXME, what about expires ??*/ + sal_add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*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..82e48f5c1 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -0,0 +1,46 @@ +/* +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 ( const belle_sip_refresher_t* refresher + ,void* user_pointer + ,unsigned int status_code + ,const char* reason_phrase) { + SalOp* op = (SalOp*)user_pointer; + /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ + ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); + + +} +/*presence publish */ +int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ + belle_sip_request_t *req=NULL; + 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"); + sal_add_presence_info(BELLE_SIP_MESSAGE(req),status); + return sal_op_send_and_create_refresher(op,req,600,publish_refresher_listener); + +} + diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 20b753330..9fc43103f 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -43,7 +43,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher } sal_op_set_service_route(op,(const SalAddress*)service_route_address); if (service_route_address) belle_sip_object_unref(service_route_address); - op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->registration_refresher)>0); + 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- @@ -70,20 +70,6 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher } } - - -/*if expire = -1, does not change expires*/ -static int send_register_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); -} - - int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; belle_sip_uri_t* req_uri; @@ -95,27 +81,12 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ req_uri = belle_sip_request_get_uri(req); belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ - if (send_register_request_with_expires(op,req,expires)) { - return -1; - } else { - if (op->registration_refresher) { - belle_sip_refresher_stop(op->registration_refresher); - belle_sip_object_unref(op->registration_refresher); - } - if ((op->registration_refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { - belle_sip_refresher_enable_nat_helper(op->registration_refresher,op->base.root->nat_helper_enabled); - belle_sip_refresher_set_listener(op->registration_refresher,register_refresher_listener,op); - return 0; - } else { - return -1; - } - - } + return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); } int sal_register_refresh(SalOp *op, int expires){ - if (op->registration_refresher) - return belle_sip_refresher_refresh(op->registration_refresher,expires); + if (op->refresher) + return belle_sip_refresher_refresh(op->refresher,expires); else return -1; } diff --git a/tester/call_tester.c b/tester/call_tester.c index e56866294..bfb3dac2e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -93,15 +93,11 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { } bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { - LinphoneProxyConfig* proxy; int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; - LinphoneAddress* identity; - linphone_core_get_default_proxy(callee_mgr->lc,&proxy); - CU_ASSERT_PTR_NOT_NULL(proxy); - if (!proxy) return -1; + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); @@ -127,15 +123,12 @@ bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) |(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); - linphone_core_get_default_proxy(caller_mgr->lc,&proxy); - CU_ASSERT_PTR_NOT_NULL(proxy); - if (!proxy) return 0; - identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); if (!linphone_core_get_current_call_remote_address(callee_mgr->lc)) return 0; - CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); - linphone_address_destroy(identity); + CU_ASSERT_TRUE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); diff --git a/tester/empty_rc b/tester/empty_rc index e8de43fa4..2fa8c43a3 100644 --- a/tester/empty_rc +++ b/tester/empty_rc @@ -1,5 +1,6 @@ -[net] +[net] mtu=1300 [sip] -ping_with_options=0 \ No newline at end of file +ping_with_options=0 +sip_random_port=1 \ No newline at end of file diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 59372cdbe..cf7ce5f6d 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -22,7 +22,15 @@ #include "private.h" #include "liblinphone_tester.h" - +static LinphoneCoreManager* presence_linphone_core_manager_new(char* username) { + LinphoneCoreManager* mgr= linphone_core_manager_new2(liblinphone_tester_file_prefix, "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_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ char* from=linphone_address_as_string(linphone_friend_get_address(lf)); stats* counters; @@ -76,14 +84,11 @@ static void simple_publish(void) { 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; - LinphoneProxyConfig* proxy; bool_t result=FALSE; + char* identity=linphone_address_as_string_uri_only(callee_mgr->identity); - LinphoneFriend * friend; - linphone_core_get_default_proxy(callee_mgr->lc,&proxy); - if (!proxy) return 0; - friend=linphone_friend_new_with_addr(linphone_proxy_config_get_identity(proxy)); + LinphoneFriend* friend=linphone_friend_new_with_addr(identity); linphone_friend_edit(friend); linphone_friend_enable_subscribes(friend,TRUE); linphone_friend_done(friend); @@ -96,23 +101,15 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1); CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1); CU_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1); - + ms_free(identity); return result; } static void simple_subscribe(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - const MSList* marie_friends = linphone_core_get_friend_list(marie->lc); - LinphoneFriend* friend; - CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends); - friend = (LinphoneFriend*) marie_friends->data; - linphone_friend_edit(friend); - linphone_friend_enable_subscribes(friend,TRUE); - linphone_friend_done(friend); + LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1)); + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); linphone_core_manager_destroy(marie); CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ @@ -132,8 +129,8 @@ static void unsubscribe_while_subscribing(void) { } static void call_with_presence(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); CU_ASSERT_TRUE(call(marie,pauline)); From 9b846f0ecc01832da295712409d4c996f3017b95 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 23 Apr 2013 13:56:35 +0200 Subject: [PATCH 290/909] better support of publish --- coreapi/bellesip_sal/sal_op_presence.c | 3 ++- coreapi/bellesip_sal/sal_op_publish.c | 27 +++++++++++++++++--------- tester/presence_tester.c | 5 +++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 434c73a81..390462ebf 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -392,9 +392,10 @@ void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); - + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application",presence_style?"xpidf+xml":"pidf+xml"))); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(buf)))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),buf,content_length); diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 82e48f5c1..29d78cd72 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -32,15 +32,24 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher /*presence publish */ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ belle_sip_request_t *req=NULL; - 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"); - sal_add_presence_info(BELLE_SIP_MESSAGE(req),status); - return sal_op_send_and_create_refresher(op,req,600,publish_refresher_listener); + 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"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); + sal_add_presence_info(BELLE_SIP_MESSAGE(req),status); + return sal_op_send_and_create_refresher(op,req,600,publish_refresher_listener); + } else { + /*update status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*update status*/ + sal_add_presence_info(BELLE_SIP_MESSAGE(last_publish),status); + return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + } } diff --git a/tester/presence_tester.c b/tester/presence_tester.c index cf7ce5f6d..308388710 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -78,6 +78,11 @@ static void simple_publish(void) { linphone_core_iterate(marie->lc); ms_usleep(100000); } + linphone_core_set_presence_info(marie->lc,0,NULL,LinphoneStatusOffline); + for (i=0;i<10;i++) { + linphone_core_iterate(marie->lc); + ms_usleep(100000); + } linphone_core_manager_destroy(marie); } From 4de9a7f7e1815de3ef7b1995e3e04820bad3995a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 24 Apr 2013 11:57:52 +0200 Subject: [PATCH 291/909] link to libxml2 statically (shared version not working with android-ndk-r8e) --- build/android/common.mk | 4 +++- build/android/lpc2xml.mk | 1 - build/android/xml2lpc.mk | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index 584649735..d0bf70cad 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -95,10 +95,12 @@ LOCAL_STATIC_LIBRARIES := \ libeXosip2 \ libosip2 \ libgsm + ifeq ($(BUILD_REMOTE_PROVISIONING),1) LOCAL_STATIC_LIBRARIES += \ libxml2lpc \ - liblpc2xml + liblpc2xml \ + liblpxml2 endif ifeq ($(BUILD_TUNNEL),1) diff --git a/build/android/lpc2xml.mk b/build/android/lpc2xml.mk index 91038adce..d93be9b79 100644 --- a/build/android/lpc2xml.mk +++ b/build/android/lpc2xml.mk @@ -39,7 +39,6 @@ LOCAL_C_INCLUDES = \ $(LOCAL_PATH)/../../externals/build/libxml2 \ LOCAL_SHARED_LIBRARIES = \ - libxml2 # liblinphonenoneon \ # liblinphone \ diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk index e89ab383b..55e4a03a0 100644 --- a/build/android/xml2lpc.mk +++ b/build/android/xml2lpc.mk @@ -39,7 +39,6 @@ LOCAL_C_INCLUDES = \ $(LOCAL_PATH)/../../externals/build/libxml2 \ LOCAL_SHARED_LIBRARIES = \ - libxml2 # liblinphonenoneon \ # liblinphone \ From 21147b0c44042f47ff3513f83ec4e839570a3156 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 24 Apr 2013 14:08:14 +0200 Subject: [PATCH 292/909] Add missing export. --- coreapi/linphonecore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 57369545d..d9c017fea 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1461,7 +1461,7 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); * @param uri which should match call remote uri * @return LinphoneCall or NULL is no match is found */ -const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); +LINPHONE_PUBLIC const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc); From 51d3ea2759f2a714f5c2a04d3745ae6bcdfe4e95 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 24 Apr 2013 14:14:22 +0200 Subject: [PATCH 293/909] Add sal_op_publish.c file to the Visual Studio project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index b52044b7c..71bf6912c 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -179,6 +179,7 @@ + From 91cdae81ce81552ecc562085d2733cb367a31f87 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 25 Apr 2013 10:36:18 +0200 Subject: [PATCH 294/909] add special case to compute aac network birate --- coreapi/misc.c | 11 ++++++++++- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 35a58e200..5d4c0ebcc 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -234,12 +234,21 @@ static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){ return pt->normal_bitrate; } +/* + *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; + *ptime=1/npacket + */ static double get_audio_payload_bandwidth(LinphoneCore *lc, 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; + } + bitrate=get_codec_bitrate(lc,pt); - packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; + packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; return packet_size*8.0*npacket; } diff --git a/mediastreamer2 b/mediastreamer2 index 07824fcf3..23b802c46 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 07824fcf3879d265c59beaf970d833b5859f3691 +Subproject commit 23b802c4631fdf909a218a0dd0a77c6cf6d4d5a9 diff --git a/oRTP b/oRTP index 20b527144..bd64df514 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 20b527144f9850dd9065d96db7a20244e8a8b227 +Subproject commit bd64df5148bdfd4a2ff5153927676fc497118279 From 19495da6b960bcceee048d3d2ca57eb4ef7de05c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 25 Apr 2013 10:54:29 +0200 Subject: [PATCH 295/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 23b802c46..c3e5bad58 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 23b802c4631fdf909a218a0dd0a77c6cf6d4d5a9 +Subproject commit c3e5bad583aad848e1e0d5391092311a31f3ea5a From 2a95bd9707e674159a02a1bbec9cd727ddf8401a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 25 Apr 2013 11:17:11 +0200 Subject: [PATCH 296/909] Increment tries in loop that have a maximum number of tries. --- coreapi/sal_eXosip2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index e577b6422..222e7c329 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -2400,6 +2400,7 @@ int sal_register_refresh(SalOp *op, int expires){ * the exosip lock in a non blocking way, and give up if it takes too long*/ while (eXosip_trylock()!=0){ ms_usleep(100000); + tries++; if (tries>30) {/*after 3 seconds, give up*/ ms_warning("Could not obtain exosip lock in a reasonable time, giving up."); return -1; From f9685df87b2d06c692aca78d6961cf3672097bdd Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 25 Apr 2013 17:00:31 +0200 Subject: [PATCH 297/909] Aac-eld add missing header according to RFC3640 3.3.6 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c3e5bad58..bec2520cb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c3e5bad583aad848e1e0d5391092311a31f3ea5a +Subproject commit bec2520cbb80daf9420bf71c05e25394e2b6024d From feae19c319c152cad00082fefc431c411cf6b14a Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 26 Apr 2013 01:12:51 +0200 Subject: [PATCH 298/909] aac-eld support multiframe per packet decoding --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index bec2520cb..3acaa7372 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bec2520cbb80daf9420bf71c05e25394e2b6024d +Subproject commit 3acaa7372423ffb0d18923e9e41e1076cec51905 From ff0f3964c5c48326985188f09c43447d97e7172b Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Fri, 26 Apr 2013 10:47:04 +0200 Subject: [PATCH 299/909] Fix UI feedbacks : - updates pixmaps - contact list resizable - property.ui modified - call stats remove when a call ends - update hebrew translation file --- README | 2 +- gtk/about.ui | 1 + gtk/incall_view.c | 3 +- gtk/main.ui | 76 +++++++--- gtk/parameters.ui | 252 +++++++++++++++++--------------- gtk/propertybox.c | 27 +++- pixmaps/contact_unstarred.png | Bin 3243 -> 2894 bytes pixmaps/startcall-small.png | Bin 3869 -> 3726 bytes po/cs.po | 50 +++---- po/de.po | 50 +++---- po/es.po | 50 +++---- po/fr.po | 207 +++++++++++++------------- po/he.po | 266 +++++++++++++++------------------- po/hu.po | 50 +++---- po/it.po | 50 +++---- po/ja.po | 50 +++---- po/nb_NO.po | 50 +++---- po/nl.po | 50 +++---- po/pl.po | 50 +++---- po/pt_BR.po | 50 +++---- po/ru.po | 50 +++---- po/sr.po | 50 +++---- po/sv.po | 50 +++---- po/zh_CN.po | 50 +++---- po/zh_TW.po | 50 +++---- 25 files changed, 807 insertions(+), 777 deletions(-) diff --git a/README b/README index db78b72e5..1a66f4a27 100644 --- a/README +++ b/README @@ -49,7 +49,7 @@ with their corresponding -dev or -devel package if you don't use source packages $ ./autogen.sh $ ./configure - $ sudo make install + $ make && sudo make install $ sudo ldconfig - Command line for Ubuntu && Debian diff --git a/gtk/about.ui b/gtk/about.ui index 1d79dbf7e..38fc2e796 100644 --- a/gtk/about.ui +++ b/gtk/about.ui @@ -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/incall_view.c b/gtk/incall_view.c index 44b35c03c..01e3b3cd9 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -758,10 +758,11 @@ 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); - + if (taskid!=0) g_source_remove(taskid); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); if (in_conf) diff --git a/gtk/main.ui b/gtk/main.ui index 347a402ea..591b042ae 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -7,6 +7,16 @@ False gtk-add
+ + True + False + gtk-add + + + True + False + gtk-add + False @@ -701,6 +711,16 @@ False gtk-edit + + True + False + gtk-edit + + + True + False + gtk-edit + True False @@ -751,11 +771,21 @@ False gtk-select-color + + True + False + gtk-add + True False gtk-refresh + + True + False + gtk-add + True False @@ -1088,9 +1118,9 @@ - + True - False + True True @@ -1144,16 +1174,14 @@ 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 + add_image2 1 @@ -1168,9 +1196,8 @@ True True True - Edit False - edit_image + edit_image2 @@ -1185,7 +1212,7 @@ True True False - remove_image + remove_image2 @@ -1203,10 +1230,8 @@ - False - False - 6 - 0 + False + True @@ -1353,7 +1378,7 @@ True True False - image16 + image20 @@ -1467,10 +1492,8 @@
- True - True - 6 - 1 + True + True
@@ -1529,13 +1552,6 @@ False none - - - True - False - gtk-refresh - -
True @@ -1880,4 +1896,16 @@ Delete gtk-remove
+ + True + False + Delete + gtk-remove + + + True + False + Delete + gtk-remove + diff --git a/gtk/parameters.ui b/gtk/parameters.ui index e4a6430fa..b8063792f 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -639,53 +639,115 @@ 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) + + Direct connection to the Internet True True False False True True + + + + False + False + 0 + + + + + Behind NAT / Firewall (specify gateway IP ) + True + True + False + False + True no_nat True True - 0 + 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) + True + True + False + 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 @@ -705,6 +767,8 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True False False True @@ -720,7 +784,53 @@ True - 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 @@ -731,102 +841,6 @@ 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 - - diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 1c189e0b8..f30b55d05 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -131,6 +131,13 @@ void linphone_gtk_update_my_port(GtkWidget *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){ const gchar *addr=gtk_entry_get_text(GTK_ENTRY(w)); linphone_core_set_stun_server(linphone_gtk_get_core(),addr); @@ -217,28 +224,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){ diff --git a/pixmaps/contact_unstarred.png b/pixmaps/contact_unstarred.png index ad041095b4696747d24dbc5d4392a74efb589bd1..38fdbbb7740c1712054214af3d63427b1b7201a7 100644 GIT binary patch delta 2861 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 Z{{;vjA1VGm?-u|7002ovPDHLkV1m_)B}o7P diff --git a/pixmaps/startcall-small.png b/pixmaps/startcall-small.png index 30b32789a802b49afbd0e0c576ca3fd92a743520..d5726e12c03df86864df4c48e8f98c33ba6af9fe 100644 GIT binary patch delta 1068 zcmV+{1k?MS9*!L$iBL{Q4GJ0x0000DNk~Le0000I0000G2nGNE02>A`T(Kc^3V#FR zNklr{;7}lhmBejO@CNpwn>|YB7(MCmq#Tc@+t)ijnqOAmUdxTmfgEE<6IIF(n;>U zXXebDd%o{{XMl4K*5l zxU3`6b-FI>t5%R>fJC-{)!lIxUqcGC^k(q9pqhku$e?fvR;E#w(68g>&J2>4_%w+cY~+)I2Mq#eI!NN@6t zYI6;XIPX@$U6M9C}h}hbS8`5u*oBt@;q1If7>#!xa_J5YF&+HENI8@Jw zeo;xo*OL+WQbq-BkibaN1zAcG@;E`@NnQa8%@GG@^1UFp113BE0%9oY-Xz5=+{F35 z%IG4eyazZoNeVBJSOS1kR*-6BPXZ@5iBpgv!!Tc>Ggbx@0!EvVhc0WyjN{L;0s$$7 ze^GkfwTCgh3leMqLw`*Y)fylUZ0yRNO=yt=ry%USC8<~`@0UKU88==o3#z$!S6q8& z63P(apqz$wV#fl7Q9Cls5aM)+RQ{HdBzD#=JBnYMDmwj3`NZtK)#c-Mp7|Y7Yz^XX zovK^v$ttEDih(C34Ir_~fl+>;@5Sh%oPu5&13QbuMWHFcBYz|5UqA1zZ^@IM`{a$x zlOJ1<%KK7E(XmmlI_-s`gWQ5Qlg9ZhH(BSSx%iFL9IaIleU?VpH^HLVJKGHlec(KG zuld5wh@U@9-tU@R8*ct#^@M9jH~FpL$o7G5&C7qc71m7Y-`7s-yz)=IyYvqu(^^L# z_epKg#;^sI(SOeaZ)V$aK3X9Q?%uVl_xo0QX8)m6^GL`RnA9comV-7d5>OOmaE`4h zXL_r`k1UOCcmE|gM!evs7NmuTvwP>2@y4M@?<=C?pZ$01&ORcmAV^&kcg3_M^GH*C5S9P{002ovPDHLkU;%doSNKD2@fdL&*7-8tx7RFZw-GBk@ZF}!IzULypJ;`a$ zdEfVW-p_M^a}IkOf*^g&f$rV^?|;9x2b`V>e)oV~3x~Y{*JL90sC)uH8t6XJ#;*)1l_5w}8PGQ(41cm3rGC zKnnCo1Q%{Rpl@uSp+oYjapkl`;XJiKny$hUW85?7j?dFXj@pL8eW1~kdt?G6z=8yi zqEXDCMJFN(RKlP;b`jmYti>QHDdd1e=;s1Qypzf#f|o)^;!SlCC4WyNa2DZ1A$PpP zFxZXMh|IWSbp9Y#t^}lDF;7-c+5(c9pJOVZkk?QI7lQ^P!dU0zU2`^VqYC-f8?k*Q zWP53fGe#_G&Vx8!f=tLv+Q5`Vg$qw5=J`v)~+geG1{^%!C)KO~gENFPQA*g+JsFZ#V(Yk>fv zwY?yTNb9H5U7iW+@3Nha$hOp&XVlg#U>wMlXcytcN-^<4^xuG+WGvTw!s7g@oFN)Z zU-FKpH~!WFQco?{1W;8qCzW}Vu5y=bCwX}G2|3ovPI2y8ihtjwjPq~IIW(^^vj6SQ zXFC&xCZC_JTYi)sya;!fm0E|Z$E_E=lh!jJNgrVGb&wF8Kq85R3_?m8bu1cZ>}OIE zEHP&m%#0S;E6eg}Y2$}^Uv~?m=Bc6=9_b6OA++9{O-z`H$PH2(n7j^a1ZS}SNbI~X zVtZb)!xe3lhkruun9q1AN5iDV>#QGgJ3aP7>ONha{oI#^XZ)#{CXbm@)+Zqa2XQc| zY=U{qYOJrjf$w<6Y|T{Sm(k3OQ(GZk3;4NT63_3<-z{YwE1%wq@;M%jFOGKI|E}$` zg*Wpt9>b}y+1tKRrK);D3D(`Qa_@w)?Fn0(gbwFZGJlK%y#cwswp|O1JZ*oy?ECjo z_s%_KTIpNrg2>jjI}6%B%MvvuIny(+J^3al$;8G0*6p&1v$H+r>YVtxt1G=;p36*VRtmSc!+`t>&WlpP~PMkze\n" "Language-Team: Czech \n" @@ -109,7 +109,7 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Neplatný sipový kontakt!" @@ -176,11 +176,11 @@ msgstr "" msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Příchozí hovor" @@ -1512,19 +1512,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "přerušen" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "dokončen" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "promeškán" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1539,70 +1539,70 @@ msgstr "" "Stav: %s\n" "Délka: %i min %i s\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Připraven." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Vyhledává se umístění čísla…" -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Toto číslo nelze vyhledat." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" msgstr "" "Špatně zadaná SIP adresa. Adresa má mít tento formát " -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Kontaktuji" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Nelze volat" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 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:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "vás volá" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " a požaduje automatickou zvednutí." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Upravují se parametry hovoru…" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Připojeno." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" @@ -1821,7 +1821,7 @@ msgstr "Registrace na %s selhala: %s" msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/de.po b/po/de.po index 44c1e66ea..855048c94 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2012-11-07 19:27+0100\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" @@ -96,7 +96,7 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Ungültiger SIP-Kontakt!" @@ -165,11 +165,11 @@ msgstr "" msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Eingehender Anruf" @@ -1492,19 +1492,19 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "abgebrochen" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "beendet" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "entgangen" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1519,23 +1519,23 @@ msgstr "" "Status: %s\n" "Dauer: %i min %i sec\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Abgehender Anruf" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Bereit" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Telefonnummernziel wird gesucht..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Diese Nummer kann nicht aufgelöst werden." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1543,47 +1543,47 @@ msgstr "" "SIP-Adresse kann nicht eingelesen werden. Eine SIP-Adresse hat folgenden " "Aufbau " -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Verbindungsaufbau" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Anruf kann nicht getätigt werden." -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Die maximale Anzahl der gleichzeitigen Anrufe ist erreicht." -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "ruft Sie an" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " und fragt nach automatischer Antwort." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Die Anrufparameter werden verändert..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Verbunden." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." @@ -1802,7 +1802,7 @@ msgstr "Registrierung auf %s fehlgeschlagen: %s" msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/es.po b/po/es.po index 90fa0f926..474f630f4 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2012-12-06 15:54+0100\n" "Last-Translator: BERAUDO Guillaume \n" "Language-Team: es \n" @@ -101,7 +101,7 @@ msgstr "Yo" msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "¡Contacto SIP no válido!" @@ -170,12 +170,12 @@ msgstr "" msgid "Call error" msgstr "Error en la llamada." -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 #, fuzzy msgid "Call ended" msgstr "Llamada terminada" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Llamada entrante" @@ -1572,19 +1572,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "abortada" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "completada" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "perdida" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1599,24 +1599,24 @@ msgstr "" "Estado: %s\n" "Duración: %i min %i seg\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Llamada saliente" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 #, fuzzy msgid "Ready" msgstr "Preparado" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Buscando el número de teléfono del destinatario…" -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "No se ha podido resolver este número." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 #, fuzzy msgid "" "Could not parse given sip address. A sip url usually looks like sip:" @@ -1625,51 +1625,51 @@ msgstr "" "Dirección SIP mal escrita. Una dirección SIP es del tipo " -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 #, fuzzy msgid "Contacting" msgstr "Contactando" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "No se pudo llamar" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 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:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "le está llamando" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "y ha solicitado auto respuesta." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Modificando parámetros de llamada…" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "Llamada abortada" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "No se pudo pausar la llamada" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Pausando la llamada actual..." @@ -1898,7 +1898,7 @@ msgstr "El registro en %s ha fallado." msgid "Authentication token is %s" msgstr "El tóken de autenticación es%s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/fr.po b/po/fr.po index 48e85b46b..02c1f8fca 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2013-04-09 13:57+0100\n" "Last-Translator: Simon Morlat \n" "Language-Team: french \n" @@ -15,14 +15,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 -#: ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 #, c-format msgid "Call %s" msgstr "Appeler %s" -#: ../gtk/calllogs.c:140 -#: ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 #, c-format msgid "Send text to %s" msgstr "Chatter avec %s" @@ -62,8 +60,7 @@ msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 -#: ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format msgid "%s\t%s" msgstr "" @@ -84,8 +81,7 @@ msgid "" "%s" msgstr "" -#: ../gtk/conference.c:38 -#: ../gtk/main.ui.h:13 +#: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" msgstr "Conférence" @@ -93,15 +89,12 @@ msgstr "Conférence" 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/chat.c:324 -#: ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Contact sip invalide !" @@ -130,8 +123,12 @@ msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" #: ../gtk/main.c:134 -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)" +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:515 #, c-format @@ -142,12 +139,15 @@ msgstr "Appel avec %s" #, 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" +"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 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'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." #: ../gtk/main.c:1023 #, c-format @@ -162,24 +162,19 @@ msgstr "" msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1129 -#: ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1132 -#: ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1134 -#: ../gtk/incall_view.c:497 -#: ../gtk/main.ui.h:5 +#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1136 -#: ../gtk/main.ui.h:6 +#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" @@ -210,8 +205,7 @@ msgstr "Linphone - un téléphone video pour l'internet" msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1796 -#: ../coreapi/callbacks.c:810 +#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" @@ -236,9 +230,7 @@ msgstr "Ajouter au carnet d'adresse" msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:661 -#: ../gtk/propertybox.c:367 -#: ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" @@ -291,13 +283,11 @@ msgstr "Débit min. (kbit/s)" msgid "Parameters" msgstr "Paramètres" -#: ../gtk/propertybox.c:435 -#: ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 msgid "Enabled" msgstr "Activé" -#: ../gtk/propertybox.c:437 -#: ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 msgid "Disabled" msgstr "Désactivé" @@ -378,8 +368,11 @@ msgid "Serbian" msgstr "Serbe" #: ../gtk/propertybox.c:848 -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." +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:934 msgid "None" @@ -400,7 +393,8 @@ msgid "" "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 ?" +"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." @@ -461,8 +455,7 @@ msgstr "Entrez votre identifiant linphone.org" msgid "Username:" msgstr "Nom d'utilisateur:" -#: ../gtk/setupwizard.c:94 -#: ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 msgid "Password:" msgstr "Mot de passe:" @@ -511,7 +504,8 @@ 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" +"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:380 @@ -520,10 +514,12 @@ msgstr "Merci. Votre compte est maintenant configuré et prêt à être utilisé #: ../gtk/setupwizard.c:388 msgid "" -"Please validate your account by clicking on the link we just sent you by email.\n" +"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" +"Merci de valider votre compte en cliquant sur le lien que nous avons envoyé " +"par email.\n" "Puis appuyez sur suivant." #: ../gtk/setupwizard.c:564 @@ -558,8 +554,7 @@ msgstr "Erreur" msgid "Terminating" msgstr "En cours d’arrêt." -#: ../gtk/incall_view.c:70 -#: ../gtk/incall_view.c:94 +#: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format msgid "Call #%i" msgstr "Appel #%i" @@ -569,8 +564,7 @@ msgstr "Appel #%i" msgid "Transfer to call #%i with %s" msgstr "Transférer vers l'appel #%i avec %s" -#: ../gtk/incall_view.c:210 -#: ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 #, fuzzy msgid "Not used" msgstr "Non trouvé" @@ -621,13 +615,11 @@ msgstr "uPnP en cours d’exécution" msgid "uPnP failed" msgstr "uPnP a échoué." -#: ../gtk/incall_view.c:256 -#: ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 msgid "Direct or through server" msgstr "Directe ou via un serveur" -#: ../gtk/incall_view.c:259 -#: ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 #, c-format msgid "" "download: %f\n" @@ -639,8 +631,7 @@ msgstr "" msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 -#: ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Raccrocher" @@ -648,8 +639,7 @@ msgstr "Raccrocher" msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:479 -#: ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 msgid "00::00::00" msgstr "" @@ -677,8 +667,7 @@ msgstr "très faible" msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:536 -#: ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 msgid "unavailable" msgstr "indisponible" @@ -695,8 +684,7 @@ msgstr "Sécurisé par ZRTP- [jeton: %s]" msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:663 -#: ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" @@ -737,8 +725,7 @@ msgstr "Transfert échoué" msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:835 -#: ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" @@ -843,13 +830,11 @@ msgstr "Démarrer un nouvel appel" msgid "Contacts" msgstr "Contacts" -#: ../gtk/main.ui.h:28 -#: ../gtk/parameters.ui.h:50 +#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 msgid "Add" msgstr "Ajouter" -#: ../gtk/main.ui.h:29 -#: ../gtk/parameters.ui.h:51 +#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 msgid "Edit" msgstr "Editer" @@ -873,13 +858,11 @@ msgstr "Appels récents" msgid "My current identity:" msgstr "Mon identité sip:" -#: ../gtk/main.ui.h:35 -#: ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Nom d'utilisateur" -#: ../gtk/main.ui.h:36 -#: ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Mot de passe" @@ -1066,8 +1049,7 @@ msgstr "Codecs audio" msgid "Video codecs" msgstr "Codecs vidéo" -#: ../gtk/parameters.ui.h:7 -#: ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" @@ -1218,7 +1200,9 @@ msgstr "Paramètres multimedia" #: ../gtk/parameters.ui.h:44 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" +msgstr "" +"Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de " +"compte SIP" #: ../gtk/parameters.ui.h:45 msgid "Your display name (eg: John Doe):" @@ -1260,13 +1244,11 @@ msgstr "Sécurité" msgid "Manage SIP Accounts" msgstr "Gérer mes comptes SIP" -#: ../gtk/parameters.ui.h:57 -#: ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Activer" -#: ../gtk/parameters.ui.h:58 -#: ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Désactiver" @@ -1291,8 +1273,13 @@ msgid "Enable adaptive rate control" msgstr "Activer le control de débit adaptatif." #: ../gtk/parameters.ui.h:64 -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." +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:65 msgid "Bandwidth control" @@ -1481,19 +1468,19 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "abandonné" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "terminé" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "manqué" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1508,67 +1495,70 @@ msgstr "" "Etat: %s\n" "Durée: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Appel sortant" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Prêt." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Recherche de la destination du numéro de téléphone..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "La destination n'a pu être trouvée." -#: ../coreapi/linphonecore.c:2231 -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:2252 +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:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Appel de" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Echec de l'appel" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 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:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "vous appelle" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "et sollicite un décrochage automatique." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Modifications des paramètres d'appels..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "En ligne." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." @@ -1654,8 +1644,12 @@ msgid "Unknown-bug" msgstr "Bug inconnu" #: ../coreapi/proxy.c:204 -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." +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:210 msgid "" @@ -1663,7 +1657,8 @@ msgid "" "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:username@domain, comme par example sip:" +"alice@example.net" #: ../coreapi/proxy.c:1069 #, c-format @@ -1784,7 +1779,7 @@ msgstr "Echec de l'enregistrement sur %s: %s" msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/he.po b/po/he.po index b8b2895b8..32e51337c 100644 --- a/po/he.po +++ b/po/he.po @@ -2,16 +2,16 @@ # Copyright (C) Belledonne Communications,2010 # This file is distributed under the same license as the linphone package. # Eli Zaretskii , 2012. -# Isratine Citizen , 2012. +# Isratine Citizen , 2012, 2013. # msgid "" msgstr "" -"Project-Id-Version: Linphone 3.5.2\n" +"Project-Id-Version: Linphone 3.5.99.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-08 16:59+0200\n" -"PO-Revision-Date: 2012-12-27 10:14+0200\n" +"PO-Revision-Date: 2013-04-24 21:31+0200\n" "Last-Translator: Isratine Citizen \n" -"Language-Team: Rahut \n" +"Language-Team: Rahut Project \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,29 +31,25 @@ msgid "Send text to %s" msgstr "שלח טקסט אל %s" #: ../gtk/calllogs.c:223 -#, fuzzy, c-format +#, c-format msgid "Recent calls (%i)" -msgstr "בשיחה כעת" +msgstr "שיחות אחרונות (%i)" #: ../gtk/calllogs.c:300 msgid "n/a" msgstr "לא זמין (n/a)" #: ../gtk/calllogs.c:303 -#, fuzzy msgid "Aborted" msgstr "ננטשה" #: ../gtk/calllogs.c:306 -#, fuzzy msgid "Missed" msgstr "הוחמצה" -# דחיה #: ../gtk/calllogs.c:309 -#, fuzzy msgid "Declined" -msgstr "לדחות" +msgstr "נדחתה" #: ../gtk/calllogs.c:315 #, c-format @@ -70,29 +66,25 @@ msgstr[0] "שניה %i" msgstr[1] "%i שניות" #: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 -#, fuzzy, c-format +#, c-format msgid "%s\t%s" msgstr "" -"%s\t%s\tאיכות: %s\n" -"%s\t%s %s\t" #: ../gtk/calllogs.c:323 -#, fuzzy, c-format +#, c-format msgid "" "%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:329 -#, fuzzy, c-format +#, c-format msgid "" "%s\t\n" "%s" msgstr "" -"%s\t%s\tאיכות: %s\n" -"%s\t%s %s\t" #: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" @@ -124,9 +116,11 @@ msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמ msgid "path to a file to write logs into." msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." +# cli #: ../gtk/main.c:106 +#, fuzzy msgid "Start linphone with video disabled." -msgstr "" +msgstr "התחל את לינפון עם וידאו מנוטרל." # cli #: ../gtk/main.c:113 @@ -214,14 +208,14 @@ msgid "Call paused" msgstr "שיחה הושהתה" #: ../gtk/main.c:1142 -#, fuzzy, c-format +#, c-format msgid "by %s" -msgstr "Ports utilisés" +msgstr "על ידי %s" #: ../gtk/main.c:1191 #, c-format msgid "%s proposed to start video. Do you accept ?" -msgstr "" +msgstr "‏%s רוצה להתחיל וידאו. האם אתה מסכים ?" #: ../gtk/main.c:1353 msgid "Website link" @@ -232,10 +226,11 @@ msgstr "קישור אתר רשת" msgid "Linphone - a video internet phone" msgstr "‫Linphone - וידאופון אינטרנטי" +# משתמטת #: ../gtk/main.c:1494 #, c-format msgid "%s (Default)" -msgstr "‫%s (משתמטת)" +msgstr "‫%s (ברירת מחדל)" #: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 #, c-format @@ -249,7 +244,7 @@ msgid "" "You won't be able to send or receive audio calls." msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" -"לא תהיה ביכולתך לשלוח או לקבל שיחות שמע." +"לא תהיה ביכולתך לשלוח או לקבל שיחות אודיו." #: ../gtk/main.c:1911 msgid "A free SIP video-phone" @@ -273,7 +268,7 @@ msgstr "קריאה" #: ../gtk/friendlist.c:678 msgid "Chat" -msgstr "" +msgstr "שיחה" # a name or a number #: ../gtk/friendlist.c:708 @@ -292,9 +287,9 @@ msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" #: ../gtk/friendlist.c:926 -#, fuzzy, c-format +#, c-format msgid "Delete chat history of '%s'" -msgstr "מחק איש קשר '%s'" +msgstr "מחק היסטוריית שיחה של '%s'" #: ../gtk/friendlist.c:977 #, c-format @@ -319,10 +314,12 @@ msgstr "קצב נתונים מינימלי (קי״ב/שנ׳)" msgid "Parameters" msgstr "פרמטרים" +# מאופשר #: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 msgid "Enabled" msgstr "מופעל" +# מנוטרל #: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 msgid "Disabled" msgstr "לא מופעל" @@ -399,11 +396,11 @@ msgstr "norsk" #: ../gtk/propertybox.c:780 msgid "Hebrew" -msgstr "" +msgstr "עברית" #: ../gtk/propertybox.c:781 msgid "Serbian" -msgstr "" +msgstr "српски srpski" # selected הנבחרת #: ../gtk/propertybox.c:848 @@ -548,7 +545,6 @@ msgstr "" "שגיאה, חשבון לא אומת, שם משתמש כבר בשימוש או שרת לא ניתן להשגה.\n" "נא לחזור ולנסות שוב." -# תודה רבה #: ../gtk/setupwizard.c:380 msgid "Thank you. Your account is now configured and ready for use." msgstr "תודה לך. חשבונך מוגדר ומוכן לשימוש כעת." @@ -610,63 +606,56 @@ msgid "Transfer to call #%i with %s" msgstr "העברה אל שיחה מס׳ %i עם %s" #: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 -#, fuzzy msgid "Not used" -msgstr "לא נמצא" +msgstr "לא בשימוש" #: ../gtk/incall_view.c:220 msgid "ICE not activated" -msgstr "" +msgstr "‏ICE לא מופעלת" #: ../gtk/incall_view.c:222 -#, fuzzy msgid "ICE failed" -msgstr "קריאה נכשלה." +msgstr "‏ICE נכשלה" #: ../gtk/incall_view.c:224 msgid "ICE in progress" -msgstr "" +msgstr "‏ICE מצויה כעת בעיצומה" #: ../gtk/incall_view.c:226 msgid "Going through one or more NATs" -msgstr "" +msgstr "עובר דרך NAT אחד או יותר" #: ../gtk/incall_view.c:228 -#, fuzzy msgid "Direct" -msgstr "מכוון מחדש" +msgstr "ישיר" #: ../gtk/incall_view.c:230 msgid "Through a relay server" -msgstr "" +msgstr "דרך שרת ממסר" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" -msgstr "" +msgstr "‏uPnP לא מופעלת" -# במהלך (או) באמצע חיפוש... #: ../gtk/incall_view.c:240 -#, fuzzy msgid "uPnP in progress" -msgstr "בדיקת STUN מצויה כעת בעיצומה..." +msgstr "‏uPnP מצויה כעת בעיצומה" #: ../gtk/incall_view.c:242 -#, fuzzy msgid "uPnp not available" -msgstr "לא זמינה" +msgstr "‏uPnp לא זמינה" #: ../gtk/incall_view.c:244 msgid "uPnP is running" -msgstr "" +msgstr "‏uPnP מורצת כעת" #: ../gtk/incall_view.c:246 -#, fuzzy msgid "uPnP failed" -msgstr "קריאה נכשלה." +msgstr "‏uPnP נכשלה" #: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 msgid "Direct or through server" -msgstr "" +msgstr "ישיר או דרך שרת" #: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 #, c-format @@ -674,15 +663,17 @@ msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"הורדה: %f\n" +"העלאה: %f (קי״ב/שנ׳)" #: ../gtk/incall_view.c:286 -#, fuzzy, c-format +#, c-format msgid "%.3f seconds" -msgstr "שניה %i" +msgstr "%.3f שניות" #: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" -msgstr "" +msgstr "נתק" #: ../gtk/incall_view.c:476 msgid "Calling..." @@ -767,25 +758,23 @@ msgstr "שיחה הסתיימה." #: ../gtk/incall_view.c:778 msgid "Transfer in progress" -msgstr "" +msgstr "העברה מצויה כעת בעיצומה" #: ../gtk/incall_view.c:781 -#, fuzzy msgid "Transfer done." -msgstr "העברה" +msgstr "העברה הסתיימה." #: ../gtk/incall_view.c:784 -#, fuzzy msgid "Transfer failed." -msgstr "העברה" +msgstr "העברה נכשלה." #: ../gtk/incall_view.c:828 msgid "Resume" -msgstr "חזרה" +msgstr "חזור" #: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 msgid "Pause" -msgstr "השהיה" +msgstr "השהה" #: ../gtk/incall_view.c:900 #, c-format @@ -793,11 +782,12 @@ msgid "" "Recording into\n" "%s %s" msgstr "" +"מקליט אל תוך\n" +"%s %s" #: ../gtk/incall_view.c:900 -#, fuzzy msgid "(Paused)" -msgstr "השהיה" +msgstr "(מושהה)" #: ../gtk/loginframe.c:93 #, c-format @@ -808,32 +798,32 @@ msgstr "נא להזין מידע התחברות עבור %s" # זה ש: נתקשר או מתוקשר או הותקשר? #: ../gtk/main.ui.h:1 msgid "Callee name" -msgstr "שם המקבל" +msgstr "שם מקבל" +# שגר #: ../gtk/main.ui.h:2 msgid "Send" -msgstr "שיגור" +msgstr "שלח" #: ../gtk/main.ui.h:3 -#, fuzzy msgid "End conference" -msgstr "בשיחת ועידה" +msgstr "סיים ועידה" #: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" -msgstr "" +msgstr "הקלט את שיחה זו אל קובץ אודיו" #: ../gtk/main.ui.h:8 msgid "Video" -msgstr "" +msgstr "וידאו" #: ../gtk/main.ui.h:10 msgid "Mute" -msgstr "" +msgstr "השתק" #: ../gtk/main.ui.h:11 msgid "Transfer" -msgstr "העברה" +msgstr "העבר" #: ../gtk/main.ui.h:14 msgid "In call" @@ -853,7 +843,7 @@ msgstr "_אפשרויות" #: ../gtk/main.ui.h:18 msgid "Always start video" -msgstr "" +msgstr "התחל תמיד וידאו" #: ../gtk/main.ui.h:19 msgid "Enable self-view" @@ -885,7 +875,7 @@ msgstr "כתובת SIP או מספר טלפון" #: ../gtk/main.ui.h:26 msgid "Initiate a new call" -msgstr "התחלת שיחה חדשה" +msgstr "התחל שיחה חדשה" #: ../gtk/main.ui.h:27 msgid "Contacts" @@ -909,7 +899,7 @@ msgstr "הוסף אנשי קשר מן מדור" #: ../gtk/main.ui.h:32 msgid "Add contact" -msgstr "הוספת איש קשר" +msgstr "הוסף איש קשר" # קריאות אחרונות #: ../gtk/main.ui.h:33 @@ -969,7 +959,7 @@ msgstr "ברירת מחדל" #: ../gtk/main.ui.h:46 msgid "Delete" -msgstr "" +msgstr "מחק" #: ../gtk/about.ui.h:1 msgid "About linphone" @@ -1035,7 +1025,7 @@ msgstr "נא להזין את סיסמת המתחם" #: ../gtk/password.ui.h:3 msgid "UserID" -msgstr "זהות משתמש (‫UID)" +msgstr "מזהה משתמש" # קריאות #: ../gtk/call_logs.ui.h:1 @@ -1113,7 +1103,7 @@ msgstr "" #: ../gtk/parameters.ui.h:5 msgid "Audio codecs" -msgstr "קודקים של שמע" +msgstr "קודקים של אודיו" #: ../gtk/parameters.ui.h:6 msgid "Video codecs" @@ -1125,15 +1115,15 @@ msgstr "" #: ../gtk/parameters.ui.h:8 msgid "SIP (UDP)" -msgstr "" +msgstr "‏SIP ‏(UDP)" #: ../gtk/parameters.ui.h:9 msgid "SIP (TCP)" -msgstr "" +msgstr "‏SIP ‏(TCP)" #: ../gtk/parameters.ui.h:10 msgid "SIP (TLS)" -msgstr "" +msgstr "‏SIP ‏(TLS)" #: ../gtk/parameters.ui.h:11 msgid "Settings" @@ -1167,29 +1157,27 @@ msgstr "וידאו RTP/UDP:" #: ../gtk/parameters.ui.h:18 msgid "Audio RTP/UDP:" -msgstr "שמע RTP/UDP:" +msgstr "אודיו RTP/UDP:" #: ../gtk/parameters.ui.h:19 msgid "DSCP fields" -msgstr "" +msgstr "שדות DSCP" #: ../gtk/parameters.ui.h:20 msgid "Fixed" -msgstr "" +msgstr "מקובע" -# מנהרה #: ../gtk/parameters.ui.h:21 msgid "Tunnel" -msgstr "" +msgstr "מינהור" #: ../gtk/parameters.ui.h:22 -#, fuzzy msgid "Media encryption is mandatory" -msgstr "סוג הצפנת מדיה" +msgstr "הצפנת מדיה הינה מנדטורית" #: ../gtk/parameters.ui.h:23 msgid "Network protocol and ports" -msgstr "פרוטוקולי רשת עבודה ופורטים" +msgstr "פרוטוקולי רשת תקשורת ופורטים" #: ../gtk/parameters.ui.h:24 msgid "Direct connection to the Internet" @@ -1197,31 +1185,30 @@ msgstr "חיבור ישיר אל האינטרנט" #: ../gtk/parameters.ui.h:25 msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "מאחורי NAT \\ חומת־אש (ציון כתובת שער (Gateway IP) למטה)" +msgstr "מאחורי NAT / חומת אש (ציון כתובת שער (Gateway IP) למטה)" #: ../gtk/parameters.ui.h:26 msgid "Public IP address:" msgstr "כתובת IP פומבית:" +# ניצול STUN # שימוש ב־STUN # utilize #: ../gtk/parameters.ui.h:27 msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "מאחורי NAT \\ חומת־אש (ניצול STUN)" +msgstr "מאחורי NAT / חומת אש (בעזרת STUN לפתירה)" # שימוש ב־STUN # utilize #: ../gtk/parameters.ui.h:28 -#, fuzzy msgid "Behind NAT / Firewall (use ICE)" -msgstr "מאחורי NAT \\ חומת־אש (ניצול STUN)" +msgstr "מאחורי NAT / חומת אש (בעזרת ICE)" # שימוש ב־STUN # utilize #: ../gtk/parameters.ui.h:29 -#, fuzzy msgid "Behind NAT / Firewall (use uPnP)" -msgstr "מאחורי NAT \\ חומת־אש (ניצול STUN)" +msgstr "מאחורי NAT / חומת אש (בעזרת uPnP)" #: ../gtk/parameters.ui.h:30 msgid "Stun server:" @@ -1233,7 +1220,7 @@ msgstr "‫NAT וחומת אש" #: ../gtk/parameters.ui.h:32 msgid "Network settings" -msgstr "הגדרות רשת עבודה" +msgstr "הגדרות רשת תקשורת" #: ../gtk/parameters.ui.h:33 msgid "Ring sound:" @@ -1261,7 +1248,7 @@ msgstr "אפשר ביטול הד" #: ../gtk/parameters.ui.h:39 msgid "Audio" -msgstr "שמע" +msgstr "אודיו" #: ../gtk/parameters.ui.h:40 msgid "Video input device:" @@ -1342,12 +1329,12 @@ msgstr "קודקים" msgid "0 stands for \"unlimited\"" msgstr "0 מסמל \"בלי הגבלה\"" -# האם KiB means kibibyte? +# does KiB mean kibibyte? #: ../gtk/parameters.ui.h:61 msgid "Upload speed limit in Kbit/sec:" msgstr "מגבלת מהירות העלאה בקי״ב/שנ׳:" -# האם KiB means kibibyte? +# האם KiB זה kibibyte? # קי״ב (1024) אל מול ק״ב (1000) #: ../gtk/parameters.ui.h:62 msgid "Download speed limit in Kbit/sec:" @@ -1418,89 +1405,80 @@ msgid "Please wait" msgstr "נא להמתין" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy msgid "Dscp settings" -msgstr "הגדרות" +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 "Audio Media connectivity" -msgstr "סוג הצפנת מדיה" +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 "סוג הצפנת מדיה" +msgstr "קישוריות מדיום וידאו" #: ../gtk/call_statistics.ui.h:8 msgid "Round trip time" -msgstr "" +msgstr "זמן הלוך ושוב" #: ../gtk/call_statistics.ui.h:9 -#, fuzzy 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:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "הגדר http proxy (רשות)" #: ../gtk/keypad.ui.h:1 msgid "D" @@ -1520,15 +1498,15 @@ msgstr "" #: ../gtk/keypad.ui.h:6 msgid "9" -msgstr "9 (סעפ)" +msgstr "9 [סעפ]" #: ../gtk/keypad.ui.h:7 msgid "8" -msgstr "8 (צק)" +msgstr "8 [צק]" #: ../gtk/keypad.ui.h:8 msgid "7" -msgstr "7 (רשת)" +msgstr "7 [רשת]" #: ../gtk/keypad.ui.h:9 msgid "B" @@ -1536,15 +1514,15 @@ msgstr "" #: ../gtk/keypad.ui.h:10 msgid "6" -msgstr "6 (זחט)" +msgstr "6 [זחט]" #: ../gtk/keypad.ui.h:11 msgid "5" -msgstr "5 (יכל)" +msgstr "5 [יכל]" #: ../gtk/keypad.ui.h:12 msgid "4" -msgstr "4 (מנ)" +msgstr "4 [מנ]" #: ../gtk/keypad.ui.h:13 msgid "A" @@ -1552,11 +1530,11 @@ msgstr "" #: ../gtk/keypad.ui.h:14 msgid "3" -msgstr "3 (אבג)" +msgstr "3 [אבג]" #: ../gtk/keypad.ui.h:15 msgid "2" -msgstr "2 (דהו)" +msgstr "2 [דהו]" #: ../gtk/keypad.ui.h:16 msgid "1" @@ -1692,7 +1670,7 @@ msgstr "בדיקת STUN מצויה כעת בעיצומה..." #: ../coreapi/misc.c:630 msgid "ICE local candidates gathering in progress..." -msgstr "" +msgstr "צבירת מועמדים מקומיים של ICE מצויה כעת בעיצומה..." #: ../coreapi/friend.c:33 msgid "Online" @@ -1745,14 +1723,14 @@ msgstr "בהמתנה" #: ../coreapi/friend.c:66 msgid "Unknown-bug" -msgstr "תקלה לא ידועה" +msgstr "תקלה לא מוכרת" #: ../coreapi/proxy.c:204 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 @@ -1806,24 +1784,21 @@ msgstr "קריאה נענתה על ידי %s." # אי תאימות # אי התאמה #: ../coreapi/callbacks.c:412 -#, fuzzy msgid "Incompatible, check codecs or security settings..." -msgstr "חוסר תאימות, נא לבדוק קודקים..." +msgstr "חוסר תאימות, בדוק קודקים או הגדרות אבטחה..." #: ../coreapi/callbacks.c:460 -#, fuzzy msgid "We have been resumed." -msgstr "חזרנו..." +msgstr "חזרנו." #: ../coreapi/callbacks.c:469 msgid "We are paused by other party." -msgstr "" +msgstr "אנו מושהים על ידי צד אחר." # באופן מרוחק #: ../coreapi/callbacks.c:475 -#, fuzzy msgid "Call is updated by remote." -msgstr "שיחה עודכנה מרחוק..." +msgstr "שיחה עודכנה מרחוק." #: ../coreapi/callbacks.c:544 msgid "Call terminated." @@ -1862,9 +1837,8 @@ msgstr "מכוון מחדש" # אי תאימות # אי התאמה #: ../coreapi/callbacks.c:627 -#, fuzzy msgid "Incompatible media parameters." -msgstr "חוסר תאימות, נא לבדוק קודקים..." +msgstr "פרמטריי מדיה חסרי תואמים." #: ../coreapi/callbacks.c:633 msgid "Call failed." diff --git a/po/hu.po b/po/hu.po index 256e7ffba..65bbb3e7b 100644 --- a/po/hu.po +++ b/po/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2013-03-26 19:00+0100\n" "Last-Translator: Viktor \n" "Language-Team: \n" @@ -98,7 +98,7 @@ msgstr "én" msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Érvénytelen sip partner !" @@ -165,11 +165,11 @@ msgstr "" msgid "Call error" msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Beérkező hívás" @@ -1475,19 +1475,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "megszakítva" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "befejezve" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "elhibázva" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1502,70 +1502,70 @@ msgstr "" "Állapot: %s\n" "Időtartam: %i perc %i másodperc\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Kimenő hívás" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Kész" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Telefonszám-cél keresése..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Nem sikkerült értelmezni a számot." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" msgstr "" "Az adott szám nem értelmezhető. Egy sip cím általában így néz ki: user@domain" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Kapcsolódás" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Nem sikerült hívni" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Elnézést, elértük a egyidejű hívások maximális számát" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "kapcsolatba lépett veled." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "és automatikus választ kért." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "A hívási jellemzők módosítása..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Kapcsolódva." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Jelenlegi hívás várakoztatásának aktiválása..." @@ -1784,7 +1784,7 @@ msgstr "A regisztáció a %s -n nem sikerült: %s" msgid "Authentication token is %s" msgstr "Hitelesítési jel: %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/it.po b/po/it.po index f1c29e8b0..e7c8cfc13 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" "Last-Translator: Matteo Piazza \n" "Language-Team: it \n" @@ -98,7 +98,7 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Contatto SIP non valido" @@ -161,11 +161,11 @@ msgstr "Prego inserire la password per username %s e dominio %s" msgid "Call error" msgstr "Cronologia" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Chiamata terminata" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Chimata in entrata" @@ -1505,19 +1505,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "comletato" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "mancante" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1532,23 +1532,23 @@ msgstr "" "Stato: %s\n" "Durata: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Chiamata in uscita" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Pronto" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Ricerca numero destinazione..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Impossibile risolvere il numero." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1556,51 +1556,51 @@ msgstr "" "Errore nel formato del contatto sip. Usualmente un indirizzo appare sip:" "user@domain" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "In connessione" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "ti sta conttatando." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Connessione" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 #, fuzzy msgid "Could not pause the call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 #, fuzzy msgid "Pausing the current call..." msgstr "Mostra chiamata corrente" @@ -1822,7 +1822,7 @@ msgstr "Registrazione su %s fallita: %s" msgid "Authentication token is %s" msgstr "Linphone - Autenticazione richiesta" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/ja.po b/po/ja.po index 668018fd1..56362238b 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2003-01-21 00:05+9000\n" "Last-Translator: YAMAGUCHI YOSHIYA \n" "Language-Team: \n" @@ -96,7 +96,7 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "" @@ -156,12 +156,12 @@ msgstr "" msgid "Call error" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 #, fuzzy msgid "Call ended" msgstr "通話は拒否されました。" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "" @@ -1516,19 +1516,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1538,24 +1538,24 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 #, fuzzy msgid "Ready" msgstr "準備完了。" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "" -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 #, fuzzy msgid "" "Could not parse given sip address. A sip url usually looks like sip:" @@ -1564,51 +1564,51 @@ msgstr "" "SIPアドレスの形式エラーです。SIPアドレスは、のような" "形式です。" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 #, fuzzy msgid "Contacting" msgstr "接続中" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "から電話です。" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "接続しました。" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "通話はキャンセルされました。" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "" @@ -1832,7 +1832,7 @@ msgstr "登録しました。" msgid "Authentication token is %s" msgstr "コーデックの情報" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/nb_NO.po b/po/nb_NO.po index 8b7f20c28..470e0d024 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2011-04-05 01:56+0200\n" "Last-Translator: Øyvind Sæther \n" "Language-Team: Norwegian Bokmål \n" @@ -98,7 +98,7 @@ msgstr "Skru mikrofonen av" msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Ugyldig SIP kontakt !" @@ -166,11 +166,11 @@ msgstr "" msgid "Call error" msgstr "Samtalehistorikk" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Innkommende samtale" @@ -1498,19 +1498,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "avbrutt" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "Fullført" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "ubesvart" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1525,23 +1525,23 @@ msgstr "" "Status: %s\n" "Lengde: %i min %i sek\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Utgående samtale" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Klar" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Ser etter telefonnummer for destinasjonen..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Kan ikke tilkoble dette nummeret." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1549,47 +1549,47 @@ msgstr "" "Klarer ikke å tolke angitt SIP-adresse. En SIP-adresse er vanligvis ut som " "sip: brukernavn@domenenavn" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Tilknytter" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Kunne ikke ringe" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Beklager, du har nådd maksimalt antall samtidige samtaler" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "Kontakter deg." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " og ba om autosvar." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Endrer ringeparametre..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Tilkoblet" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" @@ -1810,7 +1810,7 @@ msgstr "Registrering hos %s mislykkes: %s" msgid "Authentication token is %s" msgstr "Autorisering kreves" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/nl.po b/po/nl.po index 8cfe7febd..fcd4ca42b 100644 --- a/po/nl.po +++ b/po/nl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: nl\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2007-09-05 10:40+0200\n" "Last-Translator: Hendrik-Jan Heins \n" "Language-Team: Nederlands \n" @@ -99,7 +99,7 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "" @@ -159,11 +159,11 @@ msgstr "" msgid "Call error" msgstr "Linphone - Oproepgeschiedenis" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Oproep beeindigd" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Inkomende oproep" @@ -1527,19 +1527,19 @@ msgstr "" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "voltooid" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "gemist" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1554,23 +1554,23 @@ msgstr "" "Status: %s\n" "Tijdsduur: %i mins %i secs\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Uitgaande oproep" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Gereed." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Zoekt de lokatie van het telefoonnummer..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Kon dit nummer niet vinden." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1578,51 +1578,51 @@ msgstr "" "Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" "gebruikersnaam@domeinnaam" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Verbinden" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "belt u." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Verbonden." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 #, fuzzy msgid "Could not pause the call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 #, fuzzy msgid "Pausing the current call..." msgstr "Kon niet oproepen" @@ -1848,7 +1848,7 @@ msgstr "Registratie op %s mislukt (time-out)." msgid "Authentication token is %s" msgstr "Authorisatie gegevens" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pl.po b/po/pl.po index 4512b7230..869f9b85e 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2003-08-22 12:50+0200\n" "Last-Translator: Robert Nasiadek \n" "Language-Team: Polski \n" @@ -94,7 +94,7 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "" @@ -154,12 +154,12 @@ msgstr "" msgid "Call error" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 #, fuzzy msgid "Call ended" msgstr "Rozmowa odrzucona." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "" @@ -1515,19 +1515,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1537,75 +1537,75 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 #, fuzzy msgid "Ready" msgstr "Gotowy." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "" -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 #, 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:2432 +#: ../coreapi/linphonecore.c:2453 #, fuzzy msgid "Contacting" msgstr "Dzwonie do " -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "dzwoni do Ciebie." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Połączony" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "Połączenie odwołane." -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "" @@ -1829,7 +1829,7 @@ msgstr "Rejestracja powiodła się." msgid "Authentication token is %s" msgstr "Informacje o kodeku" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/pt_BR.po b/po/pt_BR.po index 821ba910f..1ebd70a43 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-1.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2006-07-11 23:30+0200\n" "Last-Translator: Rafael Caesar Lenzi \n" "Language-Team: pt_BR \n" @@ -97,7 +97,7 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "" @@ -157,12 +157,12 @@ msgstr "" msgid "Call error" msgstr "Linphone - Histórico de chamadas" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 #, fuzzy msgid "Call ended" msgstr "Chamada cancelada." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Camadas recebidas" @@ -1520,19 +1520,19 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "Competado" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "Perdido" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, fuzzy, c-format msgid "" "%s at %s\n" @@ -1546,74 +1546,74 @@ msgstr "" "Status: %s\n" "Duração: %i min %i seg\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Chamadas efetuadas" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 #, fuzzy msgid "Ready" msgstr "Pronto." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Procurando por telefone de destino..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Não foi possível encontrar este número." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" msgstr "" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 #, fuzzy msgid "Contacting" msgstr "Contatando " -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "está chamado você." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "" @@ -1827,7 +1827,7 @@ msgstr "Registro falhou (tempo esgotado)." msgid "Authentication token is %s" msgstr "Informações de autenticação" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/ru.po b/po/ru.po index 66419e69a..0c81d472b 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2010-01-22 18:43+0300\n" "Last-Translator: Maxim Prokopyev \n" "Language-Team: Russian \n" @@ -105,7 +105,7 @@ msgstr "Я" msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Неверный sip-контакт!" @@ -174,11 +174,11 @@ msgstr "" msgid "Call error" msgstr "Ошибка вызова" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Разговор окончен" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Входящий вызов" @@ -1508,19 +1508,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "отмененный" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "завершённый" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "пропущенный" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1535,23 +1535,23 @@ msgstr "" "Статус: %s\n" "Длительность: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Исходящий звонок" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Готов" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Поиск адреса для телефонного номера..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Не могу найти этот номер." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1559,47 +1559,47 @@ msgstr "" "Не могу опознать sip адрес. SIP-URL обычно выглядит как sip:" "username@domainname" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Соединение" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Не удалось позвонить" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, мы превысили максимальное количество одновременных вызовов" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "пытается связаться с вами" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " и ответил автоответчик." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Изменение параметров вызова..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Соединён." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Вызов отменён" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Не удалось приостановить вызов" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Приостановление текущего вызова..." @@ -1823,7 +1823,7 @@ msgstr "Регистрация на %s не удалась: %s" msgid "Authentication token is %s" msgstr "Аутентификационный токен: %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/sr.po b/po/sr.po index 814b4d050..d0b470f95 100644 --- a/po/sr.po +++ b/po/sr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2013-02-11 19:03+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" @@ -106,7 +106,7 @@ msgstr "Ја" msgid "Couldn't find pixmap file: %s" msgstr "Не могу да пронађем датотеку сличице: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Неисправан сип контакт !" @@ -173,11 +173,11 @@ msgstr "" msgid "Call error" msgstr "Грешка позива" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Позив је завршен" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Долазни позив" @@ -1503,19 +1503,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "прекинути" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "завршени" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "пропуштени" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1530,23 +1530,23 @@ msgstr "" "Стање: %s\n" "Трајање: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Одлазни позив" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Спреман" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Тражим одредиште телефонског броја..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Не могу да решим овај број." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1554,47 +1554,47 @@ msgstr "" "Не могу да обрадим дату сип адресу. Сип адреса обично изгледа као „sip:" "корисник@домен“" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Ступам у везу" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "Не могу да позовем" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, достигли смо највећи број истовремених позива" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "вам се обраћа" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " и затражени само-одговор." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "Мењам параметре позива..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Повезан сам." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "Позив је прекинут" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "Не могу да зауставим позив" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "Заустављам тренутни позив..." @@ -1814,7 +1814,7 @@ msgstr "Уписивање на „%s“ није успело: %s" msgid "Authentication token is %s" msgstr "Симбол потврђивања идентитета је „%s“" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/sv.po b/po/sv.po index 4f7ec762c..c814f86c4 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2009-02-17 15:22+0100\n" "Last-Translator: Emmanuel Frécon \n" "Language-Team: SWEDISH \n" @@ -97,7 +97,7 @@ msgstr "Mikrofon av" msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "ogiltig SIP kontakt!" @@ -165,11 +165,11 @@ msgstr "" msgid "Call error" msgstr "Samtalshistorik" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "Inkommande samtal" @@ -1503,19 +1503,19 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "avslutade" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "missade" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1530,23 +1530,23 @@ msgstr "" "Status: %s\n" "Längd: %i min %i sek\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "Utgående samtal" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "Redo" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "Leta efter telefonnummer för destinationen..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "Kan inte nå dett nummer." -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1554,51 +1554,51 @@ msgstr "" "Kan inte förstå angiven SIP adress. En SIP adress vanligen ser ut som sip:" "användare@domänen" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "Kontaktar" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 #, fuzzy msgid "is contacting you" msgstr "kontaktar dig." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "Kopplad" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 #, fuzzy msgid "Could not pause the call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 #, fuzzy msgid "Pausing the current call..." msgstr "Nuvarande samtal" @@ -1821,7 +1821,7 @@ msgstr "Registrering hos %s mislyckades: %s" msgid "Authentication token is %s" msgstr "Linphone - Autentisering krävs" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/zh_CN.po b/po/zh_CN.po index 7c81df3fc..0d21351a8 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2011-01-08 23:51+0800\n" "Last-Translator: Aron Xu \n" "Language-Team: Chinese (simplified) \n" @@ -97,7 +97,7 @@ msgstr "静音" msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "无效的 SIP 联系人!" @@ -160,11 +160,11 @@ msgstr "请输入 %s@%s 的密码:" msgid "Call error" msgstr "呼叫历史" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "呼入" @@ -1514,19 +1514,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "完成" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "丢失" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1541,23 +1541,23 @@ msgstr "" "状态:%s\n" "状态:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "呼出" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "就绪" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "查询电话号码目的地..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "该号码无法解析。" -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" @@ -1565,50 +1565,50 @@ msgstr "" "无法解析给定的 SIP 地址,SIP 地址应有如下格式:\n" "sip:用户名@域名" -#: ../coreapi/linphonecore.c:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "联系中" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 #, fuzzy msgid "Could not call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "正在联系您" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr " 并询问了自动回答。" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "已连接。" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 #, fuzzy msgid "Call aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 #, fuzzy msgid "Could not pause the call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "" @@ -1823,7 +1823,7 @@ msgstr "注册到 %s 失败: %s" msgid "Authentication token is %s" msgstr "Linphone - 需要认证" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." diff --git a/po/zh_TW.po b/po/zh_TW.po index d1b2ce1a7..26a086150 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2013-04-24 14:04+0200\n" "PO-Revision-Date: 2011-04-06 21:24+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: \n" @@ -96,7 +96,7 @@ msgstr "靜音" msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "無效的 sip 連絡人!" @@ -162,11 +162,11 @@ msgstr "" msgid "Call error" msgstr "通話紀錄" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 msgid "Incoming call" msgstr "來電" @@ -1489,19 +1489,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../coreapi/linphonecore.c:228 msgid "aborted" msgstr "已放棄" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:231 msgid "completed" msgstr "已完成" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:234 msgid "missed" msgstr "未接" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:239 #, c-format msgid "" "%s at %s\n" @@ -1516,69 +1516,69 @@ msgstr "" "狀態:%s\n" "持續時間:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:240 msgid "Outgoing call" msgstr "去電" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1321 msgid "Ready" msgstr "準備就緒" -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:2205 msgid "Looking for telephone number destination..." msgstr "尋找電話號碼目的端..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2208 msgid "Could not resolve this number." msgstr "無法解析這個號碼。" -#: ../coreapi/linphonecore.c:2231 +#: ../coreapi/linphonecore.c:2252 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:2432 +#: ../coreapi/linphonecore.c:2453 msgid "Contacting" msgstr "正在連絡" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2460 msgid "Could not call" msgstr "無法通話" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2570 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "抱歉,我們已達瀏同步通話的最大數目" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2752 msgid "is contacting you" msgstr "正在連絡您" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid " and asked autoanswer." msgstr "並要求自動接聽。" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2753 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:2820 msgid "Modifying call parameters..." msgstr "修改通話參數..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3159 msgid "Connected." msgstr "已連線。" -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3187 msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3378 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3383 msgid "Pausing the current call..." msgstr "暫停目前的通話..." @@ -1795,7 +1795,7 @@ msgstr "在 %s 註冊失敗:%s" msgid "Authentication token is %s" msgstr "驗證失敗" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2355 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." From cf65a0f6f9c4667c305ecbef35171673c462270f Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Fri, 26 Apr 2013 12:24:38 +0200 Subject: [PATCH 300/909] hold_call disabled in conf set minimum size to contact list --- gtk/incall_view.c | 2 ++ gtk/main.ui | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 01e3b3cd9..5e13f2602 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -701,9 +701,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")); diff --git a/gtk/main.ui b/gtk/main.ui index 591b042ae..dde462ec3 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1118,7 +1118,7 @@ - + True True @@ -1231,7 +1231,7 @@ False - True + False From 1f4a7fd9f4b5a82141435b6fb811614846c9a181 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 26 Apr 2013 16:50:17 +0200 Subject: [PATCH 301/909] Fix debug flags for release (use NDEBUG instead of _DEBUG). --- build/vsx/LibLinphone/LibLinphone.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 71bf6912c..9ba14d251 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -91,7 +91,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default @@ -147,7 +147,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default From 313fbaa6481f7e7f04d3ab1a32635da3557f2529 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 28 Apr 2013 11:34:03 +0200 Subject: [PATCH 302/909] implement use_dates and dates in text messages. --- coreapi/bellesip_sal/sal_impl.c | 8 ++++++++ coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_call.c | 8 +------- coreapi/bellesip_sal/sal_op_message.c | 6 +++++- coreapi/bellesip_sal/sal_op_registration.c | 6 +++++- coreapi/callbacks.c | 1 + 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 5e1d197bf..c868854b6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -677,3 +677,11 @@ const char* sal_op_type_to_string(const SalOpType_t type) { return "SalOpUnknown"; } } + +void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ + ms_warning("sal_expire_old_registration_contacts not implemented "); +} + +void sal_use_dates(Sal *ctx, bool_t enabled){ + ctx->use_dates=enabled; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 487eb046a..a53afd4c8 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -42,6 +42,7 @@ struct Sal{ bool_t nat_helper_enabled; bool_t tls_verify; bool_t tls_verify_cn; + bool_t use_dates; }; typedef enum SalOpSate { diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2401df88c..d399b11d1 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -787,12 +787,6 @@ int sal_call_is_offerer(const SalOp *h){ return h->sdp_offering; } -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ - ms_warning("sal_expire_old_registration_contacts not implemented "); -} - -void sal_use_dates(Sal *ctx, bool_t enabled){ - ms_warning("sal_use_dates not implemented yet"); -} + diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index a1e8a3e54..96ce30d8b 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -87,6 +87,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_response_t* resp; belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); + belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); SalMessage salmsg; char message_id[256]={0}; int response_code=501; @@ -109,6 +110,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; salmsg.url=external_body?belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"):NULL; salmsg.message_id=message_id; + salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); op->base.root->callbacks.text_received(op,&salmsg); belle_sip_object_unref(address); belle_sip_free(from); @@ -124,10 +126,11 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ - /*FIXME impement time*/ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; + time_t curtime=time(NULL); + sal_op_message_fill_cbs(op); if (from) sal_op_set_from(op,from); @@ -138,6 +141,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); return sal_op_send_request(op,req); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 9fc43103f..2bda3266c 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -73,6 +73,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; belle_sip_uri_t* req_uri; + op->type=SalOpRegister; sal_op_set_from(op,from); sal_op_set_to(op,from); @@ -80,7 +81,10 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ 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))); + } return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7323573d4..b64500e0c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -967,6 +967,7 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ chat_msg->state=chatStatusSal2Linphone(status); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { + ms_message("Notifying text delivery with status %i",chat_msg->state); chat_msg->cb(chat_msg ,chat_msg->state ,chat_msg->cb_ud); From 86ba23e486fdeb6d99ba3ef3b86285cc191eb6d4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sun, 28 Apr 2013 15:05:57 +0200 Subject: [PATCH 303/909] fix ha1 issue and store ha1 instead of passwd --- coreapi/authentication.c | 13 +++++++++---- coreapi/bellesip_sal/sal_impl.c | 4 ++++ coreapi/callbacks.c | 1 + include/sal/sal.h | 1 + tester/liblinphone_tester.c | 2 ++ tester/register_tester.c | 16 ++++++++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 8ab1c21ff..1d0eaf15c 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -161,18 +161,22 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj==NULL || lp_config_get_int(config, "sip", "store_auth_info", 1) == 0){ return; - } + } + if (!obj->ha1 && obj->realm && obj->passwd && (obj->username||obj->userid)) { + /*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); @@ -308,6 +312,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) sai.userid=ai->userid; sai.realm=ai->realm; sai.password=ai->passwd; + sai.ha1=ai->ha1; sal_op_authenticate(op,&sai); ai->usecount++; } diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c868854b6..b0bf517ac 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -685,3 +685,7 @@ void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ 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); +} diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b64500e0c..10014ecae 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -896,6 +896,7 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { if (ai) { sai->userid=ai->userid?ai->userid:ai->username; sai->password=ai->passwd; + sai->ha1=ai->ha1; ai->usecount++; ai->last_use_time=ms_time(NULL); return TRUE; diff --git a/include/sal/sal.h b/include/sal/sal.h index f66413b8f..4bf2f415d 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -374,6 +374,7 @@ typedef struct SalCallbacks{ SalAuthInfo* sal_auth_info_new(); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); void sal_auth_info_delete(const SalAuthInfo* auth_info); +LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 6f7840a03..726296f09 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -92,6 +92,8 @@ LinphoneCore* create_lc_with_auth(unsigned int with_auth) { linphone_core_set_user_data(lc,&global_stat); /* until we have good certificates on our test server... */ linphone_core_verify_server_certificates(lc,FALSE); + /*to allow testing with 127.0.0.1*/ + linphone_core_set_network_reachable(lc,TRUE); return lc; } diff --git a/tester/register_tester.c b/tester/register_tester.c index 3522617bb..b58ee4e7b 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -199,6 +199,21 @@ static void simple_authenticated_register(){ CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } +static void ha1_authenticated_register(){ + stats* counters; + LinphoneCore* lc = create_lc(); + 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); /*create authentication structure from identity*/ + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh(lc,FALSE,auth_domain,route); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + static void authenticated_register_with_no_initial_credentials(){ LinphoneCoreVTable v_table; LinphoneCore* lc; @@ -345,6 +360,7 @@ test_t register_tests[] = { { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, { "TLS register", simple_tls_register }, { "Simple authenticated register", simple_authenticated_register }, + { "Ha1 authenticated register", ha1_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, { "Register with refresh", simple_register_with_refresh }, From cd14f216c0e9376bd8c7ec410e23ec8ac12ca05f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sun, 28 Apr 2013 15:48:29 +0200 Subject: [PATCH 304/909] make sure presence dialog ref op --- coreapi/bellesip_sal/sal_op_presence.c | 2 ++ mediastreamer2 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 390462ebf..5268c063a 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -493,9 +493,11 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=server_transaction; + if (!op->dialog) { 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)); } dialog_state=belle_sip_dialog_get_state(op->dialog); diff --git a/mediastreamer2 b/mediastreamer2 index 3acaa7372..2720ab1d1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3acaa7372423ffb0d18923e9e41e1076cec51905 +Subproject commit 2720ab1d1568ced6f0bf63e454a35f340d8ace64 From 0e9b41562fe6c6f3629be3a3c61d12a2ab07e11e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 28 Apr 2013 16:17:06 +0200 Subject: [PATCH 305/909] fix build. --- build/android/common.mk | 14 +++++------- build/android/lpc2xml.mk | 47 ---------------------------------------- build/android/xml2lpc.mk | 47 ---------------------------------------- 3 files changed, 6 insertions(+), 102 deletions(-) delete mode 100644 build/android/lpc2xml.mk delete mode 100644 build/android/xml2lpc.mk diff --git a/build/android/common.mk b/build/android/common.mk index 047d64b8c..06a773091 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -43,6 +43,7 @@ LOCAL_SRC_FILES := \ bellesip_sal/sal_op_message.c \ bellesip_sal/sal_op_presence.c \ bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_op_publish.c \ bellesip_sal/sal_sdp.c \ sal.c \ offeranswer.c \ @@ -98,12 +99,6 @@ LOCAL_STATIC_LIBRARIES := \ libbellesip \ libgsm -ifeq ($(BUILD_REMOTE_PROVISIONING),1) -LOCAL_STATIC_LIBRARIES += \ - libxml2lpc \ - liblpc2xml \ - liblpxml2 -endif ifeq ($(BUILD_TUNNEL),1) LOCAL_CFLAGS +=-DTUNNEL_ENABLED @@ -204,6 +199,7 @@ else LOCAL_STATIC_LIBRARIES += libsrtp-static endif endif + ifeq ($(BUILD_REMOTE_PROVISIONING),1) LOCAL_SRC_FILES += ../tools/xml2lpc.c \ ../tools/xml2lpc_jni.cc \ @@ -211,8 +207,10 @@ LOCAL_SRC_FILES += ../tools/xml2lpc.c \ ../tools/lpc2xml_jni.cc LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 -LOCAL_STATIC_LIBRARIES += libxml2 + $(LOCAL_PATH)/../../externals/build/libxml2 + +LOCAL_STATIC_LIBRARIES += liblpxml2 + endif LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) diff --git a/build/android/lpc2xml.mk b/build/android/lpc2xml.mk deleted file mode 100644 index d93be9b79..000000000 --- a/build/android/lpc2xml.mk +++ /dev/null @@ -1,47 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2013 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_PATH:= $(call my-dir)/../../tools - -include $(CLEAR_VARS) - -LOCAL_CPP_EXTENSION := .cc - -LOCAL_SRC_FILES := \ - lpc2xml.c \ - lpc2xml_jni.cc \ - -LOCAL_CFLAGS += -DIN_LINPHONE - -LOCAL_C_INCLUDES = \ - $(LOCAL_PATH)/../coreapi \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 \ - -LOCAL_SHARED_LIBRARIES = \ -# liblinphonenoneon \ -# liblinphone \ - -LOCAL_MODULE := liblpc2xml - -include $(BUILD_STATIC_LIBRARY) diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk deleted file mode 100644 index 55e4a03a0..000000000 --- a/build/android/xml2lpc.mk +++ /dev/null @@ -1,47 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2013 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_PATH:= $(call my-dir)/../../tools - -include $(CLEAR_VARS) - -LOCAL_CPP_EXTENSION := .cc - -LOCAL_SRC_FILES := \ - xml2lpc.c \ - xml2lpc_jni.cc \ - -LOCAL_CFLAGS += -DIN_LINPHONE - -LOCAL_C_INCLUDES = \ - $(LOCAL_PATH)/../coreapi \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 \ - -LOCAL_SHARED_LIBRARIES = \ -# liblinphonenoneon \ -# liblinphone \ - -LOCAL_MODULE := libxml2lpc - -include $(BUILD_STATIC_LIBRARY) From 8ad869352ccbc1f8149103c20153c056726463ae Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 28 Apr 2013 16:59:18 +0200 Subject: [PATCH 306/909] small tls fix --- coreapi/bellesip_sal/sal_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b0bf517ac..876d572e2 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -578,7 +578,7 @@ static void set_tls_properties(Sal *ctx){ 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); + if (ctx->root_ca) belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions); } } From 4f4546121f2b631187e0cd736a4ddd69ed414986 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 28 Apr 2013 17:01:26 +0200 Subject: [PATCH 307/909] update ms2 and ortp that were far behind --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2720ab1d1..3acaa7372 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2720ab1d1568ced6f0bf63e454a35f340d8ace64 +Subproject commit 3acaa7372423ffb0d18923e9e41e1076cec51905 diff --git a/oRTP b/oRTP index bd64df514..8cf1bea6d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit bd64df5148bdfd4a2ff5153927676fc497118279 +Subproject commit 8cf1bea6dfa66332cad995fc1c9f38b0b98d77c0 From 1098142ac18706c1cb65220415ab4debffce8dd3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 28 Apr 2013 21:59:46 +0200 Subject: [PATCH 308/909] better management of publish --- coreapi/proxy.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e655bf9d7..6bffff6de 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -251,6 +251,11 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ sal_unregister(obj->op); } } + if (obj->publish_op){ + /*we should certainly cancel our publish by some manner*/ + sal_op_release(obj->publish_op); + obj->publish_op=NULL; + } } void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) @@ -846,13 +851,14 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphoneOnlineStatus presence_mode){ int err; - SalOp *op=sal_op_new(proxy->lc->sal); - sal_op_set_route(op,proxy->reg_proxy); - err=sal_publish(op,linphone_proxy_config_get_identity(proxy), - linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode)); - if (proxy->publish_op!=NULL) - sal_op_release(proxy->publish_op); - proxy->publish_op=op; + + if (proxy->publish_op==NULL){ + proxy->publish_op=sal_op_new(proxy->lc->sal); + sal_op_set_route(proxy->publish_op,proxy->reg_proxy); + sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); + sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); + } + err=sal_publish(proxy->publish_op,NULL,NULL,linphone_online_status_to_sal(presence_mode)); return err; } From 22314280bb5a395fa60b013b965b9c9e6a94ca94 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 29 Apr 2013 13:42:04 +0200 Subject: [PATCH 309/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3acaa7372..89c644022 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3acaa7372423ffb0d18923e9e41e1076cec51905 +Subproject commit 89c644022b1dbf32be6afb08b0425bd4c788fc1b From 77892bd7207b073ba5823a69e0e8ddd54d57645a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 29 Apr 2013 17:04:11 +0200 Subject: [PATCH 310/909] Fix swapped soundcards and use voidsink. --- coreapi/ec-calibrator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 9bc7567d9..dbb6d857a 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -36,7 +36,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); @@ -50,7 +50,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); @@ -60,7 +60,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); From 24186bfffaac5153db6cac65ad963d53718a662b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 29 Apr 2013 17:04:11 +0200 Subject: [PATCH 311/909] Fix swapped soundcards and use voidsink. --- coreapi/ec-calibrator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 223fb087d..fa92b4992 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -36,7 +36,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); @@ -50,7 +50,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); @@ -60,7 +60,7 @@ static void ecc_init_filters(EcCalibrator *ecc){ 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); From b5addf958d8b8b6cd6f6682a82e87aa126c64324 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 30 Apr 2013 10:32:56 +0200 Subject: [PATCH 312/909] fix crash when receiving an incorrect SDP message in a 200Ok. fix indentation --- coreapi/callbacks.c | 3 ++- coreapi/sal_eXosip2_presence.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8a6ea631c..a6b49a0e8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -351,7 +351,8 @@ static void call_accepted(SalOp *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 (md) + call->params.has_video &= linphone_core_media_description_contains_video_stream(md); if (call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingRinging || diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index c81910986..b9f7b5763 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -85,19 +85,19 @@ static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; static void msg_add_current_date(osip_message_t *msg){ - char tmp[64]={0}; - time_t curtime=time(NULL); - struct tm *ret; + char tmp[64]={0}; + time_t curtime=time(NULL); + struct tm *ret; #ifndef WIN32 - struct tm gmt; - ret=gmtime_r(&curtime,&gmt); + struct tm gmt; + ret=gmtime_r(&curtime,&gmt); #else - ret=gmtime(&curtime); + ret=gmtime(&curtime); #endif - /*cannot use strftime because it is locale dependant*/ - snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", - days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); - osip_message_replace_header(msg,"Date",tmp); + /*cannot use strftime because it is locale dependant*/ + snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", + days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); + osip_message_replace_header(msg,"Date",tmp); } From efc4f86932c1410e6fde38af7dde6cf8415b1a98 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 30 Apr 2013 10:34:40 +0200 Subject: [PATCH 313/909] update ms2 and oRTP --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 89c644022..4ad5b7bec 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 89c644022b1dbf32be6afb08b0425bd4c788fc1b +Subproject commit 4ad5b7becb57b10775d024f89140c8c462c9de57 diff --git a/oRTP b/oRTP index bd64df514..8cf1bea6d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit bd64df5148bdfd4a2ff5153927676fc497118279 +Subproject commit 8cf1bea6dfa66332cad995fc1c9f38b0b98d77c0 From 476661a0fa9dad3272f1abfa5085361454a27e0e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 30 Apr 2013 12:17:24 +0200 Subject: [PATCH 314/909] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 8cf1bea6d..2d8a82247 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 8cf1bea6dfa66332cad995fc1c9f38b0b98d77c0 +Subproject commit 2d8a82247fbebbd690ae2fc8300522ab9b71a542 From a4bd90f12cd70ca43976f18155e48023a46c7eba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 30 Apr 2013 15:30:30 +0200 Subject: [PATCH 315/909] Update ms2 submodule for NEON detection fix. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4ad5b7bec..239be1a39 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4ad5b7becb57b10775d024f89140c8c462c9de57 +Subproject commit 239be1a39fa3f4ab460e8e7ab6d4d3d31e15e72a From 29a290f43b81a9d3b47f35ac4e3ec248a81a5279 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 2 May 2013 15:51:51 +0200 Subject: [PATCH 316/909] fix display of delivery notification --- coreapi/linphonecall.c | 2 +- gtk/chat.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b8971edd5..fa2c891f5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2481,7 +2481,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , #ifdef USE_BELLESIP ret=ctt; #else - ret=linphone_adress_as_string(ctt); + ret=linphone_address_as_string(ctt); #endif } else if (call->op && sal_op_get_contact(call->op)!=NULL){ /* if already choosed, don't change it */ diff --git a/gtk/chat.c b/gtk/chat.c index 2cba0754f..83538c848 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -168,7 +168,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, case LinphoneChatMessageStateInProgress: { g_hash_table_insert(table,(gpointer)msg,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending .. ",-1, + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1, "right","small","italic","font_grey","bg",NULL); g_object_set_data(G_OBJECT(w),"table",table); break; @@ -237,10 +237,10 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag 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: { @@ -249,16 +249,19 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag char buf[80]; strftime(buf,80,"%H:%M",tm); result=buf; + g_hash_table_remove(table,msg); break; } case LinphoneChatMessageStateNotDelivered: + { result="Message not sent"; + g_hash_table_remove(table,msg); break; + } default : result="Sending .."; } gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1, "right","small","italic","font_grey","bg",NULL); - g_hash_table_remove(table,msg); g_object_set_data(G_OBJECT(page),"table",table); } } From 3512728d0f366132b8ad4b6c8c615278240ef562 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 May 2013 17:14:04 +0200 Subject: [PATCH 317/909] Implement linphone_core_set_user_agent() for belle-sip. --- coreapi/bellesip_sal/sal_impl.c | 12 ++++++++---- coreapi/linphonecore.c | 11 +++++++++++ coreapi/sal_eXosip2.c | 4 ++++ include/sal/sal.h | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 876d572e2..b3877004d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -362,17 +362,14 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event } Sal * sal_init(){ - char stack_string[64]; belle_sip_listener_callbacks_t listener_callbacks; Sal * sal=ms_new0(Sal,1); sal->nat_helper_enabled=TRUE; - snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); #if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION) belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); #endif - - belle_sip_header_user_agent_add_product(sal->user_agent,stack_string); + sal_append_stack_string_to_user_agent(sal); belle_sip_object_ref(sal->user_agent); belle_sip_set_log_handler(_belle_sip_log); sal->stack = belle_sip_stack_new(NULL); @@ -502,6 +499,13 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){ belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent); return ; } + +void sal_append_stack_string_to_user_agent(Sal *ctx) { + char stack_string[64]; + snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string()); + belle_sip_header_user_agent_add_product(ctx->user_agent, stack_string); +} + /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value){ const belle_sip_list_t* iterator; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 043943dbe..3a866a364 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1782,8 +1782,10 @@ int linphone_core_get_sip_port(LinphoneCore *lc) return tr->udp_port>0 ? tr->udp_port : (tr->tcp_port > 0 ? tr->tcp_port : tr->tls_port); } +#if !USE_BELLE_SIP static char _ua_name[64]="Linphone"; static char _ua_version[64]=LINPHONE_VERSION; +#endif #if HAVE_EXOSIP_GET_VERSION && !USE_BELLESIP extern const char *eXosip_get_version(); @@ -1809,9 +1811,18 @@ static void apply_user_agent(LinphoneCore *lc){ * @ingroup misc **/ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){ +#if USE_BELLESIP + char ua_string[256]; + snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name, ver); + if (lc->sal) { + sal_set_user_agent(lc->sal, ua_string); + sal_append_stack_string_to_user_agent(lc->sal); + } +#else strncpy(_ua_name,name,sizeof(_ua_name)-1); strncpy(_ua_version,ver,sizeof(_ua_version)); apply_user_agent(lc); +#endif } const char *linphone_core_get_user_agent_name(void){ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 222e7c329..591e39d99 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -447,6 +447,10 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){ eXosip_set_user_agent(user_agent); } +void sal_append_stack_string_to_user_agent(Sal *ctx) { + /* Not implemented for eXosip */ +} + void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; } diff --git a/include/sal/sal.h b/include/sal/sal.h index 4bf2f415d..9b715eb63 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -383,6 +383,7 @@ void sal_set_dscp(Sal *ctx, int dscp); int sal_reset_transports(Sal *ctx); ortp_socket_t sal_get_socket(Sal *ctx); void sal_set_user_agent(Sal *ctx, const char *user_agent); +void sal_append_stack_string_to_user_agent(Sal *ctx); /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value); void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled); From dbaa0297ce32cf9e7cd66f9b2f9f8307e12549c7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 3 May 2013 14:36:21 +0200 Subject: [PATCH 318/909] fix bug when comparing event name (there can be parameters) --- coreapi/sal_eXosip2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 222e7c329..0c1b12445 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1653,7 +1653,7 @@ static void process_notify(Sal *sal, eXosip_event_t *ev){ //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){ + if (h->hvalue && strncasecmp(h->hvalue,"refer",strlen("refer"))==0){ /*special handling of refer events*/ if (body && body->body){ osip_message_t *msg; From 29350eaab14fa8692a75e1eeebc1f70d0d981abc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 3 May 2013 18:11:51 +0200 Subject: [PATCH 319/909] custom headers in progress --- coreapi/bellesip_sal/sal_impl.c | 66 +++++++++++++++++++++ coreapi/bellesip_sal/sal_impl.h | 3 + coreapi/bellesip_sal/sal_op_call.c | 7 ++- coreapi/bellesip_sal/sal_op_call_transfer.c | 51 ++++++++-------- coreapi/bellesip_sal/sal_sdp.c | 3 +- coreapi/sal.c | 55 ----------------- include/sal/sal.h | 5 -- 7 files changed, 99 insertions(+), 91 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b3877004d..55786af3b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -693,3 +693,69 @@ void sal_use_dates(Sal *ctx, bool_t enabled){ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) { return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } + + +SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ + belle_sip_message_t *msg=(belle_sip_message_t*)ch; + belle_sip_header_t *h; + char *tmp=ms_strdup_printf("%s: %s\r\n",name,value); + + if (msg==NULL){ + msg=(belle_sip_message_t*)belle_sip_request_new(); + } + h=BELLE_SIP_HEADER(belle_sip_header_extension_parse(tmp)); + ms_free(tmp); + if (h==NULL){ + belle_sip_error("Fail to parse extension header."); + return (SalCustomHeader*)msg; + } + belle_sip_message_add_header(msg,h); + return (SalCustomHeader*)msg; +} + +const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ + belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); + + if (h){ + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){ + return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h)); + }else{ + char *tmp=belle_sip_object_to_string((belle_sip_object_t*)h); + char *p=tmp+strlen(belle_sip_header_get_name(h))+1+1; /*header name + : + ' '*/ + char *ret=belle_sip_strdup(p); + belle_sip_free(tmp); + /*TODO: fix memory leak here*/ + + return ret; + } + } + return NULL; +} + +void sal_custom_header_free(SalCustomHeader *ch){ + belle_sip_object_unref((belle_sip_message_t*)ch); +} + +SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ + return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch); +} + +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; + } + if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); + b->custom_headers=ch; +} + + diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index a53afd4c8..70f3a45d4 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -89,6 +89,7 @@ struct SalOp{ SalOpType_t type; }; + 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); @@ -126,4 +127,6 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) ; void sal_add_pending_auth(Sal *sal, SalOp *op); void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status); + + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index d399b11d1..5b2c3c8e1 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -82,13 +82,14 @@ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* ses belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; int length; - char buff[1024]; + char buff[2048]; if (session_desc) { content_type = belle_sip_header_content_type_create("application","sdp"); length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff)); - if (length==sizeof(buff)) { + if (length>=sizeof(buff)) { ms_error("Buffer too small or sdp too big"); + return -1; } content_length= belle_sip_header_content_length_create(length); @@ -205,7 +206,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; - switch(dialog_state) { + switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 5afa9d8dc..4062bb30a 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -192,7 +192,6 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ } void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event){ - 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); const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); @@ -202,34 +201,32 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even ms_message("Receiving NOTIFY request on op [%p]",op); if (header_event - && strcasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"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)); + && strncasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"refer",strlen("refer"))==0 + && content_type + && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 + && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 + && body){ + belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); - if (sipfrag){ - - int code=belle_sip_response_get_status_code(sipfrag); - SalReferStatus status=SalReferFailed; - if (code==100){ - status=SalReferTrying; - }else if (code==200){ - status=SalReferSuccess; - }else if (code>=400){ - status=SalReferFailed; - } - belle_sip_object_unref(sipfrag); - resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); + if (sipfrag){ + int code=belle_sip_response_get_status_code(sipfrag); + SalReferStatus status=SalReferFailed; + if (code==100){ + status=SalReferTrying; + }else if (code==200){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = belle_sip_response_create_from_request(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 = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 1aa7f004c..1b75f4293 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -204,7 +204,8 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) ); - if ( !sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive ) ) { + if ( (!sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive )) + || desc->ice_ufrag[0] != '\0' ) { belle_sdp_session_description_set_connection ( session_desc ,belle_sdp_connection_create ( "IN",inet6 ? "IP6" :"IP4",desc->addr ) ); diff --git a/coreapi/sal.c b/coreapi/sal.c index fa7277261..407d0fc2e 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -487,61 +487,6 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info) { ms_free((void*)auth_info); } -SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ - SalCustomHeader *h=ms_new0(SalCustomHeader,1); - h->header_name=ms_strdup(name); - h->header_value=ms_strdup(value); - h->node.data=h; - return (SalCustomHeader*)ms_list_append_link((MSList*)ch,(MSList*)h); -} - -const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ - const MSList *it; - for (it=(const MSList*)ch;it!=NULL;it=it->next){ - const SalCustomHeader *itch=(const SalCustomHeader *)it; - if (strcasecmp(itch->header_name,name)==0) - return itch->header_value; - } - 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; -} - const char* sal_stream_type_to_string(SalStreamType type) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 9b715eb63..ecb6bb314 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -515,11 +515,6 @@ int sal_ping(SalOp *op, const char *from, const char *to); /*misc*/ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); -struct SalCustomHeader{ - MSList node; - char *header_name; - char *header_value; -}; 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); From 27d669254688a5f69d06c71f3d8e0976c240da6c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 4 May 2013 22:08:54 +0200 Subject: [PATCH 320/909] fix missing c=line in media description --- coreapi/bellesip_sal/sal_sdp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 1b75f4293..7125810fa 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -68,7 +68,7 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer)); } -static belle_sdp_media_description_t *stream_description_to_sdp ( const SalStreamDescription *stream ) { +static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMediaDescription *md, const SalStreamDescription *stream ) { belle_sdp_mime_parameter_t* mime_param; belle_sdp_media_description_t* media_desc; int j; @@ -105,6 +105,15 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalStrea belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param ); belle_sip_object_unref ( mime_param ); } + /*only add a c= line within the stream description if address are differents*/ + if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){ + bool_t inet6; + if (strchr(rtp_addr,':')!=NULL){ + inet6=TRUE; + }else inet6=FALSE; + belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr)); + } + if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); @@ -228,7 +237,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag)); for ( i=0; in_total_streams; i++ ) { - belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(&desc->streams[i])); + belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i])); } return session_desc; } From 8e124bc7f8dce5555d74c66bc60424678faa0b13 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 4 May 2013 22:43:14 +0200 Subject: [PATCH 321/909] fix ICE problem in belle-sip implementation --- coreapi/bellesip_sal/sal_sdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 7125810fa..7baf559dc 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -273,7 +273,6 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S int nb=0; SalStreamDir stream_dir=SalStreamSendRecv; const char* value; - int nb_ice_candidates=0; desc->n_active_streams = 0; desc->n_total_streams = 0; @@ -308,6 +307,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { + int nb_ice_candidates=0; media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); stream=&desc->streams[desc->n_total_streams]; media=belle_sdp_media_description_get_media ( media_desc ); @@ -328,7 +328,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S } stream->rtp_port=belle_sdp_media_get_media_port ( media ); - stream->rtcp_port = stream->rtp_port + 1; + if ( stream->rtp_port > 0 ) desc->n_active_streams++; From 156927cdae3747eb61577207a747bcdb0f4f78b7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 6 May 2013 22:09:31 +0200 Subject: [PATCH 322/909] important conference bugfixes --- coreapi/conference.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/coreapi/conference.c b/coreapi/conference.c index c9d51b151..0d8ea39a0 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -182,7 +182,6 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){ * @returns 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){ @@ -190,21 +189,25 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ 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*/ } 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 */ + 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)); @@ -231,13 +234,16 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a 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); From 59fa81ecd3c20a12c3d1b088f72b89534a46aa4c Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 7 May 2013 09:19:46 +0200 Subject: [PATCH 323/909] Update Czech translation Add patch for search in friendlist no case sensitive --- gtk/dscp_settings.ui | 2 +- gtk/friendlist.c | 6 +- po/cs.po | 346 ++++++++++++++++++++----------------------- 3 files changed, 166 insertions(+), 188 deletions(-) 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 8f73c2fcb..f7e683f95 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -513,7 +513,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; diff --git a/po/cs.po b/po/cs.po index 233eddbcf..4c1cb6503 100644 --- a/po/cs.po +++ b/po/cs.po @@ -2,12 +2,13 @@ # 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. +# Petr Pisar , 2006, 2007, 2008, 2009, 2010, 2011, 2013. # # XXX: Don't translate gtk-* messages. They will be replaced from GTK+ # catalogue. # # On hold → odložen +# chat → diskuze # Pause call → odložit hovor # Resume call → obnovit hovor # token → klíč @@ -15,10 +16,10 @@ # msgid "" msgstr "" -"Project-Id-Version: linphone-3.4.99.4\n" +"Project-Id-Version: linphone-3.5.99.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-24 14:04+0200\n" -"PO-Revision-Date: 2011-11-04 22:30+0100\n" +"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"PO-Revision-Date: 2013-05-01 09:55+0200\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" "Language: cs\n" @@ -38,49 +39,46 @@ msgid "Send text to %s" msgstr "Poslat text komu: %s" #: ../gtk/calllogs.c:223 -#, fuzzy, c-format +#, c-format msgid "Recent calls (%i)" -msgstr "Probíhá hovor" +msgstr "Nedávné hovory (%i)" #: ../gtk/calllogs.c:300 msgid "n/a" msgstr "–" #: ../gtk/calllogs.c:303 -#, fuzzy msgid "Aborted" -msgstr "přerušen" +msgstr "Přerušen" #: ../gtk/calllogs.c:306 -#, fuzzy msgid "Missed" -msgstr "promeškán" +msgstr "Zmeškán" #: ../gtk/calllogs.c:309 -#, fuzzy msgid "Declined" -msgstr "Odmítnout" +msgstr "Odmítnut" #: ../gtk/calllogs.c:315 #, c-format msgid "%i minute" msgid_plural "%i minutes" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%i minuta" +msgstr[1] "%i minuty" +msgstr[2] "%i minut" #: ../gtk/calllogs.c:318 #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%i sekunda" +msgstr[1] "%i sekundy" +msgstr[2] "%i sekund" #: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format msgid "%s\t%s" -msgstr "" +msgstr "%s\t%s" #: ../gtk/calllogs.c:323 #, c-format @@ -88,6 +86,8 @@ msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" +"%s\tKvalita: %s\n" +"%s\t%s\t" #: ../gtk/calllogs.c:329 #, c-format @@ -95,6 +95,8 @@ msgid "" "%s\t\n" "%s" msgstr "" +"%s\t\n" +"%s" #: ../gtk/conference.c:38 ../gtk/main.ui.h:13 msgid "Conference" @@ -109,7 +111,7 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 msgid "Invalid sip contact !" msgstr "Neplatný sipový kontakt!" @@ -123,7 +125,7 @@ msgstr "Soubor, kam zapisovat protokol." #: ../gtk/main.c:106 msgid "Start linphone with video disabled." -msgstr "" +msgstr "Spustí linphone se zakázaným obrazem." #: ../gtk/main.c:113 msgid "Start only in the system tray, do not show the main interface." @@ -176,11 +178,11 @@ msgstr "" msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 msgid "Incoming call" msgstr "Příchozí hovor" @@ -197,14 +199,14 @@ msgid "Call paused" msgstr "Hovor odložen" #: ../gtk/main.c:1142 -#, fuzzy, c-format +#, c-format msgid "by %s" -msgstr "Porty" +msgstr "kým: %s" #: ../gtk/main.c:1191 #, 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:1353 msgid "Website link" @@ -237,9 +239,8 @@ msgid "A free SIP video-phone" msgstr "Volný SIP videofon" #: ../gtk/friendlist.c:469 -#, fuzzy msgid "Add to addressbook" -msgstr "Zobrazit adresář" +msgstr "Přidat do adresáře" #: ../gtk/friendlist.c:643 msgid "Presence status" @@ -250,14 +251,12 @@ msgid "Name" msgstr "Jméno" #: ../gtk/friendlist.c:673 -#, fuzzy msgid "Call" -msgstr "Volat komu: %s" +msgstr "Zavolat" #: ../gtk/friendlist.c:678 -#, fuzzy msgid "Chat" -msgstr "Diskuzní skupina" +msgstr "Diskuze" #: ../gtk/friendlist.c:708 #, c-format @@ -275,9 +274,9 @@ msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" #: ../gtk/friendlist.c:926 -#, fuzzy, c-format +#, c-format msgid "Delete chat history of '%s'" -msgstr "Odstranit kontakt „%s“" +msgstr "Odstranit historii diskuze u kontaktu „%s“" #: ../gtk/friendlist.c:977 #, c-format @@ -378,20 +377,21 @@ msgstr "norština" #: ../gtk/propertybox.c:780 msgid "Hebrew" -msgstr "" +msgstr "hebrejština" #: ../gtk/propertybox.c:781 msgid "Serbian" -msgstr "" +msgstr "srbština" #: ../gtk/propertybox.c:848 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." +# Media encryption type: #: ../gtk/propertybox.c:934 msgid "None" -msgstr "Žádná" +msgstr "Žádné" #: ../gtk/propertybox.c:938 msgid "SRTP" @@ -451,23 +451,20 @@ msgstr "" "Tento průvodce vám pomůže používat sipový účet při vašich hovorech." #: ../gtk/setupwizard.c:43 -#, fuzzy 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:44 -#, fuzzy 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:45 -#, fuzzy 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:85 msgid "Enter your linphone.org username" -msgstr "" +msgstr "Zadejte uživatelské jméno na linphone.org" #: ../gtk/setupwizard.c:92 msgid "Username:" @@ -479,53 +476,52 @@ msgstr "Heslo:" #: ../gtk/setupwizard.c:114 msgid "Enter your account informations" -msgstr "" +msgstr "Zadejte údaje o vašem účtu" #: ../gtk/setupwizard.c:121 -#, fuzzy msgid "Username*" -msgstr "Uživatelské jméno" +msgstr "Uživatelské jméno*" #: ../gtk/setupwizard.c:122 -#, fuzzy msgid "Password*" -msgstr "Heslo" +msgstr "Heslo*" #: ../gtk/setupwizard.c:125 msgid "Domain*" -msgstr "" +msgstr "Doména*" #: ../gtk/setupwizard.c:126 msgid "Proxy" -msgstr "" +msgstr "Proxy" #: ../gtk/setupwizard.c:298 msgid "(*) Required fields" -msgstr "" +msgstr "(*) Povinné položky" #: ../gtk/setupwizard.c:299 -#, fuzzy msgid "Username: (*)" -msgstr "Uživatelské jméno:" +msgstr "Uživatelské jméno: (*)" #: ../gtk/setupwizard.c:301 -#, fuzzy msgid "Password: (*)" -msgstr "Heslo:" +msgstr "Heslo: (*)" #: ../gtk/setupwizard.c:303 msgid "Email: (*)" -msgstr "" +msgstr "E-mail: (*)" #: ../gtk/setupwizard.c:305 msgid "Confirm your password: (*)" -msgstr "" +msgstr "Potvrďte heslo: (*)" #: ../gtk/setupwizard.c:369 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:380 msgid "Thank you. Your account is now configured and ready for use." @@ -537,6 +533,9 @@ msgid "" "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:564 msgid "Welcome to the account setup assistant" @@ -547,31 +546,28 @@ msgid "Account setup assistant" msgstr "Průvodce nastavením účtu" #: ../gtk/setupwizard.c:575 -#, fuzzy msgid "Configure your account (step 1/1)" -msgstr "Nastavit SIP účet" +msgstr "Nastavit účet (krok 1/1)" #: ../gtk/setupwizard.c:580 msgid "Enter your sip username (step 1/1)" -msgstr "" +msgstr "Zadejte vaše sipové uživatelské jméno (krok 1/1)" #: ../gtk/setupwizard.c:584 msgid "Enter account information (step 1/2)" -msgstr "" +msgstr "Zadejte údaje o účtu (krok 1/2)" #: ../gtk/setupwizard.c:593 msgid "Validation (step 2/2)" -msgstr "" +msgstr "Ověření (krok 2/2)" #: ../gtk/setupwizard.c:598 -#, fuzzy msgid "Error" -msgstr "Chyba." +msgstr "Chyba" #: ../gtk/setupwizard.c:602 -#, fuzzy msgid "Terminating" -msgstr "Ukončit hovor" +msgstr "Ukončuje se" #: ../gtk/incall_view.c:70 ../gtk/incall_view.c:94 #, c-format @@ -584,62 +580,56 @@ msgid "Transfer to call #%i with %s" msgstr "Přepojit hovor č. %i s %s" #: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 -#, fuzzy msgid "Not used" -msgstr "Nenalezeno" +msgstr "Nepoužito" #: ../gtk/incall_view.c:220 msgid "ICE not activated" -msgstr "" +msgstr "ICE není zapnuto" #: ../gtk/incall_view.c:222 -#, fuzzy msgid "ICE failed" -msgstr "Filtr ICE" +msgstr "ICE selhalo" #: ../gtk/incall_view.c:224 msgid "ICE in progress" -msgstr "" +msgstr "Probíhá ICE" #: ../gtk/incall_view.c:226 msgid "Going through one or more NATs" -msgstr "" +msgstr "Prochází se jedním nebo více NATy" #: ../gtk/incall_view.c:228 -#, fuzzy msgid "Direct" -msgstr "Přesměrováno" +msgstr "Přímé" #: ../gtk/incall_view.c:230 msgid "Through a relay server" -msgstr "" +msgstr "Skrze relay server" #: ../gtk/incall_view.c:238 msgid "uPnP not activated" -msgstr "" +msgstr "UPnP není zapnuto" #: ../gtk/incall_view.c:240 -#, fuzzy msgid "uPnP in progress" -msgstr "Hledá se adresa pomocí STUN…" +msgstr "Probíhá UPnP" #: ../gtk/incall_view.c:242 -#, fuzzy msgid "uPnp not available" -msgstr "nedostupná" +msgstr "UPnP není nedostupné" #: ../gtk/incall_view.c:244 msgid "uPnP is running" -msgstr "" +msgstr "UPnP běží" #: ../gtk/incall_view.c:246 -#, fuzzy msgid "uPnP failed" -msgstr "Filtr ICE" +msgstr "UPnP selhalo" #: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 msgid "Direct or through server" -msgstr "" +msgstr "Přímé nebo skrze server" #: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 #, c-format @@ -647,15 +637,17 @@ msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" +"příchozí: %f\n" +"odchozí: %f (kb/s)" #: ../gtk/incall_view.c:286 #, c-format msgid "%.3f seconds" -msgstr "" +msgstr "%.3f sekund" #: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 msgid "Hang up" -msgstr "" +msgstr "Zavěsit" #: ../gtk/incall_view.c:476 msgid "Calling..." @@ -695,20 +687,20 @@ msgstr "nedostupná" #: ../gtk/incall_view.c:651 msgid "Secured by SRTP" -msgstr "" +msgstr "Zabezpečeno pomocí SRTP" #: ../gtk/incall_view.c:657 #, c-format msgid "Secured by ZRTP - [auth token: %s]" -msgstr "" +msgstr "Zabezpečeno pomocí ZRTP – [ověřovací klíč: %s]" #: ../gtk/incall_view.c:663 msgid "Set unverified" -msgstr "" +msgstr "Nastavit na neověřeno" #: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 msgid "Set verified" -msgstr "" +msgstr "Nastavit na ověřeno" #: ../gtk/incall_view.c:684 msgid "In conference" @@ -733,17 +725,15 @@ msgstr "Hovor skončil." #: ../gtk/incall_view.c:778 msgid "Transfer in progress" -msgstr "" +msgstr "Probíhá přepojení" #: ../gtk/incall_view.c:781 -#, fuzzy msgid "Transfer done." -msgstr "Přepojit" +msgstr "Přepojení dokončeno." #: ../gtk/incall_view.c:784 -#, fuzzy msgid "Transfer failed." -msgstr "Přepojit" +msgstr "Přepojení selhalo." #: ../gtk/incall_view.c:828 msgid "Resume" @@ -759,11 +749,12 @@ msgid "" "Recording into\n" "%s %s" msgstr "" +"Nahrává se do\n" +"%s %s" #: ../gtk/incall_view.c:900 -#, fuzzy msgid "(Paused)" -msgstr "Odložit" +msgstr "(Odloženo)" #: ../gtk/loginframe.c:93 #, c-format @@ -779,21 +770,20 @@ msgid "Send" msgstr "Odeslat" #: ../gtk/main.ui.h:3 -#, fuzzy msgid "End conference" -msgstr "Probíhá konference" +msgstr "Ukončit konferenci" #: ../gtk/main.ui.h:7 msgid "Record this call to an audio file" -msgstr "" +msgstr "Nahrát tento hovor do zvukového souboru" #: ../gtk/main.ui.h:8 msgid "Video" -msgstr "" +msgstr "Obraz" #: ../gtk/main.ui.h:10 msgid "Mute" -msgstr "" +msgstr "Ztišit" #: ../gtk/main.ui.h:11 msgid "Transfer" @@ -817,7 +807,7 @@ msgstr "V_olby" #: ../gtk/main.ui.h:18 msgid "Always start video" -msgstr "" +msgstr "Vždy spustit obraz" #: ../gtk/main.ui.h:19 msgid "Enable self-view" @@ -840,9 +830,8 @@ msgid "Check _Updates" msgstr "Vyhledat akt_ualizace" #: ../gtk/main.ui.h:24 -#, fuzzy msgid "Account assistant" -msgstr "Průvodce nastavením účtu" +msgstr "Průvodce účtem" #: ../gtk/main.ui.h:25 msgid "SIP address or phone number:" @@ -930,7 +919,7 @@ msgstr "Výchozí" #: ../gtk/main.ui.h:46 msgid "Delete" -msgstr "" +msgstr "Smazat" #: ../gtk/about.ui.h:1 msgid "About linphone" @@ -992,7 +981,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" @@ -1052,7 +1041,7 @@ msgstr "Registrační období (s):" #: ../gtk/sip_account.ui.h:9 msgid "Register" -msgstr "" +msgstr "Zaregistrovat se" #: ../gtk/sip_account.ui.h:10 msgid "Publish presence information" @@ -1136,20 +1125,20 @@ msgstr "Zvukový RTP/UDP:" #: ../gtk/parameters.ui.h:19 msgid "DSCP fields" -msgstr "" +msgstr "Položky DSCP" +# Port number #: ../gtk/parameters.ui.h:20 msgid "Fixed" -msgstr "" +msgstr "Stálý" #: ../gtk/parameters.ui.h:21 msgid "Tunnel" -msgstr "" +msgstr "Tunel" #: ../gtk/parameters.ui.h:22 -#, fuzzy msgid "Media encryption is mandatory" -msgstr "Druh šifrování médií" +msgstr "Šifrování médií je povinné" #: ../gtk/parameters.ui.h:23 msgid "Network protocol and ports" @@ -1172,14 +1161,12 @@ msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Za NAT/firewallem (adresu určí STUN)" #: ../gtk/parameters.ui.h:28 -#, fuzzy msgid "Behind NAT / Firewall (use ICE)" -msgstr "Za NAT/firewallem (adresu určí STUN)" +msgstr "Za NAT/firewallem (adresu určí ICE)" #: ../gtk/parameters.ui.h:29 -#, fuzzy msgid "Behind NAT / Firewall (use uPnP)" -msgstr "Za NAT/firewallem (adresu určí STUN)" +msgstr "Za NAT/firewallem (adresu určí UPnP)" #: ../gtk/parameters.ui.h:30 msgid "Stun server:" @@ -1259,7 +1246,7 @@ msgstr "Implicitní totožnost" #: ../gtk/parameters.ui.h:49 msgid "Wizard" -msgstr "" +msgstr "Průvodce" #: ../gtk/parameters.ui.h:52 msgid "Remove" @@ -1307,7 +1294,7 @@ msgstr "Omezení příchozí rychlosti (kb/s):" #: ../gtk/parameters.ui.h:63 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:64 msgid "" @@ -1366,91 +1353,80 @@ msgid "Please wait" msgstr "Prosím, čekejte" #: ../gtk/dscp_settings.ui.h:1 -#, fuzzy msgid "Dscp settings" -msgstr "Nastavení" +msgstr "Nastavení DSCP" #: ../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 "Audio Media connectivity" -msgstr "Druh šifrování médií" +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 "Druh šifrování médií" +msgstr "Obrazové spojení" #: ../gtk/call_statistics.ui.h:8 -#, fuzzy msgid "Round trip time" -msgstr "Vlastnosti zvuku" +msgstr "Odezva" #: ../gtk/call_statistics.ui.h:9 -#, fuzzy 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:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "Nastavit HTTP proxy (volitelné)" #: ../gtk/keypad.ui.h:1 msgid "D" @@ -1512,19 +1488,19 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../coreapi/linphonecore.c:227 msgid "aborted" msgstr "přerušen" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:230 msgid "completed" msgstr "dokončen" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:233 msgid "missed" msgstr "promeškán" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:238 #, c-format msgid "" "%s at %s\n" @@ -1539,70 +1515,70 @@ msgstr "" "Stav: %s\n" "Délka: %i min %i s\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:239 msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1312 msgid "Ready" msgstr "Připraven." -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:2184 msgid "Looking for telephone number destination..." msgstr "Vyhledává se umístění čísla…" -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2187 msgid "Could not resolve this number." msgstr "Toto číslo nelze vyhledat." -#: ../coreapi/linphonecore.c:2252 +#: ../coreapi/linphonecore.c:2231 msgid "" "Could not parse given sip address. A sip url usually looks like sip:" "user@domain" msgstr "" "Špatně zadaná SIP adresa. Adresa má mít tento formát " -#: ../coreapi/linphonecore.c:2453 +#: ../coreapi/linphonecore.c:2432 msgid "Contacting" -msgstr "Kontaktuji" +msgstr "Navazuje se spojení" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2439 msgid "Could not call" msgstr "Nelze volat" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2549 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:2752 +#: ../coreapi/linphonecore.c:2731 msgid "is contacting you" msgstr "vás volá" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2732 msgid " and asked autoanswer." msgstr " a požaduje automatickou zvednutí." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2732 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:2799 msgid "Modifying call parameters..." msgstr "Upravují se parametry hovoru…" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3138 msgid "Connected." msgstr "Připojeno." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3166 msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3357 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3362 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" @@ -1636,11 +1612,11 @@ msgstr "Hledá se adresa pomocí STUN…" #: ../coreapi/misc.c:630 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" @@ -1668,19 +1644,19 @@ 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" @@ -1691,7 +1667,7 @@ 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 @@ -1740,21 +1716,19 @@ msgstr "Hovor přijat kým: %s." #: ../coreapi/callbacks.c:412 msgid "Incompatible, check codecs or security settings..." -msgstr "" +msgstr "Není slučitelné. Zkontrolujte nastavení kodeků a zabezpečení…" #: ../coreapi/callbacks.c:460 -#, fuzzy msgid "We have been resumed." -msgstr "Byli jsme obnoveni…" +msgstr "Byli jsme obnoveni." #: ../coreapi/callbacks.c:469 msgid "We are paused by other party." -msgstr "" +msgstr "Byli jsme odloženi protistranou." #: ../coreapi/callbacks.c:475 -#, fuzzy msgid "Call is updated by remote." -msgstr "Hovor byl aktualizován protistranou…" +msgstr "Hovor byl aktualizován protistranou." #: ../coreapi/callbacks.c:544 msgid "Call terminated." @@ -1791,7 +1765,7 @@ msgstr "Přesměrováno" #: ../coreapi/callbacks.c:627 msgid "Incompatible media parameters." -msgstr "" +msgstr "Neslučitelné parametry médií." #: ../coreapi/callbacks.c:633 msgid "Call failed." @@ -1821,7 +1795,7 @@ msgstr "Registrace na %s selhala: %s" msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2319 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." From d0279bf40431585103e2fe10dd3cd151673936dc Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 7 May 2013 11:49:54 +0200 Subject: [PATCH 324/909] Fix bug report --- console/linphonec.c | 3 +++ coreapi/message_storage.c | 4 ++-- coreapi/sal_eXosip2.c | 1 + coreapi/sal_eXosip2_sdp.c | 2 +- gtk/incall_view.c | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index fca5a9b86..60c3c2af1 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -1400,6 +1400,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 +1409,8 @@ copy_file(const char *from, const char *to) { if ( ! fwrite(buf, 1, n, out) ) { + fclose(in); + fclose(out); return 0; } } diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 8ba642b68..deed140c7 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -204,13 +204,13 @@ void linphone_create_table(sqlite3* db){ void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; - char *errmsg=NULL; + const char *errmsg; sqlite3 *db; ret=sqlite3_open(lc->chat_db_file,&db); if(ret != SQLITE_OK) { + errmsg=sqlite3_errmsg(db); printf("Error in the opening: %s.\n", errmsg); sqlite3_close(db); - sqlite3_free(errmsg); } linphone_create_table(db); lc->db=db; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 0c1b12445..284773c9d 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1464,6 +1464,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ case 480: error=SalErrorFailure; sr=SalReasonTemporarilyUnavailable; + break; case 486: error=SalErrorFailure; sr=SalReasonBusy; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index debd8550f..54865aab6 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -547,7 +547,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ 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", + int nb = sscanf(attr->a_att_value, "%d %255s inline:%255s", &stream->crypto[valid_count].tag, tmp, tmp2); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 5e13f2602..da954a45b 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -741,11 +741,12 @@ 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); + if(callview==NULL) return; 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; + if (status==NULL) return; if (error_msg==NULL) gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); else{ From 18d21119955eb26d0491c076f1cb6bf5de3eaf34 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 7 May 2013 12:45:50 +0200 Subject: [PATCH 325/909] add tls certificates tester --- coreapi/bellesip_sal/sal_op_call.c | 7 ++-- tester/flexisip.conf | 2 +- tester/liblinphone_tester.c | 9 +++-- tester/multi_account_lrc | 2 +- tester/pauline_rc | 4 +-- tester/register_tester.c | 57 ++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 5b2c3c8e1..cd16356d1 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -358,15 +358,16 @@ static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { } 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 = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_server_transaction_t* server_transaction=NULL; belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; belle_sip_header_t* call_info; - if (server_transaction){ - belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/ + if (strcmp("ACK",belle_sip_request_get_method(req))!=0){ /*ACK does'nt create srv transaction*/ + server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_object_ref(server_transaction); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op); sal_op_ref(op); } diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 4a4715730..6093289ca 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -44,7 +44,7 @@ transports=sip:127.0.0.1:5060 sips:127.0.0.1:5061 # Default value: /etc/flexisip/tls #tls-certificates-dir=/etc/flexisip/tls #tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip -tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip +tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-sip-parser/linphone-private/tester/certificates ## ## STUN server parameters. diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 726296f09..1c9c767dc 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -108,13 +108,16 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c char filepath[256]; char ringpath[256]; char ringbackpath[256]; + char rootcapath[256]; sprintf(filepath, "%s/%s", path, file); lc = linphone_core_new(v_table,NULL,filepath,NULL); linphone_core_set_user_data(lc,&global_stat); counters = (stats*)linphone_core_get_user_data(lc); - /* until we have good certificates on our test server... */ - linphone_core_verify_server_certificates(lc,FALSE); + /* until we have good certificates on our test server... + linphone_core_verify_server_certificates(lc,FALSE);*/ + sprintf(rootcapath, "%s/certificates/cacert.pem", path); + linphone_core_set_root_ca(lc,rootcapath); sprintf(ringpath, "%s/%s", path, "oldphone.wav"); sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); @@ -122,7 +125,7 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c linphone_core_set_ringback(lc, ringbackpath); reset_counters(counters); - CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count); + /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ while (counters->number_of_LinphoneRegistrationOk Date: Tue, 7 May 2013 16:01:16 +0200 Subject: [PATCH 326/909] add custom header test fix memory leaks fix invalid reads --- NEWS | 5 +++ coreapi/bellesip_sal/sal_impl.c | 44 +++++++++---------------- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_call.c | 8 ++++- coreapi/bellesip_sal/sal_op_impl.c | 51 +++++++++++++++++++++++++--- coreapi/bellesip_sal/sal_sdp.c | 5 ++- coreapi/chat.c | 4 +-- coreapi/linphonecall.c | 5 ++- coreapi/sal.c | 6 ++-- include/sal/sal.h | 9 +++-- tester/call_tester.c | 53 +++++++++++++++++++++++++++--- 11 files changed, 143 insertions(+), 48 deletions(-) diff --git a/NEWS b/NEWS index 413970e6a..0fc65a86f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +linphone-3.7...?? + * multiple SIP transports simualtaneously now allowed + * IP dual stack: can use IPv6 and IPv4 simultaneously + * fully asynchronous behavior: no more lengthly DNS or connections + linphone-3.xxx -- * fix bug in zRTP support (upgrade required) * diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 55786af3b..367551c81 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -193,6 +193,8 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev 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)))); } + + sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); if (op->callbacks.process_request_event) { op->callbacks.process_request_event(op,event); } else { @@ -702,6 +704,7 @@ SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, if (msg==NULL){ msg=(belle_sip_message_t*)belle_sip_request_new(); + belle_sip_object_ref(msg); } h=BELLE_SIP_HEADER(belle_sip_header_extension_parse(tmp)); ms_free(tmp); @@ -714,19 +717,15 @@ SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, } const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ - belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); - - if (h){ - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){ - return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h)); - }else{ - char *tmp=belle_sip_object_to_string((belle_sip_object_t*)h); - char *p=tmp+strlen(belle_sip_header_get_name(h))+1+1; /*header name + : + ' '*/ - char *ret=belle_sip_strdup(p); - belle_sip_free(tmp); - /*TODO: fix memory leak here*/ - - return ret; + if (ch){ + belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); + + if (h){ + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){ + return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h)); + }else{ + return belle_sip_header_get_unparsed_value(h); + } } } return NULL; @@ -740,22 +739,11 @@ SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch); } -const SalCustomHeader *sal_op_get_custom_header(SalOp *op){ +const SalCustomHeader *sal_op_get_recv_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; - } - if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); - b->custom_headers=ch; + return b->recv_custom_headers; } + + diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 70f3a45d4..7e2eab0ef 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -128,5 +128,6 @@ void sal_add_pending_auth(Sal *sal, SalOp *op); void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status); +void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index cd16356d1..ae237acfa 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -102,7 +102,11 @@ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* ses } } static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ - return set_sdp(msg,media_description_to_sdp(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){ @@ -261,6 +265,7 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); @@ -571,6 +576,7 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon if (op->sdp_answer==NULL) sdp_process(op); if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); op->sdp_answer=NULL; } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 57e8149ee..981eed9b2 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -30,7 +30,9 @@ SalOp * sal_op_new(Sal *sal){ void sal_op_release(SalOp *op){ op->state=SalOpStateTerminated; sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/ - if (op->refresher) belle_sip_refresher_stop(op->refresher); + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + } sal_op_unref(op); } void sal_op_release_impl(SalOp *op){ @@ -42,6 +44,8 @@ void sal_op_release_impl(SalOp *op){ 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); @@ -146,6 +150,19 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { sal_op_send_request(op,request); } +static void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg){ + if (belle_sip_message_get_header(msg,belle_sip_header_get_name(h))==NULL) + belle_sip_message_add_header(msg,h); +} + +static void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ + if (op->base.sent_custom_headers){ + belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers; + belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); + belle_sip_list_for_each2(l,(void (*)(void *, void *))add_headers,msg); + belle_sip_list_free(l); + } +} static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request,bool_t add_contact) { belle_sip_client_transaction_t* client_transaction; @@ -153,6 +170,8 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req belle_sip_uri_t* outbound_proxy=NULL; belle_sip_header_contact_t* contact; + _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); + if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { /*don't put route header if dialog is in confirmed state*/ const MSList *elem=sal_op_get_route_addresses(op); @@ -316,10 +335,9 @@ void* sal_op_unref(SalOp* 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)) { - return -1; - } else { + 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); @@ -332,6 +350,7 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp return -1; } } + return -1; } const char* sal_op_state_to_string(const SalOpSate_t value) { @@ -344,3 +363,27 @@ const char* sal_op_state_to_string(const SalOpSate_t value) { return "Unknon"; } } + +/* + * 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; + } +} diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 7baf559dc..f610f2d3c 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -457,6 +457,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S 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]; @@ -464,7 +465,9 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S remote_candidate->port = candidate.port; } ptr += offset; - if (ptr[offset] == ' ') ptr += 1; + if (ptrice_ufrag, value, sizeof(stream->ice_ufrag)); diff --git a/coreapi/chat.c b/coreapi/chat.c index 54a15526b..5fa51c46d 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -97,7 +97,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM linphone_transfer_routes_to_op(routes,op); 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); + sal_op_set_sent_custom_header(op,msg->custom_headers); msg->custom_headers=NULL; /*transfered to the SalOp*/ } } @@ -186,7 +186,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->time=sal_msg->time; msg->state=LinphoneChatMessageStateDelivered; msg->is_read=FALSE; - ch=sal_op_get_custom_header(op); + ch=sal_op_get_recv_custom_header(op); if (ch) msg->custom_headers=sal_custom_header_clone(ch); if (sal_msg->url) { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index fa2c891f5..1d4c22a1c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -478,8 +478,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_core_get_local_ip(lc,NULL,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); - sal_op_set_custom_header(call->op,call->params.custom_headers); - call->params.custom_headers=NULL; + sal_op_set_sent_custom_header(call->op,call->params.custom_headers); if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); @@ -828,7 +827,7 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ cp->low_bandwidth=TRUE; } } - cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op); + cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op); return cp; } } diff --git a/coreapi/sal.c b/coreapi/sal.c index 407d0fc2e..e8619b319 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -461,8 +461,10 @@ void __sal_op_free(SalOp *op){ ms_list_for_each(b->route_addresses,(void (*)(void*)) sal_address_destroy); b->route_addresses=ms_list_free(b->route_addresses); } - if (b->custom_headers) - sal_custom_header_free(b->custom_headers); + 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); } diff --git a/include/sal/sal.h b/include/sal/sal.h index ecb6bb314..5274e02f9 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -249,7 +249,8 @@ typedef struct SalOpBase{ const char* call_id; char *remote_contact; SalAddress* service_route; /*as defined by rfc3608, might be a list*/ - SalCustomHeader *custom_headers; + SalCustomHeader *sent_custom_headers; + SalCustomHeader *recv_custom_headers; } SalOpBase; @@ -520,8 +521,10 @@ SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name); void sal_custom_header_free(SalCustomHeader *ch); SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch); -const SalCustomHeader *sal_op_get_custom_header(SalOp *op); -void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch); + +const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op); + +void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch); void sal_enable_logs(); void sal_disable_logs(); diff --git a/tester/call_tester.c b/tester/call_tester.c index bfb3dac2e..62683d2fa 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -92,14 +92,18 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { counters->number_of_IframeDecoded++; } -bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + + +bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params) { int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; - - - CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + if (!params){ + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + }else{ + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,params)); + } /*linphone_core_invite(caller_mgr->lc,"pauline");*/ @@ -141,6 +145,10 @@ bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { } +bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ + return call_with_params(caller_mgr,callee_mgr,NULL); +} + static void simple_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -190,6 +198,7 @@ static void simple_call(void) { 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(liblinphone_tester_file_prefix, "marie_rc"); @@ -417,6 +426,41 @@ static void call_with_ice(void) { linphone_core_manager_destroy(pauline); } +static void call_with_custom_headers(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + const LinphoneCallParams *remote_params; + const char *hvalue; + + params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_add_custom_header(params,"Weather","bad"); + linphone_call_params_add_custom_header(params,"Working","yes"); + + CU_ASSERT_TRUE(call_with_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + c1=linphone_core_get_current_call(marie->lc); + c2=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + remote_params=linphone_call_get_remote_params(c1); + hvalue=linphone_call_params_get_custom_header(remote_params,"Weather"); + CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_TRUE(strcmp(hvalue,"bad")==0); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_paused_resumed(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -773,6 +817,7 @@ test_t call_tests[] = { { "Simple call transfer", simple_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, { "Call with ICE", call_with_ice }, + { "Call with custom headers",call_with_custom_headers} }; test_suite_t call_test_suite = { From 25f44cc7c90bcde78f97d51f489e91f5094827f1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 May 2013 16:12:56 +0200 Subject: [PATCH 327/909] enable new tls test --- tester/register_tester.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tester/register_tester.c b/tester/register_tester.c index 36c3dc59f..95b30154d 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -358,34 +358,34 @@ static void tls_certificate_failure(){ LinphoneCoreVTable v_table; LinphoneCore* lc; stats stat; - stats* counters; + //stats* counters; char rootcapath[256]; memset (&v_table,0,sizeof(v_table)); reset_counters(&stat); v_table.registration_state_changed=registration_state_changed; lc = configure_lc_from(&v_table,liblinphone_tester_file_prefix, "pauline_rc", 0); linphone_core_set_user_data(lc,&stat); - counters = (stats*)linphone_core_get_user_data(lc); - sprintf(rootcapath, "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ + //counters = (stats*)linphone_core_get_user_data(lc); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ linphone_core_set_root_ca(lc,rootcapath); linphone_core_set_network_reachable(lc,TRUE); CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,1)); linphone_core_set_root_ca(lc,NULL); /*no root ca*/ linphone_core_refresh_registers(lc); CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,2)); - sprintf(rootcapath, "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ linphone_core_set_root_ca(lc,rootcapath); linphone_core_refresh_registers(lc); CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationOk,1)); CU_ASSERT_EQUAL(stat.number_of_LinphoneRegistrationFailed,2); linphone_core_destroy(lc); } -/* + static void tls_with_non_tls_server(){ LinphoneCoreVTable v_table; LinphoneCore* lc; stats stat; - stats* counters; + //stats* counters; LinphoneProxyConfig* proxy_cfg; LinphoneAddress* addr; @@ -395,7 +395,7 @@ static void tls_with_non_tls_server(){ v_table.registration_state_changed=registration_state_changed; lc = configure_lc_from(&v_table,liblinphone_tester_file_prefix, "marie_rc", 0); linphone_core_set_user_data(lc,&stat); - counters = (stats*)linphone_core_get_user_data(lc); + //counters = (stats*)linphone_core_get_user_data(lc); linphone_core_get_default_proxy(lc,&proxy_cfg); linphone_proxy_config_edit(proxy_cfg); addr=linphone_address_new(linphone_proxy_config_get_addr(proxy_cfg)); @@ -407,7 +407,7 @@ static void tls_with_non_tls_server(){ CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,1)); linphone_core_destroy(lc); -}*/ +} test_t register_tests[] = { { "Simple register", simple_register }, @@ -415,7 +415,7 @@ test_t register_tests[] = { { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, { "TLS register", simple_tls_register }, { "TLS certificate not verified",tls_certificate_failure}, -/* { "TLS with non tls server",tls_with_non_tls_server},*/ + { "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 }, From 22f396386aabdb60656a622a0d9b54b69d1699f3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 7 May 2013 19:09:24 +0200 Subject: [PATCH 328/909] add certificates --- tester/certificates/agent.pem | 36 ++++++++++++++++++++++++++++++++++ tester/certificates/cacert.pem | 20 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tester/certificates/agent.pem create mode 100644 tester/certificates/cacert.pem diff --git a/tester/certificates/agent.pem b/tester/certificates/agent.pem new file mode 100644 index 000000000..b2a0c5f19 --- /dev/null +++ b/tester/certificates/agent.pem @@ -0,0 +1,36 @@ +-----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----- +-----BEGIN CERTIFICATE----- +MIIDbTCCAtagAwIBAgIBADANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNDMwMTQzMTE3WhcN +MTQwNDMwMTQzMTE3WjCBvzELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3Rh +dGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQKDBlCZWxsZWRvbm5lIENvbW11 +bmljYXRpb25zMQwwCgYDVQQLDANMQUIxGjAYBgNVBAMMEXNpcDIubGlucGhvbmUu +b3JnMTowOAYJKoZIhvcNAQkBFitqZWhhbi5tb25uaWVyQGJlbGxlZG9ubmUtY29t +bXVuaWNhdGlvbnMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHZG78 +iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKtJJzhp5ysq4VH7q/dmOnM +nbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWVfgeSXstCK8m9SwxKqnqA +5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQABo3sweTAJBgNVHRMEAjAA +MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd +BgNVHQ4EFgQUMhkW8N0sNI/+El1P4AzuxQbIsYwwHwYDVR0jBBgwFoAUBl9dxxav +YvgtbnEDiKDWHSsEf7owDQYJKoZIhvcNAQEFBQADgYEAkzT/wjLRg4JXAZDZ1uVR +uAXrftoKrsvTysRU7Lr+N5W9FPoWqBh35Kx5SnRN3LYf0OIaJ5hufC8v+SOIJ6Me +QpKMlMY05Fz7R2aXkSS3Ie1GUJNKnWmos2uRFIMgIpFpr2VAZqVlsjC6J7SKIdGw +JvmtefxJrjl8Tpzw5uRNC58= +-----END CERTIFICATE----- diff --git a/tester/certificates/cacert.pem b/tester/certificates/cacert.pem new file mode 100644 index 000000000..2fd957d39 --- /dev/null +++ b/tester/certificates/cacert.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----- From 9ac3d64c8611a46c226b16eeac5b730c8d686fb8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 9 May 2013 18:04:11 +0200 Subject: [PATCH 329/909] - implement contact +sip.instance parameter, with random uuid generated and store in linphonerc - add user-agent string in response --- coreapi/bellesip_sal/sal_impl.c | 48 +++++++++++++++++++++ coreapi/bellesip_sal/sal_impl.h | 4 ++ coreapi/bellesip_sal/sal_op_call.c | 20 ++++----- coreapi/bellesip_sal/sal_op_call_transfer.c | 8 ++-- coreapi/bellesip_sal/sal_op_impl.c | 30 ++++++++++--- coreapi/bellesip_sal/sal_op_presence.c | 8 ++-- coreapi/bellesip_sal/sal_op_registration.c | 1 + coreapi/linphonecore.c | 11 +++++ coreapi/misc.c | 19 -------- coreapi/private.h | 1 + include/sal/sal.h | 2 + 11 files changed, 110 insertions(+), 42 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 367551c81..9bce7aee6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -744,6 +744,54 @@ const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){ return b->recv_custom_headers; } +void sal_set_uuid(Sal *sal, const char *uuid){ + if (sal->uuid){ + belle_sip_free(sal->uuid); + sal->uuid=NULL; + } + if (uuid) + sal->uuid=belle_sip_strdup(uuid); +} + +typedef struct { + unsigned int time_low; + unsigned short time_mid; + unsigned short time_hi_and_version; + unsigned char clock_seq_hi_and_reserved; + unsigned char clock_seq_low; + unsigned char node[6]; +} sal_uuid_t; +int sal_create_uuid(Sal*ctx, char *uuid, size_t len){ + sal_uuid_t uuid_struct; + int i; + int written; + + if (len==0) return -1; + /*create an UUID as described in RFC4122, 4.4 */ + belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t)); + uuid_struct.clock_seq_hi_and_reserved&=~(1<<6); + uuid_struct.clock_seq_hi_and_reserved|=1<<7; + uuid_struct.time_hi_and_version&=~(0xf<<12); + uuid_struct.time_hi_and_version|=4<<12; + + written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid, + uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved, + uuid_struct.clock_seq_low); + if (written>len+13){ + ms_error("sal_create_uuid(): buffer is too short !"); + return -1; + } + for (i = 0; i < 6; i++) + written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]); + uuid[len-1]='\0'; + sal_set_uuid(ctx,uuid); + return 0; +} +belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_request_t* req, int code ) { + belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); + return resp; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 7e2eab0ef..12f071740 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -37,6 +37,7 @@ struct Sal{ int session_expires; unsigned int keep_alive; char *root_ca; + char *uuid; bool_t one_matching_codec; bool_t use_tcp_tls_keep_alive; bool_t nat_helper_enabled; @@ -109,6 +110,7 @@ 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); void sal_process_authentication(SalOp *op); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; @@ -128,6 +130,8 @@ void sal_add_pending_auth(Sal *sal, SalOp *op); void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status); +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); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index ae237acfa..7dd98f2ce 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -339,7 +339,7 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ 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=belle_sip_response_create_from_request(request,status_code); + resp=sal_op_create_response_from_request(op,request,status_code); belle_sip_server_transaction_send_response(server_transaction,resp); return; @@ -419,7 +419,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t if(belle_sip_request_event_get_server_transaction(event)) { /*first answer 200 ok to cancel*/ belle_sip_server_transaction_send_response(server_transaction - ,belle_sip_response_create_from_request(req,200)); + ,sal_op_create_response_from_request(op,req,200)); /*terminate invite transaction*/ call_terminated(op ,op->pending_server_trans @@ -429,10 +429,10 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else { /*call leg does not exist*/ belle_sip_server_transaction_send_response(server_transaction - ,belle_sip_response_create_from_request(req,481)); + ,sal_op_create_response_from_request(op,req,481)); } } else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) { - resp=belle_sip_response_create_from_request(req,200); + resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else { belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); @@ -459,7 +459,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }*/ op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { - resp=belle_sip_response_create_from_request(req,200); + 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; @@ -486,14 +486,14 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->base.root->callbacks.vfu_request(op); } - resp=belle_sip_response_create_from_request(req,200); + resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { sal_op_process_refer(op,event); } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { sal_op_call_process_notify(op,event); } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { - resp=belle_sip_response_create_from_request(req,200); + resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); @@ -587,7 +587,7 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon 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 = belle_sip_response_create_from_request(req,status_code); + belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code); if (early_media){ handle_offer_answer_response(op,ringing_response); } @@ -618,7 +618,7 @@ int sal_call_accept(SalOp*h){ } /* sends a 200 OK */ - response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200); + response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200); if (response==NULL){ ms_error("Fail to build answer for call"); @@ -676,7 +676,7 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti ms_error("Unexpected decline reason [%i]",reason); /* no break */ } - response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); + response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); belle_sip_server_transaction_send_response(op->pending_server_trans,response); return 0; diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 4062bb30a..16f7500f3 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -179,13 +179,13 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ sal_op_set_referred_by(op,referred_by); } refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); - resp = belle_sip_response_create_from_request(req,202); + 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 = belle_sip_response_create_from_request(req,501); + resp = sal_op_create_response_from_request(op,req,501); belle_sip_server_transaction_send_response(server_transaction,resp); } @@ -219,13 +219,13 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even status=SalReferFailed; } belle_sip_object_unref(sipfrag); - resp = belle_sip_response_create_from_request(req,200); + 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 = belle_sip_response_create_from_request(req,501); + 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_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 981eed9b2..0aa6ce1b1 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -76,7 +76,9 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna *username=op->auth_info?op->auth_info->username:NULL; return 0; } -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) { + +/* +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op, belle_sip_header_from_t* from_header) { belle_sip_uri_t* req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)from_header)); belle_sip_header_contact_t* contact_header; if (sal_op_get_contact_address(op)) { @@ -89,6 +91,24 @@ belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_fro belle_sip_object_unref(req_uri); return contact_header; } +*/ + +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op, belle_sip_header_from_t* from_header){ + belle_sip_header_contact_t* contact_header; + 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 (op->base.root->uuid){ + if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ + char *instance_id=belle_sip_strdup_printf("\"\"",op->base.root->uuid); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); + belle_sip_free(instance_id); + } + } + return contact_header; +} belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_from_t* from_header; @@ -116,7 +136,9 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { 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){ @@ -133,7 +155,6 @@ void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { } } - 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); @@ -213,8 +234,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req if (add_contact) { contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 5268c063a..b325db9d7 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -548,7 +548,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques sub_state=SalSubscribeActive; op->base.root->callbacks.notify_presence(op,sub_state, estatus,NULL); - resp=belle_sip_response_create_from_request(req,200); + resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { /*either a refresh of an unsubscribe*/ @@ -556,7 +556,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op)); } else if(expires) { ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); - resp=belle_sip_response_create_from_request(req,200); + resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } } @@ -610,7 +610,7 @@ int sal_unsubscribe(SalOp *op){ 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 = belle_sip_response_create_from_request(req,200); + 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; @@ -624,7 +624,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); sal_add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*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))); + ,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_close(SalOp *op){ diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 2bda3266c..f40444e99 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -85,6 +85,7 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ time_t curtime=time(NULL); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); } + belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op,NULL)); return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3a866a364..6a687726e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1216,10 +1216,21 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const lc->vtable.global_state_changed(lc,gstate,message); } } + static void misc_config_read (LinphoneCore *lc) { LpConfig *config=lc->config; + const char *uuid; + lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15); lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS); + + uuid=lp_config_get_string(config,"misc","uuid",NULL); + if (!uuid){ + char tmp[64]; + sal_create_uuid(lc->sal,tmp,sizeof(tmp)); + lp_config_set_string(config,"misc","uuid",tmp); + }else + sal_set_uuid(lc->sal, uuid); } diff --git a/coreapi/misc.c b/coreapi/misc.c index cd62a522f..c5177cae9 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1151,26 +1151,7 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ return 0; } -#ifndef WIN32 -#include - - - -void _linphone_core_configure_resolver(){ -/*bionic declares _res but does not define nor export it !!*/ -#ifdef ANDROID - /*timeout and attempts are the same as retrans and retry, but are android specific names.*/ - setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1); -#else - res_init(); - _res.retrans=2; /*retransmit every two seconds*/ - _res.retry=2; /*only two times per DNS server*/ -#endif -} - -#else void _linphone_core_configure_resolver(){ } -#endif diff --git a/coreapi/private.h b/coreapi/private.h index 838ee69b0..611436f0b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -738,6 +738,7 @@ typedef enum _LinphoneToneID{ }LinphoneToneID; void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); +const char *linphone_core_create_uuid(LinphoneCore *lc); #ifdef __cplusplus } diff --git a/include/sal/sal.h b/include/sal/sal.h index 5274e02f9..719e42d44 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -407,6 +407,8 @@ void sal_set_root_ca(Sal* ctx, const char* rootCa); const char *sal_get_root_ca(Sal* ctx); void sal_verify_server_certificates(Sal *ctx, bool_t verify); void sal_verify_server_cn(Sal *ctx, bool_t verify); +void sal_set_uuid(Sal*ctx, const char *uuid); +int sal_create_uuid(Sal*ctx, char *uuid, size_t len); int sal_iterate(Sal *sal); MSList * sal_get_pending_auths(Sal *sal); From 75e6db7ab9ebea70621e3c3e0d7fa46f2d17fc33 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 9 May 2013 21:48:20 +0200 Subject: [PATCH 330/909] AAC-EL: fix SDP/fmtp content according to new recommendation from Fraunhofer --- coreapi/linphonecore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bb2b4a83c..12c8880b6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1285,8 +1285,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); - linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=24; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_handle_static_payloads(lc); ms_init(); From fd98c1e057368ca405f7c77aa1ad87a06c2d7956 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 10 May 2013 15:05:42 +0200 Subject: [PATCH 331/909] - do not register outside of tunnel when tunnel is activated but not yet connected. - move TUNNEL_ENABLED to config.h, which avoids recompilation issues with -D flags. --- configure.ac | 4 +- coreapi/TunnelManager.cc | 7 +- coreapi/TunnelManager.hh | 3 +- coreapi/linphone_tunnel.cc | 4 + coreapi/linphone_tunnel.h | 6 + coreapi/linphone_tunnel_stubs.c | 4 + coreapi/proxy.c | 411 ++++++++++++++++---------------- 7 files changed, 233 insertions(+), 206 deletions(-) diff --git a/configure.ac b/configure.ac index 7bc526bbb..5bd0570cc 100644 --- a/configure.ac +++ b/configure.ac @@ -656,9 +656,7 @@ AC_ARG_ENABLE(tunnel, 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) + AC_DEFINE(TUNNEL_ENABLED,1,[Tells tunnel extension is built-in]) fi AC_ARG_ENABLE(msg-storage, diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index d1020b1b2..409f9c42a 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -189,7 +189,7 @@ bool TunnelManager::isStarted() { } bool TunnelManager::isReady() const { - return mTunnelClient && mTunnelClient->isReady(); + return mTunnelClient && mTunnelClient->isReady() && mReady; } int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){ @@ -214,6 +214,7 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mEnabled(false) ,mTunnelClient(NULL) ,mAutoDetectStarted(false) +,mReady(false) ,mHttpProxyPort(0){ mExosipTransport.data=this; @@ -271,6 +272,7 @@ void TunnelManager::processTunnelEvent(const Event &ev){ if (lProxy) { linphone_proxy_config_done(lProxy); } + mReady=true; }else if (mEnabled && !mTunnelClient->isReady()){ /* we got disconnected from the tunnel */ if (lProxy && linphone_proxy_config_is_registered(lProxy)) { @@ -278,6 +280,7 @@ void TunnelManager::processTunnelEvent(const Event &ev){ linphone_proxy_config_edit(lProxy); linphone_core_iterate(mCore); } + mReady=false; } } @@ -317,7 +320,7 @@ void TunnelManager::enable(bool isEnable) { mEnabled=false; stopClient(); - + mReady=false; linphone_core_set_rtp_transport_factories(mCore,NULL); eXosip_transport_hook_register(NULL); diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index d4c1458fc..113f76786 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -129,6 +129,7 @@ class UdpMirrorClient; */ LinphoneCore *getLinphoneCore(); virtual void setHttpProxy(const char *host,int port, const char *username, const char *passwd); + virtual bool isReady() const; private: enum EventType{ UdpMirrorClientEvent, @@ -143,7 +144,6 @@ class UdpMirrorClient; }; 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); @@ -173,6 +173,7 @@ class UdpMirrorClient; Mutex mMutex; static Mutex sMutex; bool mAutoDetectStarted; + bool mReady; LinphoneRtpTransportFactories mTransportFactories; std::string mHttpUserName; std::string mHttpPasswd; diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index f0de56694..079074aa8 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -233,6 +233,10 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ return bcTunnel(tunnel)->isEnabled(); } +bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel){ + return bcTunnel(tunnel)->isReady(); +} + static OrtpLogFunc tunnelOrtpLogHandler=NULL; /* diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index e42a054dc..f02baab54 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -165,6 +165,12 @@ void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); **/ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); +/** + * @param tunnel object + * Returns a boolean indicating whether tunnel is connected successfully. +**/ +bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel); + /** * @param tunnel object * Forces reconnection to the tunnel server. diff --git a/coreapi/linphone_tunnel_stubs.c b/coreapi/linphone_tunnel_stubs.c index 0560b3956..0865704a0 100644 --- a/coreapi/linphone_tunnel_stubs.c +++ b/coreapi/linphone_tunnel_stubs.c @@ -59,6 +59,10 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){ return FALSE; } +bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel){ + return FALSE; +} + void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){ } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 42c21f01b..05258c1d1 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -413,7 +413,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 +422,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 +436,188 @@ 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" }, + {"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" }, {NULL ,NULL , "" , 0 , NULL } }; static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"}; @@ -1092,29 +1092,40 @@ 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){ + LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); + if (tunnel && linphone_tunnel_enabled(tunnel)){ + return linphone_tunnel_connected(tunnel); + }else{ + 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; + if (can_register(cfg)){ + linphone_proxy_config_register(cfg); + if (cfg->publish && cfg->publish_op==NULL){ + linphone_proxy_config_send_publish(cfg,lc->presence_mode); } -#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); + cfg->commit=FALSE; } - cfg->commit=FALSE; } } From 41d885bc208113a7c0c9513b77caff3e81c4074d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 10 May 2013 15:42:08 +0200 Subject: [PATCH 332/909] fix call without SDP add specific test for this case add missing EXTRA_DIST --- coreapi/bellesip_sal/sal_op_call.c | 6 ++++-- tester/Makefile.am | 2 ++ tester/call_tester.c | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 7dd98f2ce..28a46bd93 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -260,11 +260,10 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t 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(response),op->sdp_answer); + set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); belle_sip_object_unref(op->sdp_answer); op->sdp_answer=NULL; } @@ -558,6 +557,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ } + void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_io_error=call_process_io_error; op->callbacks.process_response_event=call_response_event; @@ -567,6 +567,7 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_dialog_terminated=process_dialog_terminated; op->type=SalOpCall; } + static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) { if (op->base.local_media){ /*this is the case where we received an invite without SDP*/ @@ -584,6 +585,7 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon 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)); diff --git a/tester/Makefile.am b/tester/Makefile.am index 24523893f..6b5e9edae 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,3 +1,5 @@ +EXTRA_DIST=pauline_rc laure_rc marie_rc marie_no_sdp_rc + if BUILD_CUNIT_TESTS diff --git a/tester/call_tester.c b/tester/call_tester.c index 62683d2fa..6c1f51137 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -384,6 +384,20 @@ static void call_terminated_by_caller(void) { linphone_core_manager_destroy(pauline); } +static void call_with_no_sdp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_no_sdp_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + + CU_ASSERT_TRUE(call(marie,pauline)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_with_ice(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -805,6 +819,7 @@ test_t call_tests[] = { { "Simple call compatibility mode", simple_call_compatibility_mode }, { "Early-media call", early_media_call }, { "Call terminated by caller", call_terminated_by_caller }, + { "Call without SDP", call_with_no_sdp}, { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, #ifdef SRTP_ENABLED From 98a440fe320bd0a910ded706a7e5462d2f634f0d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 13 May 2013 12:07:47 +0200 Subject: [PATCH 333/909] Fix wrong contact field in 200 OK response for an incoming call. --- coreapi/linphonecall.c | 13 +++++++++++++ coreapi/linphonecore.c | 9 --------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1d4c22a1c..1e9d9b048 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2530,6 +2530,19 @@ void linphone_call_set_contact_op(LinphoneCall* call) { #else LinphoneAddress *contact; #endif + LinphoneProxyConfig *cfg = NULL; + + 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 */ + linphone_core_get_default_proxy(call->core, &cfg); + call->dest_proxy = cfg; + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to, NULL); + 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)); + } + } + contact=get_fixed_contact(call->core,call,call->dest_proxy); if (contact){ sal_op_set_contact(call->op, contact); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c7743c0c7..27a6b8e10 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3129,7 +3129,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){ **/ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { - LinphoneProxyConfig *cfg=NULL; SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; @@ -3175,14 +3174,6 @@ 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,NULL); - - 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 */ linphone_call_set_contact_op(call); if (params){ From d25af961abd980e79e57f0b48140e16ad0379f44 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 13 May 2013 13:11:20 +0200 Subject: [PATCH 334/909] cosmetics --- coreapi/bellesip_sal/sal_op_registration.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index f40444e99..44bd98072 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -34,7 +34,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher sal_op_set_contact_address(op,(SalAddress*)contact_address); belle_sip_object_unref(contact_address); } - if(status_code ==200) { + 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; @@ -65,8 +65,6 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); } op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); - } else { - ms_warning("Register refresher know what to do with this status code"); } } @@ -95,6 +93,7 @@ int sal_register_refresh(SalOp *op, int expires){ else return -1; } + int sal_unregister(SalOp *op){ return sal_register_refresh(op,0); } From ac0afacabd40f2eb8fbbbb0544a0343a0809d475 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 13 May 2013 15:12:14 +0200 Subject: [PATCH 335/909] Remove useless arguement in linphone_core_upnp_available --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 12c8880b6..02db3b54f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4190,7 +4190,7 @@ 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 diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5ae73cc4d..67d4fb255 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1199,10 +1199,9 @@ 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. */ -bool_t linphone_core_upnp_available(const LinphoneCore *lc); +bool_t linphone_core_upnp_available(); /** * @ingroup network_parameters From 5e00dd3d9021b70cb55130fd7d0dc2f42a020160 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 14 May 2013 11:57:30 +0200 Subject: [PATCH 336/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 239be1a39..382f7d766 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 239be1a39fa3f4ab460e8e7ab6d4d3d31e15e72a +Subproject commit 382f7d766dcc2505a2bce2f2144d5f48103dfbd5 From b667078985283380522b6a1b8d6c7709396b635d Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 14 May 2013 12:03:41 +0200 Subject: [PATCH 337/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 382f7d766..3f06cd60f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 382f7d766dcc2505a2bce2f2144d5f48103dfbd5 +Subproject commit 3f06cd60f1864b8c811e0f4e4590991802ce5ea7 From 7354b123c1afe2f7a48fe4ccc7190ff272d3ada9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 14 May 2013 12:13:37 +0200 Subject: [PATCH 338/909] Renamed android libraries to avoid confusion --- build/android/Android-no-neon.mk | 8 ++++++- build/android/Android.mk | 3 +++ .../core/LinphoneCoreFactoryImpl.java | 24 +++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index d8e75ca0b..061a96217 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -35,7 +35,13 @@ endif LOCAL_MODULE := liblinphonenoneon ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_MODULE_FILENAME := liblinphonearmv5 +LOCAL_MODULE_FILENAME := liblinphonearmv5noneon +endif +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_MODULE_FILENAME := liblinphonearmv7noneon +endif +ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_MODULE_FILENAME := liblinphonex86noneon endif include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/Android.mk b/build/android/Android.mk index 10fba32dd..0dc0bd041 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -34,6 +34,9 @@ LOCAL_SHARED_LIBRARIES += \ endif LOCAL_MODULE := liblinphone +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_MODULE_FILENAME := liblinphonearmv7 +endif include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 0b799f33e..1d14ceb14 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -71,20 +71,20 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("bcg729"); //Main library - if (!hasNeonInCpuFeatures()) { - 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"); + if (isArmv7()) { + if (hasNeonInCpuFeatures()) { + Log.d("linphone", "armv7 liblinphone loaded"); + System.loadLibrary("linphonearmv7"); + } else { + Log.w("linphone", "No-neon armv7 liblinphone loaded"); + System.loadLibrary("linphonearmv7noneon"); } + } else if (Version.isX86()) { + Log.d("linphone", "No-neon x86 liblinphone loaded"); + System.loadLibrary("linphonex86noneon"); } else { - System.loadLibrary("linphone"); + Log.d("linphone", "No-neon armv5 liblinphone loaded"); + System.loadLibrary("linphonearmv5noneon"); } Version.dumpCapabilities(); From c98fa12a3eb6132861284eca29703d0390851307 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 14 May 2013 21:34:14 +0200 Subject: [PATCH 339/909] implement sal_op_get_remote_contact() --- coreapi/bellesip_sal/sal_op_impl.c | 6 ++++++ coreapi/sal.c | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 0aa6ce1b1..a18037ba8 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -407,3 +407,9 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ op->base.recv_custom_headers=(SalCustomHeader*)incoming; } } + +const char *sal_op_get_remote_contact(const SalOp *op){ + return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); +} + + diff --git a/coreapi/sal.c b/coreapi/sal.c index e8619b319..d47c5d2fa 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -345,11 +345,6 @@ const SalAddress *sal_op_get_to_address(const SalOp *op){ return ((SalOpBase*)op)->to_address; } - -const char *sal_op_get_remote_contact(const SalOp *op){ - return ((SalOpBase*)op)->remote_contact; -} - 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"); From 8cd22d90631dfece2f797dc2dc1cc5e0bb40b6bd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 14 May 2013 21:39:17 +0200 Subject: [PATCH 340/909] add missing rc file --- tester/marie_no_sdp_rc | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tester/marie_no_sdp_rc diff --git a/tester/marie_no_sdp_rc b/tester/marie_no_sdp_rc new file mode 100644 index 000000000..a3733dd83 --- /dev/null +++ b/tester/marie_no_sdp_rc @@ -0,0 +1,48 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +sdp_200_ack=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG From 5149fe14f02a971943ecaa74e56c09da32578cb7 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 15 May 2013 10:46:15 +0200 Subject: [PATCH 341/909] Remove core argument in upnp_available in jni --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 02ac62c7a..5619993ab 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2491,7 +2491,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) { From 05f3feddeb898d46ffecd15366ac8d386f5ffc1c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 15 May 2013 10:50:30 +0200 Subject: [PATCH 342/909] Renamed liblinphonex86noneon to liblinphonex86 --- build/android/Android-no-neon.mk | 2 +- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 061a96217..39818fbf4 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -41,7 +41,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_MODULE_FILENAME := liblinphonearmv7noneon endif ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_MODULE_FILENAME := liblinphonex86noneon +LOCAL_MODULE_FILENAME := liblinphonex86 endif include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 1d14ceb14..8cedba445 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -81,7 +81,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } } else if (Version.isX86()) { Log.d("linphone", "No-neon x86 liblinphone loaded"); - System.loadLibrary("linphonex86noneon"); + System.loadLibrary("linphonex86"); } else { Log.d("linphone", "No-neon armv5 liblinphone loaded"); System.loadLibrary("linphonearmv5noneon"); From aae5ae888c24542bda99ecdef882f0fa0f607670 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 May 2013 10:53:34 +0200 Subject: [PATCH 343/909] improve custom header so that they work with responses too --- coreapi/bellesip_sal/sal_impl.c | 2 ++ coreapi/bellesip_sal/sal_op_impl.c | 2 ++ coreapi/linphonecall.c | 4 ++-- tester/call_tester.c | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 9bce7aee6..a241f1692 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -233,6 +233,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (!op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); } + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); + if (op->callbacks.process_response_event) { if (op->base.root->nat_helper_enabled) { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a18037ba8..a7f8b796a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -27,6 +27,7 @@ SalOp * sal_op_new(Sal *sal){ sal_op_ref(op); return op; } + void sal_op_release(SalOp *op){ op->state=SalOpStateTerminated; sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/ @@ -35,6 +36,7 @@ void sal_op_release(SalOp *op){ } 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); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1e9d9b048..5735cb777 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -827,9 +827,9 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ cp->low_bandwidth=TRUE; } } - cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op); - return cp; } + cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op); + return cp; } return NULL; } diff --git a/tester/call_tester.c b/tester/call_tester.c index 6c1f51137..4b74cabe8 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -466,6 +466,8 @@ static void call_with_custom_headers(void) { CU_ASSERT_PTR_NOT_NULL(hvalue); CU_ASSERT_TRUE(strcmp(hvalue,"bad")==0); + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_remote_contact(c1)); + /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); From 9448260574f221fbfe50008935d2c093adefb123 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 15 May 2013 08:42:24 +0200 Subject: [PATCH 344/909] fix wrong passwd use case --- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_registration.c | 21 ++++++++++++++++----- coreapi/callbacks.c | 8 +++++++- tester/register_tester.c | 22 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 12f071740..1aa33c953 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -127,7 +127,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even /*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(belle_sip_message_t *notify, SalPresenceStatus online_status); belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_request_t *req, int code); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 44bd98072..46f1b91e2 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -34,6 +34,11 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher sal_op_set_contact_address(op,(SalAddress*)contact_address); belle_sip_object_unref(contact_address); } + if (belle_sip_refresher_get_auth_events(refresher)) { + if (op->auth_info) sal_auth_info_delete(op->auth_info); + /*only take first one for now*/ + op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); + } if(status_code == 200) { /*check service route rfc3608*/ belle_sip_header_service_route_t* service_route; @@ -43,6 +48,9 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher } 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 (op->auth_info) op->base.root->callbacks.auth_success(op,op->auth_info->realm,op->auth_info->username); op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0); } else if (status_code>=400) { /* from rfc3608, 6.1. @@ -57,14 +65,17 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher sal_op_set_service_route(op,NULL); sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); - if (belle_sip_refresher_get_auth_events(refresher) && (status_code == 401 || status_code==407)) { + if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); - 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)); + op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); + if (status_code == 403) { /*in sase of 401 or 407, auth requested already invoked previouly*/ + /*auth previouly pending, probably wrong pasword, give a chance to authenticate again*/ + op->base.root->callbacks.auth_requested(op->base.root,op->auth_info); + } } - op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); + } else { + ms_warning("Register refresher know what to do with this status code"); } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index fa0ed87a1..778ee8ce7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -894,7 +894,13 @@ static void ping_reply(SalOp *op){ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); - if (ai) { + if (ai && ai->works==FALSE && ai->usecount>=1){ + /*Better is to stop (implemeted below in else statement), and retry later*/ + if (ms_time(NULL)-ai->last_use_time>30){ + ai->usecount=0; /*so that we can allow to retry */ + } + } + if (ai && (ai->works || ai->usecount<1)){ sai->userid=ai->userid?ai->userid:ai->username; sai->password=ai->passwd; sai->ha1=ai->ha1; diff --git a/tester/register_tester.c b/tester/register_tester.c index 95b30154d..c1b3e6230 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -260,6 +260,27 @@ static void authenticated_register_with_late_credentials(){ linphone_core_destroy(lc); } +static void authenticated_register_with_wrong_credentials(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + v_table.auth_info_requested=auth_info_requested2; + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + linphone_core_set_user_data(lc,&stat); + linphone_core_add_auth_info(lc,info); /*add wrong authentication info to LinphoneCore*/ + counters = (stats*)linphone_core_get_user_data(lc); + register_with_refresh_base_2(lc,TRUE,auth_domain,route,TRUE,transport); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_destroy(lc); +} + static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { return configure_lc_from(v_table, liblinphone_tester_file_prefix, "multi_account_lrc", 3); } @@ -419,6 +440,7 @@ test_t register_tests[] = { { "Simple authenticated register", simple_authenticated_register }, { "Ha1 authenticated register", ha1_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, + { "Digest auth with wrong credentials", authenticated_register_with_wrong_credentials }, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, { "Register with refresh", simple_register_with_refresh }, { "Authenticated register with refresh", simple_auth_register_with_refresh }, From 01f68a128b23706bfb51e210b55a22e2e1f5e585 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 15 May 2013 12:38:22 +0200 Subject: [PATCH 345/909] add tester for ssl handcheck timout --- coreapi/linphonecore.c | 1 + tester/register_tester.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 27a6b8e10..20dbeccdf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5215,6 +5215,7 @@ void sip_config_uninit(LinphoneCore *lc) lc->auth_info=NULL; sal_reset_transports(lc->sal); + sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ sal_iterate(lc->sal); /*make sure event are purged*/ sal_uninit(lc->sal); lc->sal=NULL; diff --git a/tester/register_tester.c b/tester/register_tester.c index c1b3e6230..d079a3930 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -421,7 +421,7 @@ static void tls_with_non_tls_server(){ 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_int(addr)); + ,(linphone_address_get_port_int(addr)>0?linphone_address_get_port_int(addr):5060)); linphone_proxy_config_set_server_addr(proxy_cfg,tmp); linphone_proxy_config_done(proxy_cfg); linphone_address_destroy(addr); From d084f4bd7af90d24f2785b8fab5b66ae3a0b3ad4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Nov 2012 16:12:35 +0100 Subject: [PATCH 346/909] Add opus codec. --- coreapi/linphonecore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 02db3b54f..186f6f976 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -825,6 +825,7 @@ typedef struct codec_desc{ }codec_desc_t; static codec_desc_t codec_pref_order[]={ + {"opus", 48000}, {"SILK", 16000}, {"speex", 16000}, {"speex", 8000}, @@ -1287,6 +1288,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_opus,-1,NULL); linphone_core_handle_static_payloads(lc); ms_init(); From 3dcb6fd44b4f2b79a2848a35915e6c785d641277 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 May 2013 14:30:41 +0200 Subject: [PATCH 347/909] improve notifications of incoming chat messages - star appears even if already in the good chat tab - contact with active chats are displayed first in the friend list - activate icon pumping on Mac OS --- gtk/chat.c | 28 ++++++++++------------------ gtk/friendlist.c | 8 ++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 2cba0754f..a58f443d6 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -66,6 +66,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); 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); from=g_object_get_data(G_OBJECT(w),"from_message"); @@ -364,7 +365,6 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.blue = 61952; with_str=linphone_address_as_string_uri_only(with); - linphone_chat_room_mark_as_read(cr); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text),FALSE); @@ -404,8 +404,9 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres } 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; + char *tmp=linphone_address_as_string(with); + LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp); + ms_free(tmp); return cr; } @@ -424,7 +425,6 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, GtkTextIter end; GtkTextBuffer *text_buffer; - linphone_chat_room_mark_as_read(cr); 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); @@ -434,6 +434,8 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, 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); @@ -445,11 +447,6 @@ void linphone_gtk_chat_destroyed(GtkWidget *w){ 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 ) { @@ -457,7 +454,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, 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" ); + /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ char *from=linphone_address_as_string ( linphone_chat_message_get_from ( msg ) ); w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); @@ -481,7 +478,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, g_object_set_data ( G_OBJECT ( friendlist ),"from",from ); } -#ifdef HAVE_GTK_OSXs +#ifdef HAVE_GTK_OSX /* Notified when a new message is sent */ linphone_gtk_status_icon_set_blinking ( TRUE ); #else @@ -495,14 +492,9 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } #endif if ( send ) { - if ( gtk_notebook_get_current_page ( notebook ) !=gtk_notebook_page_num ( notebook,w ) ) { - linphone_gtk_show_friends(); - } else { - linphone_chat_room_mark_as_read ( room ); - } linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), FALSE,room,msg,FALSE ); - } else { - linphone_gtk_show_friends(); } + linphone_gtk_show_friends(); + } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index f7e683f95..12da891f4 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -352,6 +352,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ } 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_friend_list_update_chat_picture(); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry")); @@ -556,6 +557,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; From 660a6948d8c6a574ab5f0ce9ec4c7b5ef43fbe2e Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 13 May 2013 15:12:14 +0200 Subject: [PATCH 348/909] Remove useless arguement in linphone_core_upnp_available --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 20dbeccdf..568435730 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4249,7 +4249,7 @@ 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 diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d9c017fea..6fc091c9e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1210,10 +1210,9 @@ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *l * @ingroup network_parameters * Return the availability of uPnP. * - * @param lc #LinphoneCore * @return true if uPnP is available otherwise return false. */ -bool_t linphone_core_upnp_available(const LinphoneCore *lc); +bool_t linphone_core_upnp_available(); /** * @ingroup network_parameters From 04da7df4aef8c417029944744cca201e7c00b485 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 14 May 2013 11:57:30 +0200 Subject: [PATCH 349/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 239be1a39..382f7d766 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 239be1a39fa3f4ab460e8e7ab6d4d3d31e15e72a +Subproject commit 382f7d766dcc2505a2bce2f2144d5f48103dfbd5 From 97743a057f0e6ed0bd08812af154d24bffcff8b0 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 14 May 2013 12:03:41 +0200 Subject: [PATCH 350/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 382f7d766..3f06cd60f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 382f7d766dcc2505a2bce2f2144d5f48103dfbd5 +Subproject commit 3f06cd60f1864b8c811e0f4e4590991802ce5ea7 From ba73c854ce00ae563b6248f9e3f5994e5ae6a49b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 14 May 2013 12:13:37 +0200 Subject: [PATCH 351/909] Renamed android libraries to avoid confusion --- build/android/Android-no-neon.mk | 8 ++++++- build/android/Android.mk | 3 +++ .../core/LinphoneCoreFactoryImpl.java | 24 +++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index d8e75ca0b..061a96217 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -35,7 +35,13 @@ endif LOCAL_MODULE := liblinphonenoneon ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_MODULE_FILENAME := liblinphonearmv5 +LOCAL_MODULE_FILENAME := liblinphonearmv5noneon +endif +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_MODULE_FILENAME := liblinphonearmv7noneon +endif +ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_MODULE_FILENAME := liblinphonex86noneon endif include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/Android.mk b/build/android/Android.mk index 10fba32dd..0dc0bd041 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -34,6 +34,9 @@ LOCAL_SHARED_LIBRARIES += \ endif LOCAL_MODULE := liblinphone +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_MODULE_FILENAME := liblinphonearmv7 +endif include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 0b799f33e..1d14ceb14 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -71,20 +71,20 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("bcg729"); //Main library - if (!hasNeonInCpuFeatures()) { - 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"); + if (isArmv7()) { + if (hasNeonInCpuFeatures()) { + Log.d("linphone", "armv7 liblinphone loaded"); + System.loadLibrary("linphonearmv7"); + } else { + Log.w("linphone", "No-neon armv7 liblinphone loaded"); + System.loadLibrary("linphonearmv7noneon"); } + } else if (Version.isX86()) { + Log.d("linphone", "No-neon x86 liblinphone loaded"); + System.loadLibrary("linphonex86noneon"); } else { - System.loadLibrary("linphone"); + Log.d("linphone", "No-neon armv5 liblinphone loaded"); + System.loadLibrary("linphonearmv5noneon"); } Version.dumpCapabilities(); From 415f845f3a450480246db71b4a4fbb7298f633b2 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 15 May 2013 10:46:15 +0200 Subject: [PATCH 352/909] Remove core argument in upnp_available in jni --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 58aef9850..1ff08e0a3 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2507,7 +2507,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) { From d7677e7a4b1ba91f55cf297a4105f3c4e61e08d4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 15 May 2013 10:50:30 +0200 Subject: [PATCH 353/909] Renamed liblinphonex86noneon to liblinphonex86 --- build/android/Android-no-neon.mk | 2 +- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 061a96217..39818fbf4 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -41,7 +41,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_MODULE_FILENAME := liblinphonearmv7noneon endif ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_MODULE_FILENAME := liblinphonex86noneon +LOCAL_MODULE_FILENAME := liblinphonex86 endif include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 1d14ceb14..8cedba445 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -81,7 +81,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } } else if (Version.isX86()) { Log.d("linphone", "No-neon x86 liblinphone loaded"); - System.loadLibrary("linphonex86noneon"); + System.loadLibrary("linphonex86"); } else { Log.d("linphone", "No-neon armv5 liblinphone loaded"); System.loadLibrary("linphonearmv5noneon"); From 2f10fbdde732229b96e7e99943a5bba04b3d116e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 May 2013 14:30:41 +0200 Subject: [PATCH 354/909] improve notifications of incoming chat messages - star appears even if already in the good chat tab - contact with active chats are displayed first in the friend list - activate icon pumping on Mac OS --- gtk/chat.c | 28 ++++++++++------------------ gtk/friendlist.c | 8 ++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 83538c848..1b68599b2 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -66,6 +66,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { g_return_if_fail(w!=NULL); 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); from=g_object_get_data(G_OBJECT(w),"from_message"); @@ -367,7 +368,6 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.blue = 61952; with_str=linphone_address_as_string_uri_only(with); - linphone_chat_room_mark_as_read(cr); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text),FALSE); @@ -407,8 +407,9 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres } 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; + char *tmp=linphone_address_as_string(with); + LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp); + ms_free(tmp); return cr; } @@ -427,7 +428,6 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, GtkTextIter end; GtkTextBuffer *text_buffer; - linphone_chat_room_mark_as_read(cr); 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); @@ -437,6 +437,8 @@ void linphone_gtk_load_chatroom(LinphoneChatRoom *cr,const LinphoneAddress *uri, 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); @@ -448,11 +450,6 @@ void linphone_gtk_chat_destroyed(GtkWidget *w){ 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 ) { @@ -460,7 +457,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, 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" ); + /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ char *from=linphone_address_as_string ( linphone_chat_message_get_from ( msg ) ); w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); @@ -484,7 +481,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, g_object_set_data ( G_OBJECT ( friendlist ),"from",from ); } -#ifdef HAVE_GTK_OSXs +#ifdef HAVE_GTK_OSX /* Notified when a new message is sent */ linphone_gtk_status_icon_set_blinking ( TRUE ); #else @@ -498,14 +495,9 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } #endif if ( send ) { - if ( gtk_notebook_get_current_page ( notebook ) !=gtk_notebook_page_num ( notebook,w ) ) { - linphone_gtk_show_friends(); - } else { - linphone_chat_room_mark_as_read ( room ); - } linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), FALSE,room,msg,FALSE ); - } else { - linphone_gtk_show_friends(); } + linphone_gtk_show_friends(); + } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index f7e683f95..12da891f4 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -352,6 +352,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ } 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_friend_list_update_chat_picture(); g_idle_add((GSourceFunc)grab_focus,linphone_gtk_get_widget(page,"text_entry")); @@ -556,6 +557,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; From cc0b90e9a48df26ff767033b450abe80e7822ed4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 16 May 2013 08:59:19 +0200 Subject: [PATCH 355/909] better wrong password management --- coreapi/bellesip_sal/sal_impl.c | 5 ++++ coreapi/bellesip_sal/sal_op_registration.c | 5 ++-- coreapi/callbacks.c | 27 ++++++++++++++-------- include/sal/sal.h | 8 +++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index a241f1692..9c3342ccb 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -422,8 +422,13 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; if (ctx->callbacks.auth_requested_legacy==NULL) ctx->callbacks.auth_requested_legacy=(SalOnAuthRequestedLegacy)unimplemented_stub; +#ifdef USE_BELLESIP + if (ctx->callbacks.auth_failure==NULL) + ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub; +#else if (ctx->callbacks.auth_success==NULL) ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub; +#endif if (ctx->callbacks.register_success==NULL) ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; if (ctx->callbacks.register_failure==NULL) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 46f1b91e2..bc90809d5 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -50,7 +50,6 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher if (service_route_address) belle_sip_object_unref(service_route_address); sal_remove_pending_auth(op->base.root,op); /*just in case*/ - if (op->auth_info) op->base.root->callbacks.auth_success(op,op->auth_info->realm,op->auth_info->username); op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0); } else if (status_code>=400) { /* from rfc3608, 6.1. @@ -65,13 +64,13 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher sal_op_set_service_route(op,NULL); sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); + op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); - op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); if (status_code == 403) { /*in sase of 401 or 407, auth requested already invoked previouly*/ /*auth previouly pending, probably wrong pasword, give a chance to authenticate again*/ - op->base.root->callbacks.auth_requested(op->base.root,op->auth_info); + op->base.root->callbacks.auth_failure(op,op->auth_info); } } } else { diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 778ee8ce7..994a865dd 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -712,7 +712,18 @@ static void auth_requested_legacy(SalOp *h, const char *realm, const char *usern lc->vtable.auth_info_requested(lc,realm,username); } } - +#ifdef USE_BELLESIP +static void auth_failure(SalOp *op, SalAuthInfo* info) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); + if (ai){ + ms_message("%s/%s authentication fails.",info->realm,info->username); + } + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,info->realm,info->username); + } +} +#else 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); @@ -721,7 +732,7 @@ static void auth_success(SalOp *h, const char *realm, const char *username){ ai->works=TRUE; } } - +#endif 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); @@ -894,13 +905,7 @@ static void ping_reply(SalOp *op){ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); - if (ai && ai->works==FALSE && ai->usecount>=1){ - /*Better is to stop (implemeted below in else statement), and retry later*/ - if (ms_time(NULL)-ai->last_use_time>30){ - ai->usecount=0; /*so that we can allow to retry */ - } - } - if (ai && (ai->works || ai->usecount<1)){ + if (ai) { sai->userid=ai->userid?ai->userid:ai->username; sai->password=ai->passwd; sai->ha1=ai->ha1; @@ -1000,7 +1005,11 @@ SalCallbacks linphone_sal_callbacks={ call_failure, call_released, auth_requested_legacy, +#ifdef USE_BELLESIP + auth_failure, +#else auth_success, +#endif register_success, register_failure, vfu_request, diff --git a/include/sal/sal.h b/include/sal/sal.h index 719e42d44..dc5976bec 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -325,7 +325,11 @@ typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, co typedef void (*SalOnCallReleased)(SalOp *salop); typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); +#ifndef USE_BELLESIP typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); +#else +typedef void (*SalOnAuthFailure)(SalOp *op, SalAuthInfo* info); +#endif typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); typedef void (*SalOnVfuRequest)(SalOp *op); @@ -353,7 +357,11 @@ typedef struct SalCallbacks{ SalOnCallFailure call_failure; SalOnCallReleased call_released; SalOnAuthRequestedLegacy auth_requested_legacy; +#ifdef USE_BELLESIP + SalOnAuthFailure auth_failure; +#else SalOnAuthSuccess auth_success; +#endif SalOnRegisterSuccess register_success; SalOnRegisterFailure register_failure; SalOnVfuRequest vfu_request; From 5d1809e46ce22cc116696a2dfeffe077af1b5c8e Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 16 May 2013 12:25:53 +0200 Subject: [PATCH 356/909] scroll to the end when load chat history --- gtk/chat.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index a58f443d6..13c140615 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -129,6 +129,15 @@ void udpate_tab_chat_header(GtkWidget *chat_view,const LinphoneAddress *uri,Linp gtk_widget_show_all(w); } +static gboolean scroll_to_end(GtkTextView *w){ + GtkTextBuffer *buffer=gtk_text_view_get_buffer(w); + GtkTextIter iter; + gtk_text_buffer_get_end_iter(buffer,&iter); + GtkTextMark *mark=gtk_text_buffer_create_mark(buffer,NULL,&iter,FALSE); + gtk_text_view_scroll_mark_onscreen(w,mark); + return FALSE; +} + 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")); @@ -199,8 +208,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, } gtk_text_buffer_get_end_iter(buffer,&iter); 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); + g_idle_add((GSourceFunc)scroll_to_end,text); ms_free(from_str); } From bb0f07f6a0bf188466b49f514c98ab031fc242b1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 16 May 2013 16:29:41 +0200 Subject: [PATCH 357/909] add info api refactor selection of proxy, identity, configurations of op fix bug when automatically restarting a call after a 415 due to srtp --- coreapi/Makefile.am | 22 ++++++------ coreapi/bellesip_sal/sal_impl.c | 16 +++++++-- coreapi/bellesip_sal/sal_impl.h | 10 ++++-- coreapi/callbacks.c | 11 ++++-- coreapi/chat.c | 9 ++--- coreapi/friend.c | 11 ++---- coreapi/linphonecall.c | 30 ++++++++-------- coreapi/linphonecore.c | 64 ++++++++++++++++++--------------- coreapi/linphonecore.h | 59 +++++++++++++++++++++++------- coreapi/presence.c | 2 +- coreapi/private.h | 9 +++-- include/sal/sal.h | 12 +++++++ 12 files changed, 164 insertions(+), 91 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index fd0c31eb4..1180bfff9 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -45,6 +45,7 @@ liblinphone_la_SOURCES=\ ec-calibrator.c \ conference.c \ message_storage.c \ + info.c \ $(GITVERSION_FILE) if BUILD_UPNP @@ -52,16 +53,17 @@ liblinphone_la_SOURCES+=upnp.c upnp.h endif if USE_BELLESIP -liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ - bellesip_sal/sal_impl.c \ - bellesip_sal/sal_op_impl.c \ - bellesip_sal/sal_op_call.c \ - bellesip_sal/sal_op_registration.c \ - bellesip_sal/sal_sdp.c \ - bellesip_sal/sal_op_message.c \ - bellesip_sal/sal_op_presence.c \ - bellesip_sal/sal_op_publish.c \ - bellesip_sal/sal_op_call_transfer.c +liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c \ + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_sdp.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_call_transfer.c \ + bellesip_sal/sal_op_info.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 9c3342ccb..b07a7bdf9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -53,16 +53,18 @@ void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { void sal_enable_logs(){ belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); } + void sal_disable_logs() { belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); } + void sal_add_pending_auth(Sal *sal, SalOp *op){ if (ms_list_find(sal->pending_auths,op)==NULL){ sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op)); } } - void sal_remove_pending_auth(Sal *sal, SalOp *op){ +void sal_remove_pending_auth(Sal *sal, SalOp *op){ if (ms_list_find(sal->pending_auths,op)){ sal->pending_auths=ms_list_remove(sal->pending_auths,op); sal_op_unref(op); @@ -104,6 +106,7 @@ void sal_process_authentication(SalOp *op) { } } + static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_get_dialog(event); SalOp* op = belle_sip_dialog_get_application_data(dialog); @@ -113,6 +116,7 @@ static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminat 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; @@ -126,6 +130,7 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e ms_error("sal process_io_error not implemented yet for non transaction"); } } + static void process_request_event(void *sal, const belle_sip_request_event_t *event) { SalOp* op=NULL; belle_sip_request_t* req = belle_sip_request_event_get_request(event); @@ -152,11 +157,14 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_message_fill_cbs(op); - } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; + }else if (strcmp("INFO",belle_sip_request_get_method(req))==0) { + op=sal_op_new((Sal*)sal); + op->dir=SalOpDirIncoming; + sal_op_info_fill_cbs(op); }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,501); @@ -447,6 +455,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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; } @@ -739,10 +749,12 @@ const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ } 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); } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1aa33c953..ca8cfc9d0 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -52,6 +52,7 @@ typedef enum SalOpSate { ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ ,SalOpStateTerminated }SalOpSate_t; + const char* sal_op_state_to_string(const SalOpSate_t value); typedef enum SalOpDir { @@ -64,7 +65,8 @@ typedef enum SalOpType { SalOpCall, SalOpMessage, SalOpPresence, - SalOpPublish + SalOpPublish, + SalOpInfo }SalOpType_t; const char* sal_op_type_to_string(const SalOpType_t type); @@ -121,7 +123,11 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ void sal_op_message_fill_cbs(SalOp*op); -/*call transfert*/ + +/*info*/ +void sal_op_info_fill_cbs(SalOp*op); + +/*call transfer*/ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); /*create SalAuthInfo by copying username and realm from suth event*/ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 994a865dd..0f977b911 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -621,7 +621,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de call->localdesc->streams[i].proto = SalProtoRtpAvp; memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); } - linphone_core_start_invite(lc, call); + linphone_core_restart_invite(lc, call); } return; } @@ -973,6 +973,7 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta static int op_equals(LinphoneCall *a, SalOp *b) { return a->op !=b; /*return 0 if equals*/ } + static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc); @@ -995,6 +996,11 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ } } +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); +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -1023,7 +1029,8 @@ SalCallbacks linphone_sal_callbacks={ subscribe_received, subscribe_closed, ping_reply, - auth_requested + auth_requested, + info_received }; diff --git a/coreapi/chat.c b/coreapi/chat.c index 5fa51c46d..15f380c0f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -65,7 +65,6 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){ - MSList *routes=NULL; SalOp *op=NULL; LinphoneCall *call; char* content_type; @@ -88,18 +87,14 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } msg->time=t; if (op==NULL){ - LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(cr->lc,cr->peer_url,&routes); + 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_transfer_routes_to_op(routes,op); + linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,FALSE); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ - if (msg->custom_headers){ - sal_op_set_sent_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); diff --git a/coreapi/friend.c b/coreapi/friend.c index 19dd16f01..ad6eabe54 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -106,13 +106,11 @@ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ char *friend=NULL; - const char *route=NULL; const char *from=NULL; LinphoneProxyConfig *cfg; - MSList *routes=NULL; friend=linphone_address_as_string(fr->uri); - cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr),&routes); + cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); if (cfg!=NULL){ from=linphone_proxy_config_get_identity(cfg); }else from=linphone_core_get_primary_contact(fr->lc); @@ -129,12 +127,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ fr->outsub=NULL; } fr->outsub=sal_op_new(fr->lc->sal); - sal_op_set_route(fr->outsub,route); - if (cfg && cfg->op && sal_op_get_contact(cfg->op)) - sal_op_set_contact(fr->outsub,sal_op_get_contact(cfg->op)); - else - sal_op_set_contact(fr->outsub,NULL); - linphone_transfer_routes_to_op(routes,fr->outsub); + linphone_configure_op(fr->lc,fr->outsub,fr->uri,NULL,TRUE); sal_subscribe_presence(fr->outsub,from,friend); fr->subscribe_active=TRUE; ms_free(friend); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5735cb777..d56d7ee60 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -468,17 +468,23 @@ 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); +} + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ + LinphoneCall *call=ms_new0(LinphoneCall,1); + + call->dir=LinphoneCallOutgoing; call->core=lc; linphone_core_get_local_ip(lc,NULL,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); - sal_op_set_sent_custom_header(call->op,call->params.custom_headers); if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); @@ -498,9 +504,10 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ - sal_call_set_referer(call->op,params->referer->op); call->referer=linphone_call_ref(params->referer); } + call->dest_proxy=cfg; + linphone_call_create_op(call); return call; } @@ -2530,17 +2537,10 @@ void linphone_call_set_contact_op(LinphoneCall* call) { #else LinphoneAddress *contact; #endif - LinphoneProxyConfig *cfg = NULL; 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 */ - linphone_core_get_default_proxy(call->core, &cfg); - call->dest_proxy = cfg; - call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to, NULL); - 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)); - } + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to); } contact=get_fixed_contact(call->core,call,call->dest_proxy); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 568435730..7e16f4403 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2050,7 +2050,7 @@ static void linphone_core_grab_buddy_infos(LinphoneCore *lc, LinphoneProxyConfig for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend*)elem->data; if (lf->info==NULL){ - if (linphone_core_lookup_known_proxy(lc,lf->uri,NULL)==cfg){ + if (linphone_core_lookup_known_proxy(lc,lf->uri)==cfg){ if (linphone_address_get_username(lf->uri)!=NULL){ BuddyLookupRequest *req; char *tmp=linphone_address_as_string_uri_only(lf->uri); @@ -2363,7 +2363,7 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L system. */ -static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *addr){ +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); @@ -2380,8 +2380,8 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA const char *transport=sal_address_get_transport_name(proxy_addr); if (transport){ SalAddress *route=sal_address_new(NULL); - sal_address_set_domain(route,sal_address_get_domain((SalAddress*)addr)); - sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)addr)); + sal_address_set_domain(route,sal_address_get_domain((SalAddress*)dest)); + sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)dest)); sal_address_set_transport_name(route,transport); ret=ms_list_append(ret,route); } @@ -2390,7 +2390,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA return ret; } -LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri, MSList **routes){ +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; LinphoneProxyConfig *default_cfg=lc->default_proxy; @@ -2416,31 +2416,17 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L end: if (found_cfg!=NULL && found_cfg!=default_cfg){ ms_message("Overriding default proxy setting for this call/message/subscribe operation."); - }; - - /*if route argument is given, fill adequate route set for this proxy.*/ - if (routes){ - if (found_cfg){ - *routes=make_routes_for_proxy(found_cfg,uri); - }else if (default_cfg){ - /*if the default proxy config has a locally configured route, we should use it*/ - const char *route=linphone_proxy_config_get_route(default_cfg); - if (route) - *routes=ms_list_append(*routes,sal_address_new(route)); - } - } + }else found_cfg=default_cfg; return found_cfg; } const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to){ - LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to,NULL); - if (cfg==NULL) - linphone_core_get_default_proxy (lc,&cfg); + LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to); if (cfg!=NULL){ return linphone_proxy_config_get_identity (cfg); } - return linphone_core_get_primary_contact (lc); + return linphone_core_get_primary_contact(lc); } @@ -2475,6 +2461,11 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c return 0; } +int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ + linphone_call_create_op(call); + return linphone_core_start_invite(lc,call); +} + int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ int err; char *real_url,*barmsg; @@ -2587,7 +2578,7 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr return call; } -void linphone_transfer_routes_to_op(MSList *routes, SalOp *op){ +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; @@ -2597,6 +2588,26 @@ void linphone_transfer_routes_to_op(MSList *routes, SalOp *op){ 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); + }else identity=linphone_core_get_primary_contact(lc); + /*sending out of calls*/ + if (proxy){ + routes=make_routes_for_proxy(proxy,dest); + linphone_transfer_routes_to_op(routes,op); + } + sal_op_set_to_address(op,dest); + sal_op_set_from(op,identity); + sal_op_set_sent_custom_header(op,headers); + if (with_contact && proxy && proxy->op && sal_op_get_contact(proxy->op)){ + sal_op_set_contact(op,sal_op_get_contact(proxy->op)); + } +} + /** * Initiates an outgoing call given a destination LinphoneAddress * @@ -2619,7 +2630,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *parsed_url2=NULL; char *real_url=NULL; LinphoneCall *call; - MSList *routes=NULL; bool_t defer = FALSE; linphone_core_preempt_sound_resources(lc); @@ -2632,7 +2642,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_core_get_default_proxy(lc,&proxy); real_url=linphone_address_as_string(addr); - proxy=linphone_core_lookup_known_proxy(lc,addr,&routes); + proxy=linphone_core_lookup_known_proxy(lc,addr); if (proxy!=NULL) from=linphone_proxy_config_get_identity(proxy); @@ -2642,9 +2652,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params); - call->dest_proxy=proxy; - linphone_transfer_routes_to_op(routes,call->op); + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params,proxy); if(linphone_core_add_call(lc,call)!= 0) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6fc091c9e..433001d65 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -221,6 +221,37 @@ LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); + + +struct _LinphoneInfoMessage; +/** + * The LinphoneInfoMessage is an object representing an informational message sent or received by the core. +**/ +typedef struct _LinphoneInfoMessage LinphoneInfoMessage; + +/** + * The LinphoneContent struct holds data that can be embedded in a signaling message. +**/ +struct _LinphoneContent{ + char *type; /** 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 */ @@ -848,11 +880,13 @@ typedef struct _LinphoneVTable{ BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/ NotifyReceivedCb notify_recv; /**< Other notifications*/ CallStatsUpdated call_stats_updated; /** A text message has been received */ } LinphoneCoreVTable; /** @@ -1522,14 +1556,15 @@ typedef struct _LinphoneTunnel LinphoneTunnel; */ LINPHONE_PUBLIC LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); -void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_sip_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp); +LINPHONE_PUBLIC int linphone_core_get_sip_dscp(const LinphoneCore *lc); -void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_audio_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp); +LINPHONE_PUBLIC int linphone_core_get_audio_dscp(const LinphoneCore *lc); + +LINPHONE_PUBLIC void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); +LINPHONE_PUBLIC int linphone_core_get_video_dscp(const LinphoneCore *lc); -void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_video_dscp(const LinphoneCore *lc); #ifdef __cplusplus diff --git a/coreapi/presence.c b/coreapi/presence.c index 8c93b28f7..89f361ff7 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -64,7 +64,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ tmp=linphone_address_as_string(uri); ms_message("Receiving new subscription from %s.",from); - cfg=linphone_core_lookup_known_proxy(lc,uri,NULL); + cfg=linphone_core_lookup_known_proxy(lc,uri); if (cfg!=NULL){ if (cfg->op){ if (sal_op_get_contact(cfg->op)) { diff --git a/coreapi/private.h b/coreapi/private.h index 611436f0b..6afc16c4b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -215,7 +215,7 @@ struct _LinphoneCall }; -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params); +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); void linphone_call_set_contact_op(LinphoneCall* call); @@ -315,8 +315,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, void linphone_proxy_config_update(LinphoneProxyConfig *cfg); void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); -LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri, MSList **routes); -void linphone_transfer_routes_to_op(MSList *routes, SalOp *op); +LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); 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); @@ -353,6 +352,7 @@ void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call); +int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call); int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call); void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call); @@ -739,6 +739,9 @@ typedef enum _LinphoneToneID{ void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); +void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); +void linphone_call_create_op(LinphoneCall *call); +void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); #ifdef __cplusplus } diff --git a/include/sal/sal.h b/include/sal/sal.h index dc5976bec..c43d0c0e7 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -315,6 +315,13 @@ typedef struct SalAuthInfo{ char *ha1; }SalAuthInfo; +typedef struct SalBody{ + const char *type; + const char *subtype; + const void *data; + size_t size; +}SalBody; + typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); @@ -343,6 +350,7 @@ typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenc typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); +typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body); /*allows sal implementation to access auth info if available, return TRUE if found*/ @@ -376,6 +384,7 @@ typedef struct SalCallbacks{ SalOnSubscribeClosed subscribe_closed; SalOnPingReply ping_reply; SalOnAuthRequested auth_requested; + SalOnInfoReceived info_received; }SalCallbacks; @@ -518,6 +527,9 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus s /*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to); +/*info messages*/ +int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body); + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); From 653a123b8140a7e3e8893bd920ae4b0eff9ab3cd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 16 May 2013 16:44:43 +0200 Subject: [PATCH 358/909] presence and publish bugfixes --- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/bellesip_sal/sal_op_registration.c | 2 -- coreapi/proxy.c | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index b325db9d7..19b69fecb 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -540,7 +540,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques }else{ estatus=SalPresenceOffline; } - ms_message("We are notified that [%s] has online status [%s]",sal_op_get_from(op),sal_presence_status_to_string(estatus)); + ms_message("We are notified that [%s] has online status [%s]",sal_op_get_to(op),sal_presence_status_to_string(estatus)); 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("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index bc90809d5..5683568b4 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -73,8 +73,6 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher op->base.root->callbacks.auth_failure(op,op->auth_info); } } - } else { - ms_warning("Register refresher know what to do with this status code"); } } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 208b63903..c3770d87e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1182,12 +1182,12 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ } if (can_register(cfg)){ linphone_proxy_config_register(cfg); - if (cfg->publish && cfg->publish_op==NULL){ - linphone_proxy_config_send_publish(cfg,lc->presence_mode); - } cfg->commit=FALSE; } } + if (cfg->publish && cfg->publish_op==NULL && cfg->state==LinphoneRegistrationOk){ + linphone_proxy_config_send_publish(cfg,lc->presence_mode); + } } void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type){ From a1c566ff8bb79bedcaa348a69edddc6fcb5b4dc2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 17 May 2013 19:19:01 +0200 Subject: [PATCH 359/909] fix srtp +video +ice --- configure.ac | 3 - coreapi/bellesip_sal/sal_sdp.c | 1 + coreapi/linphonecall.c | 9 +- tester/call_tester.c | 212 +++++++++++++++++++++++---------- 4 files changed, 155 insertions(+), 70 deletions(-) diff --git a/configure.ac b/configure.ac index cee8906df..f450cd84d 100644 --- a/configure.ac +++ b/configure.ac @@ -862,8 +862,5 @@ if test $USE_BELLESIP_TRUE !='#' ; then else printf "* eXosip stack\t\t\ttrue\n" fi -if test "$build_upnp" = "true" ; then - printf "* upnp support\t\t\ttrue\n" -fi echo "Now type 'make' to compile, and then 'make install' as root to install it." diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index f610f2d3c..00bba6505 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -398,6 +398,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /* read crypto lines if any */ if ( stream->proto == SalProtoRtpSavp ) { + valid_count=0; memset ( &stream->crypto, 0, sizeof ( stream->crypto ) ); for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc ) ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d56d7ee60..3f2783b06 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -223,6 +223,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + char local_ip[256]; + linphone_core_get_local_ip_for( AF_INET,"linphone.org",local_ip); linphone_core_adapt_to_network(lc,call->ping_time,&call->params); @@ -236,7 +238,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); if (call->params.down_bw) @@ -244,8 +246,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr)); - strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr)); + strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr)); + strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr)); md->streams[0].rtp_port=call->audio_port; md->streams[0].rtcp_port=call->audio_port+1; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? @@ -1291,6 +1293,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ } call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1); ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session); + ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.session); } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq); diff --git a/tester/call_tester.c b/tester/call_tester.c index 4b74cabe8..c0f370bbb 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -98,6 +98,7 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* cal int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; + bool_t result=FALSE; if (!params){ CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); @@ -139,10 +140,18 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* cal CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); /*just to sleep*/ - return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+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); + if (linphone_core_get_media_encryption(caller_mgr->lc) + && linphone_core_get_media_encryption(callee_mgr->lc)) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); + } + return result; } bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ @@ -398,38 +407,41 @@ static void call_with_no_sdp(void) { linphone_core_manager_destroy(pauline); } -static void call_with_ice(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - int i; +static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) { LinphoneCall *c1,*c2; bool_t success=FALSE; - - linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); - linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); - linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); - linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); - - CU_ASSERT_TRUE(call(pauline,marie)); - - c1=linphone_core_get_current_call(marie->lc); - c2=linphone_core_get_current_call(pauline->lc); + int i; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); CU_ASSERT_PTR_NOT_NULL(c1); CU_ASSERT_PTR_NOT_NULL(c2); - - for (i=0;i<100;i++){ + + for (i=0;i<200;i++){ if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ success=TRUE; break; } - linphone_core_iterate(marie->lc); - linphone_core_iterate(pauline->lc); - ms_usleep(100000); + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); + ms_usleep(50000); } + return success; +} +static void call_with_ice(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - CU_ASSERT_TRUE(success); + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); @@ -542,41 +554,44 @@ static void call_paused_resumed_from_callee(void) { } #ifdef VIDEO_ENABLED +static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { + LinphoneVideoPolicy caller_policy; + LinphoneCallParams* callee_params; + LinphoneCall* call_obj; + caller_policy.automatically_accept=TRUE; + caller_policy.automatically_initiate=TRUE; + linphone_core_enable_video(callee->lc,TRUE,TRUE); + linphone_core_enable_video(caller->lc,TRUE,FALSE); + linphone_core_set_video_policy(caller->lc,&caller_policy); + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + call_obj = linphone_core_get_current_call(callee->lc); + callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); + /*add video*/ + linphone_call_params_enable_video(callee_params,TRUE); + linphone_core_update_call(callee->lc,call_obj,callee_params); + + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning+1)); + + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + + linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc); + /*send vfu*/ + linphone_call_send_vfu_request(call_obj); + return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1); + +} static void call_with_video_added(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - LinphoneCall* call_obj; - LinphoneVideoPolicy pauline_policy; - LinphoneCallParams* marie_params; - pauline_policy.automatically_accept=TRUE; - pauline_policy.automatically_initiate=TRUE; - CU_ASSERT_TRUE(call(pauline,marie)); - linphone_core_enable_video(marie->lc,TRUE,TRUE); - linphone_core_enable_video(pauline->lc,TRUE,FALSE); - linphone_core_set_video_policy(pauline->lc,&pauline_policy); - - call_obj = linphone_core_get_current_call(marie->lc); - marie_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); - /*add video*/ - linphone_call_params_enable_video(marie_params,TRUE); - linphone_core_update_call(marie->lc,call_obj,marie_params); - - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); - - CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))); - CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))); - - linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,marie->lc); - /*send vfu*/ - linphone_call_send_vfu_request(call_obj); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); - + CU_ASSERT_TRUE(add_video(pauline,marie)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); @@ -645,28 +660,95 @@ static void simple_conference(void) { ms_list_free(lcs); } -#ifdef SRTP_ENABLED + static void srtp_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); - linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); - CU_ASSERT_TRUE(call(pauline,marie)); + CU_ASSERT_TRUE(call(pauline,marie)); - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); - - /*just to sleep*/ - linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -#endif //SRTP_ENABLED +static void call_with_declined_srtp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#ifdef VIDEO_ENABLED +static void srtp_video_ice_call(void) { +#else +static void srtp_ice_call(void) { +#endif + int i=0; + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); +#ifdef VIDEO_ENABLED + for (i=0;i<100;i++) { /*fixme to workaround a crash*/ + ms_usleep(20000); + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + } + + add_video(pauline,marie); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); +#endif + /*wait for ice to found the direct path*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void early_media_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_early_rc"); @@ -824,11 +906,13 @@ test_t call_tests[] = { { "Call without SDP", call_with_no_sdp}, { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, -#ifdef SRTP_ENABLED { "SRTP call", srtp_call }, -#endif + { "SRTP call with declined srtp", call_with_declined_srtp }, #ifdef VIDEO_ENABLED + { "SRTP ice video call", srtp_video_ice_call }, { "Call with video added", call_with_video_added }, +#else + { "SRTP ice call", srtp_ice_call }, #endif { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, From 4cc7c7c074a4bce273be40a1f5d74e114a71a105 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 17 May 2013 22:22:21 +0200 Subject: [PATCH 360/909] info api in progress, but test is failed due to flexisip not forking info --- coreapi/bellesip_sal/sal_impl.h | 8 ++--- coreapi/bellesip_sal/sal_op_impl.c | 4 +-- include/sal/sal.h | 1 + tester/liblinphone_tester.h | 4 +++ tester/message_tester.c | 57 +++++++++++++++++++++++++++++- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index ca8cfc9d0..59d1729e9 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -46,14 +46,14 @@ struct Sal{ bool_t use_dates; }; -typedef enum SalOpSate { +typedef enum SalOpState { SalOpStateEarly=0 ,SalOpStateActive ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ ,SalOpStateTerminated -}SalOpSate_t; +}SalOpState; -const char* sal_op_state_to_string(const SalOpSate_t value); +const char* sal_op_state_to_string(SalOpState value); typedef enum SalOpDir { SalOpDirIncoming=0 @@ -85,7 +85,7 @@ struct SalOp{ SalMediaDescription *result; belle_sdp_session_description_t *sdp_answer; bool_t supports_session_timers; - SalOpSate_t state; + SalOpState state; SalOpDir_t dir; belle_sip_refresher_t* refresher; int ref; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a7f8b796a..90f616545 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -375,14 +375,14 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp return -1; } -const char* sal_op_state_to_string(const SalOpSate_t value) { +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 "Unknon"; + return "Unknown"; } } diff --git a/include/sal/sal.h b/include/sal/sal.h index c43d0c0e7..38610ac35 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -448,6 +448,7 @@ void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_from_address(SalOp *op, const SalAddress *from); void sal_op_set_to(SalOp *op, const char *to); void sal_op_set_to_address(SalOp *op, const SalAddress *to); +SalOp *sal_op_ref(SalOp* h); void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index d33ac9f64..6b3f2a2dd 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -133,6 +133,9 @@ typedef struct _stats { int number_of_LinphoneStatusAltService; int number_of_LinphoneStatusPending; int number_of_LinphoneStatusEnd; + + int number_of_inforeceived; + int number_of_inforeceived_with_body; }stats; @@ -156,6 +159,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); +void info_message_received(LinphoneCore *lc, LinphoneInfoMessage *msg); void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); diff --git a/tester/message_tester.c b/tester/message_tester.c index 47ab8d1cc..fb06a5dbf 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -161,13 +161,68 @@ static void text_message_with_send_error(void) { linphone_core_manager_destroy(pauline); } +static const char *info_content="blabla"; + +void info_message_received(LinphoneCore *lc, LinphoneInfoMessage *msg){ + stats* counters = (stats*)linphone_core_get_user_data(lc); + const char *hvalue=linphone_info_message_get_header(msg, "Weather"); + const LinphoneContent *content=linphone_info_message_get_content(msg); + CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_TRUE(strcmp(hvalue,"still bad")==0); + + if (!content){ + counters->number_of_inforeceived++; + }else{ + CU_ASSERT_PTR_NOT_NULL(content->data); + CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); + CU_ASSERT_EQUAL(content->size,strlen(info_content)); + counters->number_of_inforeceived_with_body++; + } +} + + + +static void info_message_with_args(bool_t with_content) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneInfoMessage *info=linphone_core_create_info_message(marie->lc); + linphone_info_message_add_header(info,"Wheather","still bad"); + if (with_content) { + LinphoneContent ct; + ct.type="application"; + ct.subtype="somexml"; + ct.data=(void*)info_content; + ct.size=strlen(info_content); + linphone_info_message_set_content(info,&ct); + } + linphone_core_send_info_message(marie->lc,info,pauline->identity); + linphone_info_message_destroy(info); + + if (with_content){ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived_with_body,1)); + }else{ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void info_message(){ + info_message_with_args(FALSE); +} + +static void info_message_with_body(){ + info_message_with_args(TRUE); +} test_t message_tests[] = { { "Text message", text_message }, { "Text message 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 } + { "Text message with external body", text_message_with_external_body }, + { "Info message", info_message }, + { "Info message with body", info_message_with_body } }; test_suite_t message_test_suite = { From a08b50bd69a67a5d000724b940a5a5e403154156 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 May 2013 11:06:06 +0200 Subject: [PATCH 361/909] info api working --- coreapi/linphonecore.h | 4 ++-- tester/liblinphone_tester.c | 1 + tester/liblinphone_tester.h | 2 +- tester/message_tester.c | 12 ++++++++---- tester/setup_tester.c | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 433001d65..4ef4b6a4f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -247,9 +247,9 @@ typedef struct _LinphoneContent LinphoneContent; LINPHONE_PUBLIC LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_send_info_message(LinphoneCore *lc, const LinphoneInfoMessage *info, const LinphoneAddress *addr); 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(LinphoneInfoMessage *im, const char *name); +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(LinphoneInfoMessage *im); +LINPHONE_PUBLIC const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im); LINPHONE_PUBLIC void linphone_info_message_destroy(LinphoneInfoMessage *im); /** diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 1c9c767dc..185ce9587 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -184,6 +184,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; + mgr->v_table.info_received=info_message_received; mgr->lc=configure_lc_from(&mgr->v_table, path, rc_file, check_for_proxies?(rc_file?1:0):0); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 6b3f2a2dd..91ed8ac5e 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -159,7 +159,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); -void info_message_received(LinphoneCore *lc, LinphoneInfoMessage *msg); +void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg); void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); diff --git a/tester/message_tester.c b/tester/message_tester.c index fb06a5dbf..a9beef3ed 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -163,17 +163,21 @@ static void text_message_with_send_error(void) { static const char *info_content="blabla"; -void info_message_received(LinphoneCore *lc, LinphoneInfoMessage *msg){ +void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg){ stats* counters = (stats*)linphone_core_get_user_data(lc); const char *hvalue=linphone_info_message_get_header(msg, "Weather"); const LinphoneContent *content=linphone_info_message_get_content(msg); - CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_PTR_NOT_NULL_FATAL(hvalue); CU_ASSERT_TRUE(strcmp(hvalue,"still bad")==0); if (!content){ counters->number_of_inforeceived++; }else{ - CU_ASSERT_PTR_NOT_NULL(content->data); + CU_ASSERT_PTR_NOT_NULL_FATAL(content->data); + CU_ASSERT_PTR_NOT_NULL_FATAL(content->type); + CU_ASSERT_PTR_NOT_NULL_FATAL(content->subtype); + CU_ASSERT_TRUE(strcmp(content->type,"application")==0); + CU_ASSERT_TRUE(strcmp(content->subtype,"somexml")==0); CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); CU_ASSERT_EQUAL(content->size,strlen(info_content)); counters->number_of_inforeceived_with_body++; @@ -186,7 +190,7 @@ static void info_message_with_args(bool_t with_content) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneInfoMessage *info=linphone_core_create_info_message(marie->lc); - linphone_info_message_add_header(info,"Wheather","still bad"); + linphone_info_message_add_header(info,"Weather","still bad"); if (with_content) { LinphoneContent ct; ct.type="application"; diff --git a/tester/setup_tester.c b/tester/setup_tester.c index f567ca2e2..d14dca0b8 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -19,7 +19,7 @@ #include #include "CUnit/Basic.h" #include "linphonecore.h" -#include "private.h" + #include "liblinphone_tester.h" From 6ff0f4b2324ab937ae5baaa189ae6a01fdce37e1 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 20 May 2013 12:02:34 +0200 Subject: [PATCH 362/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3f06cd60f..9b3487265 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3f06cd60f1864b8c811e0f4e4590991802ce5ea7 +Subproject commit 9b3487265555c933375ce932f4e3e6511cf532dd From 65fec32c047f54ccec9e35d9c3e6c14512733029 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Mon, 20 May 2013 12:08:10 +0200 Subject: [PATCH 363/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 9b3487265..c799531d9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9b3487265555c933375ce932f4e3e6511cf532dd +Subproject commit c799531d9403c50fb06965a921e1530c814e02a1 From 837c3f7cf1070a01dad59d237335aa4efd9fb219 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 May 2013 15:32:36 +0200 Subject: [PATCH 364/909] fix transfer test (requires sipstack upgrade too) --- coreapi/bellesip_sal/sal_op_call_transfer.c | 13 +++++++++++-- tester/call_tester.c | 18 +++++++++--------- tester/liblinphone_tester.h | 10 +++++----- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 16f7500f3..b0058e15e 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -53,8 +53,16 @@ int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_si } int sal_call_refer(SalOp *op, const char *refer_to){ - belle_sip_header_refer_to_t* 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,NULL); + 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){ @@ -174,6 +182,7 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ 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); diff --git a/tester/call_tester.c b/tester/call_tester.c index c0f370bbb..aff361f20 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -70,11 +70,11 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, counters = (stats*)linphone_core_get_user_data(lc); switch (new_call_state) { case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; - case LinphoneCallOutgoingProgress :counters->number_of_LinphoneTransfertCallOutgoingProgress++;break; - case LinphoneCallOutgoingRinging :counters->number_of_LinphoneTransfertCallOutgoingRinging++;break; - case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneTransfertCallOutgoingEarlyMedia++;break; - case LinphoneCallConnected :counters->number_of_LinphoneTransfertCallConnected++;break; - case LinphoneCallStreamsRunning :counters->number_of_LinphoneTransfertCallStreamsRunning++;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; default: CU_FAIL("unexpected event");break; } @@ -798,13 +798,13 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransfertCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransfertCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); /*terminate marie to pauline call*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); @@ -862,7 +862,7 @@ static void call_transfer_existing_call_outgoing_call(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransfertCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); /*laure accept call*/ for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { @@ -877,7 +877,7 @@ static void call_transfer_existing_call_outgoing_call(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransfertCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,1,2000)); /*terminate marie to pauline/laure call*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 91ed8ac5e..7aa3cebb9 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -103,11 +103,11 @@ typedef struct _stats { int number_of_LinphoneCallReleased; int number_of_LinphoneTransferCallOutgoingInit; - int number_of_LinphoneTransfertCallOutgoingProgress; - int number_of_LinphoneTransfertCallOutgoingRinging; - int number_of_LinphoneTransfertCallOutgoingEarlyMedia; - int number_of_LinphoneTransfertCallConnected; - int number_of_LinphoneTransfertCallStreamsRunning; + int number_of_LinphoneTransferCallOutgoingProgress; + int number_of_LinphoneTransferCallOutgoingRinging; + int number_of_LinphoneTransferCallOutgoingEarlyMedia; + int number_of_LinphoneTransferCallConnected; + int number_of_LinphoneTransferCallStreamsRunning; int number_of_LinphoneMessageReceived; int number_of_LinphoneMessageReceivedLegacy; From 64d34b30ad24a42b584b17611138b4a658c549ec Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 May 2013 15:41:49 +0200 Subject: [PATCH 365/909] add missing files --- coreapi/bellesip_sal/sal_op_info.c | 79 +++++++++++++ coreapi/info.c | 184 +++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 coreapi/bellesip_sal/sal_op_info.c create mode 100644 coreapi/info.c diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c new file mode 100644 index 000000000..41f39008d --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -0,0 +1,79 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ +} + +static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { +} + +static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ +} + +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_header_content_type_t* content_type; + belle_sip_header_content_length_t *clen=NULL; + belle_sip_response_t* resp; + SalBody salbody; + const char *body; + + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + if (content_type){ + body=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + clen=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_length_t); + } + + 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); + op->base.root->callbacks.info_received(op,&salbody); + } else { + op->base.root->callbacks.info_received(op,NULL); + } + resp = belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); +} + +int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ + belle_sip_request_t *req=sal_op_build_request(op,"INFO"); + sal_op_info_fill_cbs(op); + 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); + } + return sal_op_send_request(op,req); +} + +void sal_op_info_fill_cbs(SalOp*op) { + op->callbacks.process_io_error=process_io_error; + op->callbacks.process_response_event=process_response_event; + op->callbacks.process_timeout=process_timeout; + op->callbacks.process_request_event=process_request_event; + op->type=SalOpInfo; +} diff --git a/coreapi/info.c b/coreapi/info.c new file mode 100644 index 000000000..6ab5f5837 --- /dev/null +++ b/coreapi/info.c @@ -0,0 +1,184 @@ +/*************************************************************************** + * 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; + SalOp *op; + SalCustomHeader *headers; +}; + +#define SET_STRING(ptr,field,val) \ + if (ptr->field) { \ + ms_free(ptr->field); \ + ptr->field=NULL; \ + } \ + if (val){ \ + ptr->field=ms_strdup(val); \ + } + +static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ + SET_STRING(obj,type,ref->type); + SET_STRING(obj,subtype,ref->subtype); + if (obj->data) { + ms_free(obj->data); + obj->data=NULL; + } + if (ref->data){ + obj->data=ms_malloc(ref->size+1); + memcpy(obj->data, ref->data, ref->size); + ((char*)obj->data)[ref->size]='\0'; + } + obj->size=ref->size; +} + +static void linphone_content_uninit(LinphoneContent * obj){ + if (obj->type) ms_free(obj->type); + if (obj->subtype) ms_free(obj->subtype); + if (obj->data) ms_free(obj->data); +} + +static LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ + SET_STRING(obj,type,ref->type); + SET_STRING(obj,subtype,ref->subtype); + if (obj->data) { + ms_free(obj->data); + obj->data=NULL; + } + if (ref->data){ + obj->data=ms_malloc(ref->size+1); + memcpy(obj->data, ref->data, ref->size); + ((char*)obj->data)[ref->size]='\0'; + } + obj->size=ref->size; + return obj; +} + +static SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ + if (lc->type){ + body->type=lc->type; + body->subtype=lc->subtype; + body->data=lc->data; + body->size=lc->size; + return body; + } + return NULL; +} + +/** + * Destroy a LinphoneInfoMessage +**/ +void linphone_info_message_destroy(LinphoneInfoMessage *im){ + /* FIXME: op is leaked. If we release it now, there is a high risk that the request won't be resent with authentication*/ + /*if (im->op) sal_op_release(im->op);*/ + linphone_content_uninit(&im->content); + sal_custom_header_free(im->headers); + ms_free(im); +} + +/** + * Creates an empty info message. + * @param lc the LinphoneCore object. + * @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); + im->op=sal_op_new(lc->sal); + return im; +} + +/** + * Send a LinphoneInfoMessage to a specified address. + * @param lc the LinphoneCore + * @param info the info message + * @param addr the destination address +**/ +int linphone_core_send_info_message(LinphoneCore *lc, const LinphoneInfoMessage *info, const LinphoneAddress *addr){ + SalBody body; + linphone_configure_op(lc,info->op,addr,info->headers,FALSE); + return sal_send_info(info->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){ + const SalCustomHeader *ch=sal_op_get_recv_custom_header(im->op); + return sal_custom_header_find(ch,name); +} + +/** + * Returns origin of received LinphoneInfoMessage +**/ +const char *linphone_info_message_get_from(LinphoneInfoMessage *im){ + return sal_op_get_from(im->op); +} + +/** + * Assign a content to the info message. + * @param im the linphone info message + * @param content the content described as a #LinphoneContent structure. + * All fields of the LinphoneContent are copied, thus the application can destroy/modify/recycloe the content object freely ater the function returns. +**/ +void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content){ + linphone_content_copy(&im->content,content); +} + +/** + * Returns the info message's content as a #LinphoneContent structure. +**/ +const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im){ + return im->content.type ? &im->content : NULL; +} + +void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){ + LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1); + info->op=sal_op_ref(op); + info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op)); + if (body) linphone_content_copy_from_sal_body(&info->content,body); + if (lc->vtable.info_received) + lc->vtable.info_received(lc,info); + linphone_info_message_destroy(info); +} From 84514831a11fbde05b25a3806e4a79df075a527e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 May 2013 15:59:45 +0200 Subject: [PATCH 366/909] disable video in presence test because it crashes opengl --- tester/presence_tester.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 308388710..bc9bf24bd 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -136,6 +136,8 @@ static void unsubscribe_while_subscribing(void) { static void call_with_presence(void) { LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); + LinphoneVideoPolicy pol={0}; + linphone_core_set_video_policy(marie->lc,&pol); CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); CU_ASSERT_TRUE(call(marie,pauline)); From bfe2437bbe7f191d616e9e2f0b3d254cfbff2476 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 20 May 2013 19:03:40 +0200 Subject: [PATCH 367/909] fix bad event name, should be "presence", not "Presence". --- coreapi/bellesip_sal/sal_op_presence.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 19b69fecb..8d800ef9d 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -592,7 +592,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ req=sal_op_build_request(op,"SUBSCRIBE"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); return sal_op_send_request(op,req); @@ -603,7 +603,7 @@ int sal_unsubscribe(SalOp *op){ ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); return -1; } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); return sal_op_send_request(op,req); } @@ -620,18 +620,26 @@ int sal_subscribe_decline(SalOp *op){ belle_sip_server_transaction_send_response(op->pending_server_trans,resp); return 0; } -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + +static belle_sip_request_t *create_presence_notify(SalOp *op){ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + belle_sip_message_add_header((belle_sip_message_t*)notify,belle_sip_header_create("Event","presence")); + return notify; +} + +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + belle_sip_request_t* notify=create_presence_notify(op); sal_add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*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_close(SalOp *op){ - belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + belle_sip_request_t* notify=create_presence_notify(op); sal_add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*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))); + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); return sal_op_send_request(op,notify); } From 3b0c5a79b194ba98358986f63a8b0d466d997c12 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 21 May 2013 09:23:38 +0200 Subject: [PATCH 368/909] Update ms2 (ffmpeg version issue) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c799531d9..1a69168c1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c799531d9403c50fb06965a921e1530c814e02a1 +Subproject commit 1a69168c1f30a7be439606069bd8dc4d5becac02 From 23967d8ca8c991898acb813afc775f2f49184fda Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 21 May 2013 11:16:45 +0200 Subject: [PATCH 369/909] fix ortp initiale ref count. Remove abusive traces --- coreapi/bellesip_sal/sal_impl.c | 3 ++- coreapi/bellesip_sal/sal_op_call.c | 6 +++++- coreapi/linphonecall.c | 3 +-- coreapi/linphonecore.c | 3 ++- oRTP | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b07a7bdf9..1609703a4 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -127,7 +127,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e op->callbacks.process_io_error(op,event); } } else { - ms_error("sal process_io_error not implemented yet for non transaction"); + /*ms_error("sal process_io_error not implemented yet for non transaction");*/ + /*nop, because already handle at transaction layer*/ } } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 28a46bd93..76ea05782 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -247,7 +247,11 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } else { /*nop error*/ } - ms_error("call op [%p] receive an unexpected answer [%i]",op,code); + if (code >= 100 && code < 180) { + ms_message("call op [%p] receive [%i]",op,code); + } else { + ms_error("call op [%p] receive an unexpected answer [%i]",op,code); + } } case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3f2783b06..88f3869ed 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -223,8 +223,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); - char local_ip[256]; - linphone_core_get_local_ip_for( AF_INET,"linphone.org",local_ip); + char* local_ip=call->localip; linphone_core_adapt_to_network(lc,call->ping_time,&call->params); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7e16f4403..449fb43e4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2799,7 +2799,8 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ sal_call_decline(call->op,SalReasonMedia,NULL); - linphone_call_unref(call); + linphone_core_del_call(lc,call); + linphone_call_ref(call); return; } } diff --git a/oRTP b/oRTP index 2d8a82247..1a103971b 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2d8a82247fbebbd690ae2fc8300522ab9b71a542 +Subproject commit 1a103971b84d39510ad14f327bd6834b3d88063f From a7f011585aeac97bb2299fcc661a16b7c3903ceb Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Tue, 21 May 2013 14:03:27 +0200 Subject: [PATCH 370/909] Update ms2 (ffmpeg) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1a69168c1..47483a49a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1a69168c1f30a7be439606069bd8dc4d5becac02 +Subproject commit 47483a49a55765197c855eefd29c9d382eaa329a From 249c4d986954243e03a4c3e7044a772aca27090c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 May 2013 14:17:53 +0200 Subject: [PATCH 371/909] add new files to be compiled in android makefiles --- build/android/common.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/android/common.mk b/build/android/common.mk index 06a773091..aeedab67b 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -44,6 +44,7 @@ LOCAL_SRC_FILES := \ bellesip_sal/sal_op_presence.c \ bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_info.c \ bellesip_sal/sal_sdp.c \ sal.c \ offeranswer.c \ @@ -52,7 +53,8 @@ LOCAL_SRC_FILES := \ conference.c \ ec-calibrator.c \ linphone_tunnel_config.c \ - message_storage.c + message_storage.c \ + info.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" From d474f9dd4c44704f4fb0bc3fe6d0860e0415c1f5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 14:02:18 +0200 Subject: [PATCH 372/909] Declare variables at the beginning of code blocks to fix compilation errors. --- coreapi/linphonecall.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index db3190bbb..d5366e5c6 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -84,9 +84,11 @@ static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) { #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; + { + const LinphoneCallParams *params=linphone_call_get_current_params(call); + if (params->has_video && !call->videostream_encrypted) { + return FALSE; + } } #endif @@ -110,9 +112,9 @@ void propagate_encryption_changed(LinphoneCall *call){ #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; + + ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted"); call->videostream_encrypted=encrypted; propagate_encryption_changed(call); } @@ -135,12 +137,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) { + OrtpZrtpParams 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 } @@ -1627,11 +1631,11 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->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.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, @@ -1701,9 +1705,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ LinphoneCore *lc=call->core; - call->current_params.audio_codec = NULL; - call->current_params.video_codec = NULL; - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); char *cname; bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); @@ -1712,6 +1713,9 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut SalProtoRtpAvp,SalVideo); #endif + 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; From f71aad552c38c62fd7283f79986d10aabfa22409 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 14:40:16 +0200 Subject: [PATCH 373/909] Declare variables at the beginning of code blocks to fix compilation errors. --- coreapi/linphonecore.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 02db3b54f..f60640160 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2838,10 +2838,13 @@ 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; +#ifdef VIDEO_ENABLED + bool_t has_video = FALSE; +#endif if (params!=NULL){ linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); #ifdef VIDEO_ENABLED - bool_t has_video = call->params.has_video; + has_video = call->params.has_video; // Video removing if((call->videostream != NULL) && !params->has_video) { @@ -4677,9 +4680,9 @@ unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc) * If not set the core will create its own window. **/ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id){ - lc->preview_window_id=id; #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call(lc); + lc->preview_window_id=id; if (call!=NULL && call->videostream){ video_stream_set_native_preview_window_id(call->videostream,id); }else if (lc->previewstream){ @@ -4693,8 +4696,8 @@ 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); } @@ -4730,9 +4733,11 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int 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 } From 6c8ee3348ea0d862ea9c37debe2059a4607e219f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 14:52:59 +0200 Subject: [PATCH 374/909] Initialize variable that may be used uninitialized otherwise. --- coreapi/bellesip_sal/sal_op_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index 41f39008d..a86328fbb 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -35,7 +35,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_header_content_length_t *clen=NULL; belle_sip_response_t* resp; SalBody salbody; - const char *body; + const char *body = NULL; content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); if (content_type){ From 0ce7e08edd43de8ab7b1f91c8d35892093ad1ce2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 14:59:39 +0200 Subject: [PATCH 375/909] Add reference to mswp8vid. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 9ba14d251..a19453da4 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -235,6 +235,9 @@ {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + {0565952a-ea62-46a2-8261-f5b4b490da42} + {ffc7b532-0502-4d88-ac98-9e89071cbc97} false From c931a7127a22d689ee7c2239702be521fe2247fd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 15:00:14 +0200 Subject: [PATCH 376/909] Add new files to be compiled to the Visual Studio project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index a19453da4..0d963e1ef 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -177,6 +177,7 @@ + @@ -188,6 +189,7 @@ + From d704282d2447824e24330fc3b1e3924930291023 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 May 2013 15:02:49 +0200 Subject: [PATCH 377/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 47483a49a..3f2672fcf 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 47483a49a55765197c855eefd29c9d382eaa329a +Subproject commit 3f2672fcf8a8d8f951047844d38dca1631999d7e From 229aa1cdb67b95a4b36c8a42ca1006ebfe3c486d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 15:04:22 +0200 Subject: [PATCH 378/909] Enabled video compilation in Visual Studio project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 0d963e1ef..693f6c9c7 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -67,7 +67,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing @@ -91,7 +91,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default @@ -117,7 +117,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default NotUsing @@ -147,7 +147,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true Default @@ -268,4 +268,4 @@ - \ No newline at end of file + From 61d82cce4266fa74d333cd94114fc9f383e06674 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 May 2013 17:50:33 +0200 Subject: [PATCH 379/909] Add missing exports. --- coreapi/linphonecore.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4ef4b6a4f..b1ca5f577 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1088,7 +1088,7 @@ LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); /* returns a MSList of PayloadType */ -const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); @@ -1351,21 +1351,21 @@ LINPHONE_PUBLIC void linphone_core_reset_missed_calls_count(LinphoneCore *lc); 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); 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); +LINPHONE_PUBLIC bool_t linphone_core_video_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); +LINPHONE_PUBLIC const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); +LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name); void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); @@ -1376,9 +1376,9 @@ bool_t linphone_core_self_view_enabled(const 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); From a3a0aac3bffca52135479ca25403d0d8345d9c25 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 22 May 2013 09:50:17 +0200 Subject: [PATCH 380/909] Add some more missing exports. --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b1ca5f577..ebfdaa1b5 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -438,8 +438,8 @@ LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); -void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); -bool_t linphone_call_camera_enabled(const LinphoneCall *lc); +LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); +LINPHONE_PUBLIC bool_t linphone_call_camera_enabled(const LinphoneCall *lc); int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call); From 7db7fbe3c20a2ae7ec237b6da6c5d9852e781d1c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 22 May 2013 15:51:23 +0200 Subject: [PATCH 381/909] Add exception to LinphoneFactory.createAddress --- java/common/org/linphone/core/LinphoneCoreFactory.java | 3 ++- java/impl/org/linphone/core/LinphoneAddressImpl.java | 5 ++++- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 5e8637999..88aa4343f 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -81,8 +81,9 @@ abstract public class LinphoneCoreFactory { * Constructs a LinphoneAddress object by parsing the user supplied address, given as a string. * @param address should be like sip:joe@sip.linphone.org * @return + * @throws LinphoneCoreException if address cannot be parsed */ - abstract public LinphoneAddress createLinphoneAddress(String address); + abstract public LinphoneAddress createLinphoneAddress(String address) throws LinphoneCoreException; abstract public LpConfig createLpConfig(String file); abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException; diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index 000ae52ab..66bfa085f 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -34,8 +34,11 @@ public class LinphoneAddressImpl implements LinphoneAddress { private native void setUserName(long ptr,String username); 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) { diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 8cedba445..d1bef5bf6 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -102,7 +102,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @Override - public LinphoneAddress createLinphoneAddress(String identity) { + public LinphoneAddress createLinphoneAddress(String identity) throws LinphoneCoreException { return new LinphoneAddressImpl(identity); } From 53d4d1b7f8bcd5b604011dafef37224c1751bfc4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 May 2013 17:01:06 +0200 Subject: [PATCH 382/909] add transfer_state_changed callback to JNI/java info api wrapping in progress --- .../core/tutorials/TutorialBuddyStatus.java | 7 +++ .../core/tutorials/TutorialChatRoom.java | 7 +++ .../core/tutorials/TutorialHelloWorld.java | 7 +++ .../core/tutorials/TutorialRegistration.java | 7 +++ coreapi/linphonecore_jni.cc | 45 +++++++++++++++++- .../org/linphone/core/LinphoneCall.java | 6 +++ .../org/linphone/core/LinphoneContent.java | 46 ++++++++++++++++++ .../org/linphone/core/LinphoneCore.java | 14 ++++++ .../linphone/core/LinphoneCoreListener.java | 7 +++ .../linphone/core/LinphoneInfoMessage.java | 36 ++++++++++++++ .../org/linphone/core/LinphoneCallImpl.java | 5 ++ .../linphone/core/LinphoneContentImpl.java | 46 ++++++++++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 11 +++++ .../core/LinphoneInfoMessageImpl.java | 47 +++++++++++++++++++ 14 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 java/common/org/linphone/core/LinphoneContent.java create mode 100644 java/common/org/linphone/core/LinphoneInfoMessage.java create mode 100644 java/impl/org/linphone/core/LinphoneContentImpl.java create mode 100644 java/impl/org/linphone/core/LinphoneInfoMessageImpl.java diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index dc1341d80..5bd39d03b 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -241,5 +241,12 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 024927468..0c5edda7e 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -163,5 +163,12 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa write("Sent message [" + msg.getText() + "] new state is " + state.toString()); } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index d6b61cf8b..bf5421d6d 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -167,5 +167,12 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index fa18d51f8..89e53f5c5 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -198,6 +198,13 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 1ff08e0a3..0701f1f37 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -139,6 +139,7 @@ public: vTable.new_subscription_request = new_subscription_request; vTable.notify_presence_recv = notify_presence_recv; vTable.call_stats_updated = callStatsUpdated; + vTable.transfer_state_changed = transferStateChanged; listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); @@ -160,6 +161,8 @@ public: callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State")); callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;"); + transferStateId = env->GetMethodID(listenerClass,"transferState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;)V"); + /*callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);*/ callStatsUpdatedId = env->GetMethodID(listenerClass, "callStatsUpdated", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCallStats;)V"); @@ -240,6 +243,7 @@ public: jmethodID messageReceivedId; jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; + jmethodID transferStateId; jclass globalStateClass; jmethodID globalStateId; @@ -499,7 +503,22 @@ public: env->CallVoidMethod(callobj, lcData->callSetVideoStatsId, statsobj); env->CallVoidMethod(lcData->listener, lcData->callStatsUpdatedId, lcData->core, callobj, statsobj); } - + static void transferStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState remote_call_state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jcall; + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->transferStateId + ,lcData->core + ,(jcall=lcData->getCall(env,call)) + ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)remote_call_state) + ); + } }; extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env @@ -545,6 +564,19 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env delete lcData; } +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: createInfoMessage + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneCoreImpl_createInfoMessage(JNIEnv *, jobject jobj, jlong lcptr){ + return (jlong) linphone_core_create_info_message((LinphoneCore*)lcptr); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_sendInfoMessage(JNIEnv *env, jobject jobj, jlong lcptr, jlong infoptr, jlong addrptr){ + return linphone_core_send_info_message((LinphoneCore*)lcptr,(LinphoneInfoMessage*)infoptr,(LinphoneAddress*)addrptr); +} + 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); @@ -1694,6 +1726,17 @@ 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); +} + extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoCancellation( JNIEnv* env ,jobject thiz ,jlong ptr diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 893572e2e..3328b2959 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -292,4 +292,10 @@ 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(); } diff --git a/java/common/org/linphone/core/LinphoneContent.java b/java/common/org/linphone/core/LinphoneContent.java new file mode 100644 index 000000000..b3811006f --- /dev/null +++ b/java/common/org/linphone/core/LinphoneContent.java @@ -0,0 +1,46 @@ +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 data as a string. + * @return the data + */ + String getDataAsString(); + /** + * Get the data size. + * @return the data size. + */ + int getSize(); + + /** + * Set the content type, for example "application" + * @param type the content's primary type + */ + void setType(String type); + /** + * Set the subtype, for example "text" + * @param subtype the subtype + */ + void setSubtype(String subtype); + /** + * Set the data, supplied as String. + * @param data the data + */ + void setStringData(String data); +} diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index d76acad9a..c3c26e946 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1259,5 +1259,19 @@ public interface LinphoneCore { * the external ip address is not available return null. */ public String getUpnpExternalIpaddress(); + + /** + * Create an empty INFO message. + * It can later be sent using {@link LinphoneCore.sendInfoMessage() }. + * @return the new info message. + */ + public LinphoneInfoMessage createInfoMessage(); + + /** + * Send an INFO message to specified destination. + * @param info the info message + * @param dest the destination sip address. + */ + public void sendInfoMessage(LinphoneInfoMessage info, LinphoneAddress dest); } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 740bdc29c..d8487c69a 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -117,6 +117,13 @@ 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); /**< @Deprecated Notifies the application that it should show up * @return */ diff --git a/java/common/org/linphone/core/LinphoneInfoMessage.java b/java/common/org/linphone/core/LinphoneInfoMessage.java new file mode 100644 index 000000000..93ee6a7ec --- /dev/null +++ b/java/common/org/linphone/core/LinphoneInfoMessage.java @@ -0,0 +1,36 @@ +package org.linphone.core; + +/** + * The LinphoneInfoMessage represents an informational message (INFO) to be transmitted or received by the LinphoneCore. + * @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); + /** + * Get the origin of the info message as a string URI. + * @return origin of the message. + */ + String getFrom(); +} diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 041acaef2..afe0afc00 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -207,4 +207,9 @@ class LinphoneCallImpl implements LinphoneCall { public void stopRecording() { stopRecording(nativePtr); } + private native int getTransferState(long nativePtr); + @Override + public State getTransferState() { + return State.fromInt(getTransferState(nativePtr)); + } } diff --git a/java/impl/org/linphone/core/LinphoneContentImpl.java b/java/impl/org/linphone/core/LinphoneContentImpl.java new file mode 100644 index 000000000..f74711042 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneContentImpl.java @@ -0,0 +1,46 @@ +package org.linphone.core; + +public class LinphoneContentImpl implements LinphoneContent { + private String mType, mSubtype, mData; + public LinphoneContentImpl(String type, String subtype, String data){ + mType=type; + mSubtype=subtype; + mData=data; + } + + @Override + public String getType() { + return mType; + } + + @Override + public String getSubtype() { + return mSubtype; + } + + @Override + public String getDataAsString() { + return mData; + } + + @Override + public int getSize() { + return mData.length(); + } + + @Override + public void setType(String type) { + mType=type; + } + + @Override + public void setSubtype(String subtype) { + mSubtype=subtype; + } + + @Override + public void setStringData(String data) { + mData=data; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f9a7abf39..a414baf7a 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -948,4 +948,15 @@ class LinphoneCoreImpl implements LinphoneCore { public int getVideoDscp() { return getVideoDscp(nativePtr); } + + private native long createInfoMessage(long nativeptr); + @Override + public LinphoneInfoMessage createInfoMessage() { + return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); + } + private native int sendInfoMessage(long corePtr, long infoptr, long destptr); + @Override + public void sendInfoMessage(LinphoneInfoMessage info, LinphoneAddress dest) { + sendInfoMessage(nativePtr,((LinphoneInfoMessageImpl)info).nativePtr, ((LinphoneAddressImpl)dest).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..604fbc961 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java @@ -0,0 +1,47 @@ +package org.linphone.core; + +public class LinphoneInfoMessageImpl implements LinphoneInfoMessage { + protected long nativePtr; + private LinphoneContent mContent; + + private native Object getContent(long nativeptr); + 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 String getFrom(long nativePtr); + @Override + public String getFrom() { + return getFrom(nativePtr); + } + + private native void delete(long nativePtr); + protected void finalize(){ + delete(nativePtr); + } +} From 53128dec9d7d558ceb2ddc5d90777a32e4b08bbc Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 22 May 2013 17:40:26 +0200 Subject: [PATCH 383/909] avoid crash with op->auth_info --- coreapi/bellesip_sal/sal_impl.c | 14 ++++++-------- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/callbacks.c | 6 +++--- mediastreamer2 | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 1609703a4..91c004962 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -363,14 +363,12 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { - SalAuthInfo auth_info; - memset(&auth_info,0,sizeof(SalAuthInfo)); - auth_info.username=(char*)belle_sip_auth_event_get_username(auth_event); - auth_info.realm=(char*)belle_sip_auth_event_get_realm(auth_event); - ((Sal*)sal)->callbacks.auth_requested(sal,&auth_info); - belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info.password); - belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info.ha1); - belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info.userid); + SalAuthInfo* auth_info = sal_auth_info_create(auth_event); + ((Sal*)sal)->callbacks.auth_requested(sal,auth_info); + belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info->password); + belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info->ha1); + belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info->userid); + sal_auth_info_delete(auth_info); return; } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 5683568b4..87eec5fcb 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -70,7 +70,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher sal_add_pending_auth(op->base.root,op); if (status_code == 403) { /*in sase of 401 or 407, auth requested already invoked previouly*/ /*auth previouly pending, probably wrong pasword, give a chance to authenticate again*/ - op->base.root->callbacks.auth_failure(op,op->auth_info); + op->base.root->callbacks.auth_failure(op,op->auth_info); /*fixme*/ } } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 0f977b911..08e7cf550 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -906,9 +906,9 @@ static void ping_reply(SalOp *op){ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); if (ai) { - sai->userid=ai->userid?ai->userid:ai->username; - sai->password=ai->passwd; - sai->ha1=ai->ha1; + sai->userid=ms_strdup(ai->userid?ai->userid:ai->username); + sai->password=ai->passwd?ms_strdup(ai->passwd):NULL; + sai->ha1=ai->ha1?ms_strdup(ai->ha1):NULL; ai->usecount++; ai->last_use_time=ms_time(NULL); return TRUE; diff --git a/mediastreamer2 b/mediastreamer2 index 3f06cd60f..c898f5af0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3f06cd60f1864b8c811e0f4e4590991802ce5ea7 +Subproject commit c898f5af06498ea9c6848e4342fab65cd4adcc4f From 31c41234be71e404078ccbd02bcb73cc4d83b9dc Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Wed, 22 May 2013 22:58:08 +0200 Subject: [PATCH 384/909] AAC-ELD: support PLC and multiple frames per RTP packet and fix uninit to free the audio converter. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3f2672fcf..6e4adda46 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3f2672fcf8a8d8f951047844d38dca1631999d7e +Subproject commit 6e4adda46186fdb197a6bca1dd7097b313fff09d From 02d7587c285847d80c0879ac0cfb3f1b329f19ee Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 23 May 2013 11:52:29 +0200 Subject: [PATCH 385/909] AAC-ELD : set an initial max ptime at 50ms - to avoid ptime automatic growing too high when packets are losts - setting overridden up to 100 by initial set ptime --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6e4adda46..58745e586 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6e4adda46186fdb197a6bca1dd7097b313fff09d +Subproject commit 58745e5866d325c07255bf34225c8b621e87870b From 1939dd72cec0d200e0ca50f99f61ac900185c249 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 23 May 2013 13:21:34 +0200 Subject: [PATCH 386/909] finished java wrapping of info API, and add loghandler java implementation --- .../core/tutorials/TutorialBuddyStatus.java | 7 + .../core/tutorials/TutorialChatRoom.java | 7 + .../core/tutorials/TutorialHelloWorld.java | 7 + .../core/tutorials/TutorialRegistration.java | 7 + coreapi/info.c | 11 +- coreapi/linphonecore.h | 2 + coreapi/linphonecore_jni.cc | 172 ++++++++++++++++-- .../linphone/core/LinphoneCoreFactory.java | 5 +- .../linphone/core/LinphoneCoreListener.java | 7 + .../org/linphone/core/LinphoneLogHandler.java | 8 +- .../core/LinphoneCoreFactoryImpl.java | 11 +- .../core/LinphoneInfoMessageImpl.java | 2 +- 12 files changed, 224 insertions(+), 22 deletions(-) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index 5bd39d03b..a65e0528c 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -29,6 +29,7 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.OnlineStatus; import org.linphone.core.LinphoneCall.State; @@ -248,5 +249,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 0c5edda7e..e64750122 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -32,6 +32,7 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; @@ -170,5 +171,11 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } + @Override + public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index bf5421d6d..ea659e60b 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -29,6 +29,7 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; @@ -174,5 +175,11 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 89e53f5c5..c8a827511 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -29,6 +29,7 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; @@ -205,6 +206,12 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/info.c b/coreapi/info.c index 6ab5f5837..961fa0b04 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -102,6 +102,15 @@ void linphone_info_message_destroy(LinphoneInfoMessage *im){ ms_free(im); } + +LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig){ + LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); + linphone_content_copy(&im->content,&orig->content); + if (orig->headers) im->headers=sal_custom_header_clone(orig->headers); + if (orig->op) im->op=sal_op_ref(orig->op); + return im; +} + /** * Creates an empty info message. * @param lc the LinphoneCore object. @@ -152,7 +161,7 @@ const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, cons /** * Returns origin of received LinphoneInfoMessage **/ -const char *linphone_info_message_get_from(LinphoneInfoMessage *im){ +const char *linphone_info_message_get_from(const LinphoneInfoMessage *im){ return sal_op_get_from(im->op); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ebfdaa1b5..e363192ac 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -250,7 +250,9 @@ LINPHONE_PUBLIC void linphone_info_message_add_header(LinphoneInfoMessage *im, c LINPHONE_PUBLIC const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, const char *name); LINPHONE_PUBLIC void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content); LINPHONE_PUBLIC const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im); +LINPHONE_PUBLIC const char *linphone_info_message_get_from(const LinphoneInfoMessage *im); LINPHONE_PUBLIC void linphone_info_message_destroy(LinphoneInfoMessage *im); +LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig); /** * Enum describing failure reasons. diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 0701f1f37..85dd369d5 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -52,15 +52,15 @@ extern "C" void libmsbcg729_init(); static JavaVM *jvm=0; static const char* LogDomain = "Linphone"; +static jclass handler_class; +static jmethodID loghandler_id; +static jobject handler_obj=NULL; #ifdef ANDROID -void linphone_android_log_handler(int prio, const char *fmt, va_list args) { - char str[4096]; +void linphone_android_log_handler(int prio, char *str) { char *current; char *next; - vsnprintf(str, sizeof(str) - 1, fmt, args); - str[sizeof(str) - 1] = '\0'; if (strlen(str) < 512) { __android_log_write(prio, LogDomain, str); } else { @@ -75,16 +75,25 @@ void linphone_android_log_handler(int prio, const char *fmt, va_list args) { } static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + char str[4096]; + const char *levname="undef"; + vsnprintf(str, sizeof(str) - 1, fmt, args); + str[sizeof(str) - 1] = '\0'; + int prio; switch(lev){ - case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; break; - case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; break; - case ORTP_WARNING: prio = ANDROID_LOG_WARN; break; - case ORTP_ERROR: prio = ANDROID_LOG_ERROR; break; - case ORTP_FATAL: prio = ANDROID_LOG_FATAL; break; - default: prio = ANDROID_LOG_DEFAULT; break; + case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; levname="debug"; break; + case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; levname="message"; break; + case ORTP_WARNING: prio = ANDROID_LOG_WARN; levname="warning"; break; + case ORTP_ERROR: prio = ANDROID_LOG_ERROR; levname="error"; break; + case ORTP_FATAL: prio = ANDROID_LOG_FATAL; levname="fatal"; break; + default: prio = ANDROID_LOG_DEFAULT; break; } - linphone_android_log_handler(prio, fmt, args); + if (handler_obj){ + JNIEnv *env=ms_get_jni_env(); + env->CallVoidMethod(handler_obj,loghandler_id,env->NewStringUTF(LogDomain),(jint)lev,env->NewStringUTF(levname),env->NewStringUTF(str),NULL); + }else + linphone_android_log_handler(prio, str); } int dumbMethodForAllowingUsageOfCpuFeaturesFromStaticLibMediastream() { @@ -140,6 +149,7 @@ public: vTable.notify_presence_recv = notify_presence_recv; vTable.call_stats_updated = callStatsUpdated; vTable.transfer_state_changed = transferStateChanged; + vTable.info_received = infoReceived; listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); @@ -187,6 +197,7 @@ public: textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); + infoReceivedId = env->GetMethodID(listenerClass,"infoReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneInfoMessage;)V"); proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -210,6 +221,9 @@ public: callStatsId = env->GetMethodID(callStatsClass, "", "(JJ)V"); callSetAudioStatsId = env->GetMethodID(callClass, "setAudioStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); callSetVideoStatsId = env->GetMethodID(callClass, "setVideoStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); + + infoMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneInfoMessageImpl")); + infoMessageCtor = env->GetMethodID(infoMessageClass,"", "(J)V"); } ~LinphoneCoreData() { @@ -222,14 +236,13 @@ public: env->DeleteGlobalRef(globalStateClass); env->DeleteGlobalRef(registrationStateClass); env->DeleteGlobalRef(callStateClass); - env->DeleteGlobalRef(callStatsClass); env->DeleteGlobalRef(chatMessageStateClass); env->DeleteGlobalRef(proxyClass); env->DeleteGlobalRef(callClass); env->DeleteGlobalRef(chatMessageClass); env->DeleteGlobalRef(chatRoomClass); env->DeleteGlobalRef(friendClass); - + env->DeleteGlobalRef(infoMessageClass); } jobject core; jobject listener; @@ -244,6 +257,7 @@ public: jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; jmethodID transferStateId; + jmethodID infoReceivedId; jclass globalStateClass; jmethodID globalStateId; @@ -288,6 +302,9 @@ public: jclass addressClass; jmethodID addressCtrId; + + jclass infoMessageClass; + jmethodID infoMessageCtor; LinphoneCoreVTable vTable; @@ -519,6 +536,22 @@ public: ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)remote_call_state) ); } + static void infoReceived(LinphoneCore *lc, const LinphoneInfoMessage *info){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jcall; + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + LinphoneInfoMessage *copy_info=linphone_info_message_copy(info); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->infoReceivedId + ,lcData->core + ,env->NewObject(lcData->infoMessageClass,lcData->infoMessageCtor,(jlong)copy_info) + ); + } }; extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env @@ -2588,3 +2621,116 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setInt(JNIEnv *env, jobject env->ReleaseStringUTFChars(key, ckey); } +static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content){ + jclass contentClass; + jmethodID ctor; + jstring jtype, jsubtype, jdata; + + contentClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneContentImpl")); + ctor = env->GetMethodID(contentClass,"", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + + jtype=env->NewStringUTF(content->type); + jsubtype=env->NewStringUTF(content->subtype); + jdata=content->data ? env->NewStringUTF((const char*)content->data) : NULL; + jobject jobj=env->NewObject(contentClass,ctor,jtype, jsubtype, jdata); + + env->DeleteGlobalRef(contentClass); + return jobj; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: getContent + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getContent(JNIEnv *env, jobject jobj, jlong infoptr){ + const LinphoneContent *content=linphone_info_message_get_content((LinphoneInfoMessage*)infoptr); + if (content){ + return create_java_linphone_content(env,content); + } + return NULL; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: setContent + * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_setContent(JNIEnv *env, jobject jobj, jlong infoptr, jstring jtype, jstring jsubtype, jstring jdata){ + const char *type,*subtype,*data; + LinphoneContent content; + + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + linphone_info_message_set_content((LinphoneInfoMessage*)infoptr,&content); + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: addHeader + * Signature: (JLjava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_addHeader(JNIEnv *env, jobject jobj, jlong infoptr, jstring jname, jstring jvalue){ + const char *name=NULL,*value=NULL; + name=env->GetStringUTFChars(jname,NULL); + value=env->GetStringUTFChars(jvalue,NULL); + linphone_info_message_add_header((LinphoneInfoMessage*)infoptr,name,value); + env->ReleaseStringUTFChars(jname,name); + env->ReleaseStringUTFChars(jvalue,value); +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: getHeader + * Signature: (JLjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getHeader(JNIEnv *env, jobject jobj, jlong infoptr, jstring jname){ + const char *name=name=env->GetStringUTFChars(jname,NULL); + const char *ret=linphone_info_message_get_header((LinphoneInfoMessage*)infoptr,name); + env->ReleaseStringUTFChars(jname,name); + return ret ? env->NewStringUTF(ret) : NULL; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: getFrom + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getFrom(JNIEnv *env , jobject jobj, jlong infoptr){ + const char *from=linphone_info_message_get_from((LinphoneInfoMessage*)infoptr); + return from ? env->NewStringUTF(from) : 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); + } +} + + diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 88aa4343f..281d89e46 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -107,5 +107,8 @@ abstract public class LinphoneCoreFactory { */ abstract public LinphoneFriend createLinphoneFriend(); - + /** + * Create a LinphoneContent object + */ + abstract public LinphoneContent createLinphoneContent(String type, String subType, String data); } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index d8487c69a..1d85a07ca 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -125,6 +125,13 @@ public interface LinphoneCoreListener { **/ 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, LinphoneInfoMessage info); + /**< @Deprecated Notifies the application that it should show up * @return */ void show(LinphoneCore lc); 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/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index d1bef5bf6..b3c638b68 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -140,10 +140,11 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public native void setDebugMode(boolean enable, String tag); + + private native void _setLogHandler(Object handler); @Override public void setLogHandler(LinphoneLogHandler handler) { - //not implemented on Android - + _setLogHandler(handler); } @Override @@ -172,4 +173,10 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { String passwd, String ha1, String realm) { return new LinphoneAuthInfoImpl(username,userid,passwd,ha1,realm); } + + @Override + public LinphoneContent createLinphoneContent(String type, String subType, + String data) { + return new LinphoneContentImpl(type,subType,data); + } } diff --git a/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java index 604fbc961..06c31dd42 100644 --- a/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java @@ -4,7 +4,7 @@ public class LinphoneInfoMessageImpl implements LinphoneInfoMessage { protected long nativePtr; private LinphoneContent mContent; - private native Object getContent(long nativeptr); + private native Object getContent(long infoptr); public LinphoneInfoMessageImpl(long ptr){ nativePtr=ptr; mContent=(LinphoneContent)getContent(nativePtr); From 2391436cd284e92fac24c482f052149812b88d42 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 23 May 2013 14:37:52 +0200 Subject: [PATCH 387/909] add option to allow to set contact in MESSAGE requests (specific for a SIP server) --- coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 20 ++------------------ coreapi/bellesip_sal/sal_op_message.c | 3 +++ coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/chat.c | 2 +- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 59d1729e9..2a6f50cc5 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -115,7 +115,7 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code); void sal_process_authentication(SalOp *op); -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) ; +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ; bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 90f616545..77cff3577 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -79,23 +79,7 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna return 0; } -/* -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op, belle_sip_header_from_t* from_header) { - belle_sip_uri_t* req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)from_header)); - belle_sip_header_contact_t* contact_header; - 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(); - belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,belle_sip_uri_new()); - belle_sip_uri_set_user(belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact_header),belle_sip_uri_get_user(req_uri)); - } - belle_sip_object_unref(req_uri); - return contact_header; -} -*/ - -belle_sip_header_contact_t* sal_op_create_contact(SalOp *op, belle_sip_header_from_t* from_header){ +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ belle_sip_header_contact_t* contact_header; if (sal_op_get_contact_address(op)) { contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); @@ -235,7 +219,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); if (add_contact) { - contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t)); + contact = sal_op_create_contact(op); belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 96ce30d8b..08eef45c7 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -138,6 +138,9 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co sal_op_set_to(op,to); op->dir=SalOpDirOutgoing; req=sal_op_build_request(op,"MESSAGE"); + if (sal_op_get_contact(op)){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); + } snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 87eec5fcb..58f1dc634 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -91,7 +91,7 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ time_t curtime=time(NULL); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); } - belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op,NULL)); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op)); return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); } diff --git a/coreapi/chat.c b/coreapi/chat.c index 15f380c0f..8dbd60f75 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -93,7 +93,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM }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,msg->custom_headers,FALSE); + 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->external_body_url) { From 169cbaac09cc0656c46869ae7455d9159675bfcc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 May 2013 15:20:30 +0200 Subject: [PATCH 388/909] Add check to prevent crash. --- tester/call_tester.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index aff361f20..a5d05e0e4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -419,13 +419,15 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee CU_ASSERT_PTR_NOT_NULL(c2); for (i=0;i<200;i++){ - if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && - linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ - success=TRUE; - break; + if ((c1 != NULL) && (c2 != NULL)) { + if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && + linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ + success=TRUE; + break; + } + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); } - linphone_core_iterate(caller->lc); - linphone_core_iterate(callee->lc); ms_usleep(50000); } return success; From 0408a776e46c1f8ddffc8e26eeaf6ffe7d726bcb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 May 2013 15:21:37 +0200 Subject: [PATCH 389/909] Load user DNS hosts file for tests. --- coreapi/bellesip_sal/sal_impl.c | 8 ++++++++ include/sal/sal.h | 4 +++- tester/liblinphone_tester.c | 11 +++++++++-- tester/tester_hosts | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tester/tester_hosts diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 91c004962..960a50254 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -683,6 +683,14 @@ int sal_get_dns_timeout(const Sal* sal) { return belle_sip_stack_get_dns_timeout(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)) ; diff --git a/include/sal/sal.h b/include/sal/sal.h index 38610ac35..051f06482 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -569,5 +569,7 @@ void sal_nat_helper_enable(Sal *sal,bool_t enable); bool_t sal_nat_helper_enabled(Sal *sal); LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); -int sal_get_dns_timeout(const Sal* sal); +LINPHONE_PUBLIC int sal_get_dns_timeout(const Sal* sal); +LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); +LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); #endif diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 185ce9587..1bd9e0ff7 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -47,6 +47,8 @@ const char *liblinphone_tester_file_prefix="Assets"; const char *liblinphone_tester_file_prefix="./tester"; #endif +const char *userhostsfile = "tester_hosts"; + #ifdef ANDROID extern void AndroidPrintf(FILE *stream, const char *fmt, ...); #define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) @@ -109,16 +111,21 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c char ringpath[256]; char ringbackpath[256]; char rootcapath[256]; + char dnsuserhostspath[256]; + sprintf(filepath, "%s/%s", path, file); lc = linphone_core_new(v_table,NULL,filepath,NULL); linphone_core_set_user_data(lc,&global_stat); counters = (stats*)linphone_core_get_user_data(lc); - + /* until we have good certificates on our test server... linphone_core_verify_server_certificates(lc,FALSE);*/ sprintf(rootcapath, "%s/certificates/cacert.pem", path); linphone_core_set_root_ca(lc,rootcapath); - + + sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); + sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + sprintf(ringpath, "%s/%s", path, "oldphone.wav"); sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); linphone_core_set_ring(lc, ringpath); diff --git a/tester/tester_hosts b/tester/tester_hosts new file mode 100644 index 000000000..9cd7f20f4 --- /dev/null +++ b/tester/tester_hosts @@ -0,0 +1 @@ +127.0.0.1 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org From f7d031a6e912e1c9437664cbaaf37b00198880d5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 23 May 2013 15:53:29 +0200 Subject: [PATCH 390/909] Use sip2.linphone.org instead of localhost for SIP server. --- tester/tester_hosts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/tester_hosts b/tester/tester_hosts index 9cd7f20f4..b5ffa240a 100644 --- a/tester/tester_hosts +++ b/tester/tester_hosts @@ -1 +1 @@ -127.0.0.1 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org +37.59.129.74 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org From ffddcbca0467970851ec4c57ded46a1dda8e5fae Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 24 May 2013 10:36:22 +0200 Subject: [PATCH 391/909] update ms2&ortp to support opus --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 58745e586..f0c613987 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 58745e5866d325c07255bf34225c8b621e87870b +Subproject commit f0c61398705609e28cbcb82f4c650ebd16ec0917 diff --git a/oRTP b/oRTP index 2d8a82247..68bdfc201 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2d8a82247fbebbd690ae2fc8300522ab9b71a542 +Subproject commit 68bdfc20122f0231c6853e3b4b9a07e57955ad76 From a8ff9df9a18d57fc48167cf9f50cde685841ac00 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 May 2013 10:55:41 +0200 Subject: [PATCH 392/909] ready for release --- NEWS | 22 ++++++++++++++++++++-- README | 31 +++++++++++++++---------------- mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 413970e6a..0eede9fa5 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,24 @@ -linphone-3.xxx -- +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 1a66f4a27..a1fb5bd3d 100644 --- a/README +++ b/README @@ -8,29 +8,35 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - intltool - you need at least: - - libosip2>=3.0.3 - - libeXosip2>=3.0.3 + - libosip2>=3.5.0 + - libeXosip2>=3.5.0 - speex>=1.2.0 (including libspeexdsp part) + if you want the gtk/glade interface: - libgtk >=2.16.0 + if you want video support: - - SDL>=1.2.10 + - libvpx (VP8 codec) - libavcodec (ffmpeg) - libswscale (part of ffmpeg too) for better scaling performance - libxv (x11 video extension) - - ligl1-mesa (OpenGL API -- GLX development files) - - libglew (OpenGL Extension Wrangler library) - - libv4l (Video for linux) - - libx11 (x11) + - ligl1-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) + libsoup (optional: for wizard - account creation assistant) - + libsqlite3 (optional : for a local history of messages) + + 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 libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libvx-dev ligl1-mesa-dev libglew-dev libv4l-dev + + + for optional library + $ sudo apt-get install libreadline-dev liggsm1-dev libtheora-dev libsoup2.4-dev libsqlit3-dev libupnp6-dev + Install srtp (optional) for call encryption : $ git clone git://git.linphone.org/srtp.git @@ -43,7 +49,6 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make $ sudo make install -with their corresponding -dev or -devel package if you don't use source packages. - Compile linphone @@ -52,13 +57,7 @@ with their corresponding -dev or -devel package if you don't use source packages $ make && sudo make install $ sudo ldconfig -- Command line for Ubuntu && Debian - $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libvx-dev ligl1-mesa-dev libglew-dev libv4l-dev - - + for optional library - $ sudo apt-get install libreadline-dev liggsm1-dev libtheora-dev libsoup2.4-dev libsqlit3-dev libupnp6-dev - For windows compilation see README.mingw. For macOS X, see README.macos diff --git a/mediastreamer2 b/mediastreamer2 index f0c613987..2b43ce538 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f0c61398705609e28cbcb82f4c650ebd16ec0917 +Subproject commit 2b43ce538299df8d9bc9d8f37de5f74a05342792 diff --git a/oRTP b/oRTP index 68bdfc201..2c37d1205 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 68bdfc20122f0231c6853e3b4b9a07e57955ad76 +Subproject commit 2c37d1205e9dd0e30a918ccf666ab217b66c2899 From 9287b6f4afb5346571b95ab75f60d6b131cf5b24 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 24 May 2013 11:04:37 +0200 Subject: [PATCH 393/909] fix ms2 version for opus --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2b43ce538..ef59e9370 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2b43ce538299df8d9bc9d8f37de5f74a05342792 +Subproject commit ef59e93709972e8e7ed1a4b642f0c113b575916f From e0eb19e8c024ec70ce5bcc20fc983175beb13adc Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Fri, 24 May 2013 13:28:47 +0200 Subject: [PATCH 394/909] Add fmtp parameters to opus payload to enable FEC and DTX - update ms2 to get opus filter with locks on ptime --- coreapi/linphonecore.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f4e5536ed..f0963f904 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1288,7 +1288,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); - linphone_core_assign_payload_type(lc,&payload_type_opus,-1,NULL); + linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=1"); linphone_core_handle_static_payloads(lc); ms_init(); diff --git a/mediastreamer2 b/mediastreamer2 index ef59e9370..2278eb3fc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ef59e93709972e8e7ed1a4b642f0c113b575916f +Subproject commit 2278eb3fca4601bd5911f1fe9585d0a3f643f965 From fa1787b3708aa2b4bf116013a40da1bbc8913e93 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 May 2013 16:11:47 +0200 Subject: [PATCH 395/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2278eb3fc..f8ca60656 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2278eb3fca4601bd5911f1fe9585d0a3f643f965 +Subproject commit f8ca6065676eff95752d546e387684ccc90e7b1e From 5e8f0d1ca3cda7358668d949cd92ef51d84783d3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 May 2013 16:13:39 +0200 Subject: [PATCH 396/909] fix OPTION to be OPTIONS add allow header in 200Ok for INVITE --- coreapi/bellesip_sal/sal_op_call.c | 12 +++++++++--- coreapi/bellesip_sal/sal_op_impl.c | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 76ea05782..dd7ede609 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -523,10 +523,15 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ op->base.local_media=desc; return 0; } -static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { + +static belle_sip_header_allow_t *create_allow(){ belle_sip_header_allow_t* header_allow; - header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(header_allow)); + header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + return header_allow; +} + +static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow())); if (op->base.root->session_expires!=0){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200")); @@ -630,6 +635,7 @@ int sal_call_accept(SalOp*h){ ms_error("Fail to build answer for call"); return -1; } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow())); if (h->base.root->session_expires!=0){ if (h->supports_session_timers) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer")); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 77cff3577..7e24389fb 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -130,7 +130,7 @@ belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_r 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,"OPTION")); + 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) { @@ -241,7 +241,7 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { 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),"OPTION")==0) + ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0) need_contact=TRUE; return _sal_op_send_request_with_contact(op, request,need_contact); From 3668dba1a9126b67ad644379bd16457a2678a3db Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Fri, 24 May 2013 16:18:11 +0200 Subject: [PATCH 397/909] Update README.mingw for sqlite3 building --- README.mingw | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.mingw b/README.mingw index 42b130f33..be45614f2 100644 --- a/README.mingw +++ b/README.mingw @@ -136,11 +136,21 @@ 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. +- 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 @@ -152,6 +162,7 @@ When running "make install DESTDIR=", somepath must be absolute and sh ./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: From 0badecdad0305c367cca5ef282623e3444a0031a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 May 2013 17:59:24 +0200 Subject: [PATCH 398/909] ready for 3.6 release --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5bd0570cc..0fcf38fc9 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.6.0],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) From 92f4fafe9e202bc4e3fb4d540d25d3d4061e48b6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Nov 2012 16:12:35 +0100 Subject: [PATCH 399/909] Add opus codec. --- coreapi/linphonecore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 92c7ce296..56ffe60d2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -838,6 +838,7 @@ typedef struct codec_desc{ }codec_desc_t; static codec_desc_t codec_pref_order[]={ + {"opus", 48000}, {"SILK", 16000}, {"speex", 16000}, {"speex", 8000}, @@ -1311,6 +1312,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_opus,-1,NULL); linphone_core_handle_static_payloads(lc); ms_init(); From c0336c8597c49a12517a09df5b208134a3a949be Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 May 2013 15:02:49 +0200 Subject: [PATCH 400/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c898f5af0..3b8361ed5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c898f5af06498ea9c6848e4342fab65cd4adcc4f +Subproject commit 3b8361ed57acccce823c500bd7a2145099d7678b From c223c2f8c0760c33327609da23a9bb524acbd139 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 24 May 2013 10:50:14 +0200 Subject: [PATCH 401/909] fix case where auth is present but there neither passwd nor ha1 --- coreapi/bellesip_sal/sal_op_registration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 58f1dc634..d4226ef3f 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -68,7 +68,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); - if (status_code == 403) { /*in sase of 401 or 407, auth requested already invoked previouly*/ + if (status_code == 403 || status_code == 401 || status_code == 407) { /*in case of 401 or 407, auth requested already invoked previously but maybe*/ /*auth previouly pending, probably wrong pasword, give a chance to authenticate again*/ op->base.root->callbacks.auth_failure(op,op->auth_info); /*fixme*/ } From c4767963941bbb5f31f63a1b96c883edbcc5b157 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 27 May 2013 08:55:01 +0200 Subject: [PATCH 402/909] update ortp --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 1a103971b..2c37d1205 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 1a103971b84d39510ad14f327bd6834b3d88063f +Subproject commit 2c37d1205e9dd0e30a918ccf666ab217b66c2899 From 0bd44b5c3a1469741b8cdf6856cab212a7574f58 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 27 May 2013 10:47:45 +0200 Subject: [PATCH 403/909] add missing sqlite dll --- linphone-deps.filelist | 1 + 1 file changed, 1 insertion(+) diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 1df0777a6..7eef0eea5 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -14,3 +14,4 @@ ./bin/libgpg-error-0.dll ./bin/libgnutls-26.dll ./bin/libtasn1-3.dll +./bin/libsqlite3-0.dll From 74844e0448889d4a5a4cc06de26f8895a78e8ea3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 27 May 2013 12:24:16 +0200 Subject: [PATCH 404/909] add alias parameter in via for Registers add declarations for new SUBSCRIBE/NOTIFY/PUBLISH api --- coreapi/bellesip_sal/sal_op_impl.c | 6 ++ coreapi/event.h | 125 +++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 coreapi/event.h diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 7e24389fb..78957f2af 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -207,6 +207,12 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } belle_sip_uri_fix(next_hop_uri); } + if (strcmp(belle_sip_request_get_method(request),"REGISTER")==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); diff --git a/coreapi/event.h b/coreapi/event.h new file mode 100644 index 000000000..68417a846 --- /dev/null +++ b/coreapi/event.h @@ -0,0 +1,125 @@ +/* +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 + +struct _LinphoneEvent; + +typedef struct _LinphoneEvent LinphoneEvent; + +/** + * Enum for subscription direction (incoming or outgoing). +**/ +enum _LinphoneSubscriptionDir{ + LinphoneSubscriptionIncoming, + LinphoneSubscriptionOutgoing +}; + +/** + * Typedef alias for _LinphoneSubscriptionDir +**/ +typedef _LinphoneSubscriptionDir LinphoneSubscriptionDir; + +/** + * Enum for subscription states. +**/ +enum _LinphoneSubscriptionState{ + LinphoneSubscriptionNone, /**< Initial state, should not be used.**/ + LinphoneSubscriptionOutoingInit, /** Date: Mon, 27 May 2013 12:36:42 +0200 Subject: [PATCH 405/909] update ms2 to remove opus for android --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3b8361ed5..1db1e85ae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3b8361ed57acccce823c500bd7a2145099d7678b +Subproject commit 1db1e85aebc7f4256bf665fb7f4b400e27442fce From 15b068fd46ffb84ae0318430a8046d8ebe3b3442 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 28 May 2013 15:12:02 +0200 Subject: [PATCH 406/909] Add zrtp dll in linphone-deps --- linphone-deps.filelist | 1 + 1 file changed, 1 insertion(+) diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 7eef0eea5..98d759b14 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -15,3 +15,4 @@ ./bin/libgnutls-26.dll ./bin/libtasn1-3.dll ./bin/libsqlite3-0.dll +./bin/libzrtpcpp.dll From 0fc6d3fd955f99a4418281f19ac3e62bc295b8d7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 29 May 2013 04:31:38 +0200 Subject: [PATCH 407/909] fix syntax errors in configure.ac and implement --enable-nls on windows --- configure.ac | 37 +++++++++++-------------------------- mediastreamer2 | 2 +- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/configure.ac b/configure.ac index f450cd84d..702109272 100644 --- a/configure.ac +++ b/configure.ac @@ -127,9 +127,11 @@ if test "$mingw_found" != "yes" ; then CPPFLAGS=$CPPFLAGS_save LIBS="$LIBS $LIBINTL" else - AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible]) - AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible]) - LIBS="$LIBS -lintl" + if test "$USE_NLS" = "yes" ; then + AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible]) + AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible]) + LIBS="$LIBS -lintl" + fi fi GETTEXT_PACKAGE=linphone @@ -681,29 +683,16 @@ if test x$enable_msg_storage != xfalse; then ] ) fi -SIPSTACK_CFLAGS= -SIPSTACK_LIBS= -AC_ARG_ENABLE([bellesip], - AS_HELP_STRING([--enable-bellesip], [Build with bellesip])) PKG_CHECK_MODULES(BELLESIP, [belle-sip],[bellesip_found=yes],foo=bar) -AM_CONDITIONAL([USE_BELLESIP], [test "x$enable_bellesip" != "xno" && test "x$bellesip_found" == "xyes"]) +AM_CONDITIONAL([USE_BELLESIP], [test "x$bellesip_found" == "xyes"]) +SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" +SIPSTACK_LIBS="$BELLESIP_LIBS" +AC_DEFINE(USE_BELLESIP,1,[Defined when bellesip is used]) -if test $USE_BELLESIP_TRUE !='#' ; then - SIPSTACK_CFLAGS=$BELLESIP_CFLAGS - SIPSTACK_LIBS=$BELLESIP_LIBS - AC_DEFINE(USE_BELLESIP,1,[Defined when bellesip is used]) -else - dnl check for osip2 - LP_CHECK_OSIP2 - dnl setup flags for exosip library - LP_SETUP_EXOSIP - SIPSTACK_CFLAGS=$EXOSIP_CFLAGS $OSIP_CFLAGS - SIPSTACK_LIBS=$EXOSIP_LIBS $OSIP_LIBS -fi AC_SUBST(SIPSTACK_CFLAGS) AC_SUBST(SIPSTACK_LIBS) @@ -855,12 +844,8 @@ printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp printf "* %-30s %s\n" "uPnP support" $build_upnp if test "$enable_tunnel" = "true" ; then - printf "* Tunnel support\t\t\ttrue\n" -fi -if test $USE_BELLESIP_TRUE !='#' ; then - printf "* bellesip stack\t\t\ttrue\n" -else - printf "* eXosip stack\t\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/mediastreamer2 b/mediastreamer2 index 1db1e85ae..5b7873ee3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1db1e85aebc7f4256bf665fb7f4b400e27442fce +Subproject commit 5b7873ee3cbc460138015ba244330d99aa861d7f From c403ad8e2225bb275435b4d3e88ad441bec89645 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 30 May 2013 10:12:31 +0200 Subject: [PATCH 408/909] update ms2 for syntax error fixes in configure. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f8ca60656..5b7873ee3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f8ca6065676eff95752d546e387684ccc90e7b1e +Subproject commit 5b7873ee3cbc460138015ba244330d99aa861d7f From a41aa048ea725b457850e2d207ad7a8c4c9d9c94 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 31 May 2013 12:02:17 +0200 Subject: [PATCH 409/909] generate rootca.pem at compilation time using mk-ca-bundle.pl from curl which gather trusted certificates from modizilla --- scripts/mk-ca-bundle.pl | 242 +++ share/.gitignore | 1 + share/Makefile.am | 12 +- share/rootca.pem | 3965 --------------------------------------- 4 files changed, 250 insertions(+), 3970 deletions(-) create mode 100755 scripts/mk-ca-bundle.pl delete mode 100644 share/rootca.pem diff --git a/scripts/mk-ca-bundle.pl b/scripts/mk-ca-bundle.pl new file mode 100755 index 000000000..edede4261 --- /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 = 'http://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/Makefile.am b/share/Makefile.am index 83c3a934e..6f8fe9198 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -31,11 +31,13 @@ pkgconfig_DATA=linphone.pc linphonedir=$(datadir)/linphone linphone_DATA=rootca.pem +rootca.pem: + $(top_srcdir)/scripts/mk-ca-bundle.pl rootca.pem EXTRA_DIST = $(LINPHONE_SOUNDS) \ - $(LINPHONE_RINGS) \ - linphone.desktop.in \ - linphone.pc.in \ - Makefile.inc \ - rootca.pem + $(LINPHONE_RINGS) \ + linphone.desktop.in \ + linphone.pc.in \ + Makefile.inc \ + rootca.pem 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----- -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 -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----- -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 ------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----- -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 ------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----- From 5f0e9b7682123effcfa670e7c0ac8c8836188edb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 3 Jun 2013 16:23:58 +0200 Subject: [PATCH 410/909] ipdate ms2 to fix build issue when compiling whitout opus --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 5b7873ee3..bc1cb1d1f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5b7873ee3cbc460138015ba244330d99aa861d7f +Subproject commit bc1cb1d1f2b996c84828ba7d81ae43b95bcceacb From fe1cddbfaac5b9d671c730a98baa3b7914265129 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 4 Jun 2013 21:25:52 +0200 Subject: [PATCH 411/909] no longuer return registration failure in case of first retry --- coreapi/bellesip_sal/sal_op_impl.c | 13 ++++++++++++- coreapi/bellesip_sal/sal_op_registration.c | 4 ---- coreapi/callbacks.c | 9 ++++++++- coreapi/proxy.c | 16 +++++++++++++--- coreapi/sal.c | 1 + include/sal/sal.h | 3 ++- tester/liblinphone_tester.c | 2 +- tester/register_tester.c | 11 +++++++---- 8 files changed, 44 insertions(+), 15 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 78957f2af..ffd2b3b86 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -40,7 +40,10 @@ void sal_op_release(SalOp *op){ void sal_op_release_impl(SalOp *op){ ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type)); if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); - if (op->auth_info) sal_auth_info_delete(op->auth_info); + if (op->auth_info) { + sal_remove_pending_auth(op->base.root,op); + sal_auth_info_delete(op->auth_info); + } if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); if (op->refresher) { belle_sip_object_unref(op->refresher); @@ -259,6 +262,10 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal case 400: *sal_err=SalErrorUnknown; break; + case 403: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonForbidden; + break; case 404: *sal_err=SalErrorFailure; *sal_reason=SalReasonNotFound; @@ -280,6 +287,10 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal break; case 487: break; + case 503: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonServiceUnavailable; + break; case 600: *sal_err=SalErrorFailure; *sal_reason=SalReasonDoNotDisturb; diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index d4226ef3f..7c70bf18f 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -68,10 +68,6 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); - if (status_code == 403 || status_code == 401 || status_code == 407) { /*in case of 401 or 407, auth requested already invoked previously but maybe*/ - /*auth previouly pending, probably wrong pasword, give a chance to authenticate again*/ - op->base.root->callbacks.auth_failure(op,op->auth_info); /*fixme*/ - } } } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 08e7cf550..35ae87a24 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -779,7 +779,14 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const } else if (error == SalErrorNoResponse) { linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse); } - linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); + if (error== SalErrorFailure + && reason == SalReasonServiceUnavailable + && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); + + } else { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); + } if (error== SalErrorFailure && reason == SalReasonForbidden) { const char *realm=NULL,*username=NULL; if (sal_op_get_auth_requested(op,&realm,&username)==0){ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index c3770d87e..253922713 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1310,9 +1310,19 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) { void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){ LinphoneCore *lc=cfg->lc; - cfg->state=state; - if (lc && lc->vtable.registration_state_changed){ - lc->vtable.registration_state_changed(lc,cfg,state,message); + + + ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg + , linphone_proxy_config_get_identity(cfg) + , linphone_registration_state_to_string(cfg->state) + , linphone_registration_state_to_string(state)); + if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ + cfg->state=state; + if (lc && lc->vtable.registration_state_changed){ + lc->vtable.registration_state_changed(lc,cfg,state,message); + } + } else { + /*state already reported*/ } } diff --git a/coreapi/sal.c b/coreapi/sal.c index d47c5d2fa..6c4db977b 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -525,6 +525,7 @@ const char* sal_reason_to_string(const SalReason reason) { case SalReasonMedia: return "SalReasonMedia"; case SalReasonForbidden: return "SalReasonForbidden"; case SalReasonUnknown: return "SalReasonUnknown"; + case SalReasonServiceUnavailable: return "SalReasonServiceUnavailable"; default: return "Unkown reason"; } } diff --git a/include/sal/sal.h b/include/sal/sal.h index 051f06482..9759f2931 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -270,7 +270,8 @@ typedef enum SalReason{ SalReasonDoNotDisturb, SalReasonMedia, SalReasonForbidden, - SalReasonUnknown + SalReasonUnknown, + SalReasonServiceUnavailable }SalReason; const char* sal_reason_to_string(const SalReason reason); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 1bd9e0ff7..40cf3df09 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -44,7 +44,7 @@ const char* test_route="sip2.linphone.org"; #if WINAPI_FAMILY_PHONE_APP const char *liblinphone_tester_file_prefix="Assets"; #else -const char *liblinphone_tester_file_prefix="./tester"; +const char *liblinphone_tester_file_prefix="."; #endif const char *userhostsfile = "tester_hosts"; diff --git a/tester/register_tester.c b/tester/register_tester.c index d079a3930..1b47bf343 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -126,11 +126,12 @@ static void register_with_refresh_with_send_error() { register_with_refresh_base(lc,TRUE,auth_domain,route); /*simultate a network error*/ sal_set_send_error(lc->sal, -1); - while (counters->number_of_LinphoneRegistrationFailed<1 && retry++ <20) { + while (counters->number_of_LinphoneRegistrationProgress<2 && retry++ <20) { linphone_core_iterate(lc); ms_usleep(100000); } - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); linphone_core_destroy(lc); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); @@ -348,7 +349,7 @@ static void transport_change(){ linphone_core_set_sip_transports(lc,&sip_tr); CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); - CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok+(total_number_of_proxies-number_of_udp_proxy))); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,total_number_of_proxies-number_of_udp_proxy)); linphone_core_destroy(lc); } @@ -368,7 +369,9 @@ static void io_recv_error(){ number_of_udp_proxy=get_number_of_udp_proxy(lc); sal_set_recv_error(lc->sal, 0); - CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,register_ok-number_of_udp_proxy /*because 1 udp*/)); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + sal_set_recv_error(lc->sal, 1); /*reset*/ linphone_core_destroy(lc); From 9a9074efd313e0c78d55148d5134ec511aae6499 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 5 Jun 2013 14:30:01 +0200 Subject: [PATCH 412/909] Add strtok in ortp for mingw compilation --- coreapi/message_storage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index deed140c7..765543f7a 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -83,7 +83,7 @@ void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom int ret; ret=sqlite3_exec(db,stmt,callback,cr,&errmsg); if(ret != SQLITE_OK) { - printf("Error in creation: %s.\n", errmsg); + ms_error("Error in creation: %s.\n", errmsg); sqlite3_free(errmsg); } } @@ -197,7 +197,7 @@ void linphone_create_table(sqlite3* db){ 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) { - printf("Error in creation: %s.\n", errmsg); + ms_error("Error in creation: %s.\n", errmsg); sqlite3_free(errmsg); } } @@ -209,7 +209,7 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ ret=sqlite3_open(lc->chat_db_file,&db); if(ret != SQLITE_OK) { errmsg=sqlite3_errmsg(db); - printf("Error in the opening: %s.\n", errmsg); + ms_error("Error in the opening: %s.\n", errmsg); sqlite3_close(db); } linphone_create_table(db); From bcbe504b9ed0c66b2ff31542e74a960f8455dbad Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 5 Jun 2013 20:19:46 +0200 Subject: [PATCH 413/909] add test --- tester/register_tester.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tester/register_tester.c b/tester/register_tester.c index 1b47bf343..16916df2c 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -377,6 +377,42 @@ static void io_recv_error(){ linphone_core_destroy(lc); } +static void io_recv_error_without_active_register(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + MSList* proxys; + + memset (&v_table,0,sizeof(LinphoneCoreVTable)); + v_table.registration_state_changed=registration_state_changed; + lc=configure_lc(&v_table); + counters = (stats*)linphone_core_get_user_data(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + + for (proxys=ms_list_copy(linphone_core_get_proxy_config_list(lc));proxys!=NULL;proxys=proxys->next) { + LinphoneProxyConfig* proxy_cfg=(LinphoneProxyConfig*)proxys->data; + linphone_proxy_config_edit(proxy_cfg); + linphone_proxy_config_enable_register(proxy_cfg,FALSE); + linphone_proxy_config_done(proxy_cfg); + } + ms_list_free(proxys); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationCleared,register_ok /*because 1 udp*/)); + + sal_set_recv_error(lc->sal, 0); + + /*nothing should happen because no active registration*/ + CU_ASSERT_FALSE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_destroy(lc); +} + static void tls_certificate_failure(){ LinphoneCoreVTable v_table; @@ -451,7 +487,8 @@ test_t register_tests[] = { { "Multi account", multiple_proxy }, { "Transport change", transport_change }, { "Network state change", network_state_change }, - { "io_recv_error_0", io_recv_error } + { "Io recv error", io_recv_error }, + { "Io recv error without active registration", io_recv_error_without_active_register} }; test_suite_t register_test_suite = { From 14bd5aa252839f8cbf3b24192c9a013eb9850829 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 6 Jun 2013 09:35:22 +0200 Subject: [PATCH 414/909] Really add strtok in oRTP --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index bc1cb1d1f..b40cd2308 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bc1cb1d1f2b996c84828ba7d81ae43b95bcceacb +Subproject commit b40cd2308ed594e2f4f311654a4291b22c72b5ac diff --git a/oRTP b/oRTP index 2c37d1205..462296433 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2c37d1205e9dd0e30a918ccf666ab217b66c2899 +Subproject commit 462296433f10bd84cb605edb0b38d16a4cd81d9e From 36e445f97f6d45239a3271f60fc3385892503741 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 10:49:28 +0200 Subject: [PATCH 415/909] generic subscribe notify api in progress --- console/linphonec.c | 15 +- coreapi/Makefile.am | 4 +- coreapi/bellesip_sal/sal_impl.c | 55 +++-- coreapi/bellesip_sal/sal_impl.h | 10 +- coreapi/bellesip_sal/sal_op_events.c | 303 +++++++++++++++++++++++++ coreapi/bellesip_sal/sal_op_impl.c | 162 +++++++++---- coreapi/bellesip_sal/sal_op_info.c | 23 +- coreapi/bellesip_sal/sal_op_message.c | 1 + coreapi/bellesip_sal/sal_op_presence.c | 41 +--- coreapi/bellesip_sal/sal_op_publish.c | 26 ++- coreapi/callbacks.c | 75 +++++- coreapi/event.c | 178 +++++++++++++++ coreapi/event.h | 51 ++++- coreapi/friend.c | 2 +- coreapi/info.c | 16 +- coreapi/linphonecore.c | 4 + coreapi/linphonecore.h | 90 ++++---- coreapi/misc.c | 60 +++++ coreapi/presence.c | 2 +- coreapi/private.h | 11 + coreapi/proxy.c | 2 +- include/sal/sal.h | 34 ++- mediastreamer2 | 2 +- tester/Makefile.am | 9 +- tester/eventapi_tester.c | 108 +++++++++ tester/liblinphone_tester.c | 3 + tester/liblinphone_tester.h | 9 + 27 files changed, 1084 insertions(+), 212 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_events.c create mode 100644 coreapi/event.c create mode 100644 tester/eventapi_tester.c diff --git a/console/linphonec.c b/console/linphonec.c index 60c3c2af1..f9e329b51 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -123,7 +123,7 @@ 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, @@ -281,13 +281,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); } @@ -638,7 +639,7 @@ main (int argc, char *argv[]) { linphonec_vtable.text_received=linphonec_text_received; linphonec_vtable.dtmf_received=linphonec_dtmf_received; linphonec_vtable.refer_received=linphonec_display_refer; - linphonec_vtable.notify_recv=linphonec_notify_received; + linphonec_vtable.transfer_state_changed=linphonec_transfer_state_changed; linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed; if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE); diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 1180bfff9..c4c60fcf7 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -46,6 +46,7 @@ liblinphone_la_SOURCES=\ conference.c \ message_storage.c \ info.c \ + event.c \ $(GITVERSION_FILE) if BUILD_UPNP @@ -63,7 +64,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_presence.c \ bellesip_sal/sal_op_publish.c \ bellesip_sal/sal_op_call_transfer.c \ - bellesip_sal/sal_op_info.c + bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_events.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 960a50254..6f7fe2124 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -141,6 +141,7 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; belle_sip_response_t* resp; + belle_sip_header_t *evh; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); @@ -150,10 +151,13 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); - } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { + } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0 && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; - sal_op_presence_fill_cbs(op); + 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",belle_sip_request_get_method(req))==0) { op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; @@ -259,7 +263,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } if (sal_op_get_contact(op)){ if (received!=NULL || rport>0) { - contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { @@ -302,30 +305,28 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even /*handle authorization*/ switch (response_code) { - case 200: { - break; - } - case 401: - case 407:{ - - /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ - if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { - /*only bye are completed*/ - belle_sip_message("Op is in state terminating, nothing else to do "); - } else { - if (op->pending_auth_transaction){ - belle_sip_object_unref(op->pending_auth_transaction); - op->pending_auth_transaction=NULL; + case 200: { + break; + } + case 401: + case 407:{ + + /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ + if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { + /*only bye are completed*/ + belle_sip_message("Op is in state terminating, nothing else to do "); + } else { + if (op->pending_auth_transaction){ + belle_sip_object_unref(op->pending_auth_transaction); + op->pending_auth_transaction=NULL; + } + op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); + sal_process_authentication(op); + return; } - op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); - sal_process_authentication(op); - return; } } - } - op->callbacks.process_response_event(op,event); - } else { ms_error("Unhandled event response [%p]",event); } @@ -444,10 +445,14 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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.subscribe_closed==NULL) + ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub; + if (ctx->callbacks.notify_presence==NULL) + ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; + if (ctx->callbacks.subscribe_presence_received==NULL) + ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub; if (ctx->callbacks.text_received==NULL) ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 2a6f50cc5..0b3e7ae24 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -66,7 +66,8 @@ typedef enum SalOpType { SalOpMessage, SalOpPresence, SalOpPublish, - SalOpInfo + SalOpInfo, + SalOpSubscribe }SalOpType_t; const char* sal_op_type_to_string(const SalOpType_t type); @@ -127,6 +128,8 @@ void sal_op_message_fill_cbs(SalOp*op); /*info*/ void sal_op_info_fill_cbs(SalOp*op); +void sal_op_subscribe_fill_cbs(SalOp*op); + /*call transfer*/ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); @@ -140,4 +143,9 @@ belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_reque 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); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c new file mode 100644 index 000000000..4923f2269 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -0,0 +1,303 @@ +/* +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 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) { + sal_op_unref(op); + op->dialog=NULL; + } +} + +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_response_event(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + belle_sip_dialog_state_t dialog_state; + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_response_t* response=belle_sip_response_event_get_response(event); + belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + int code = belle_sip_response_get_status_code(response); + char reason[256]={0}; + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + belle_sip_header_expires_t* expires; + SalSubscribeStatus sss=get_subscription_state(BELLE_SIP_MESSAGE(response)); + + if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { + ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); + op->base.root->callbacks.subscribe_response(op,SalSubscribeTerminated,error,sr); + return; + } + set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); + if (!op->dialog) { + ms_message("subscribe 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("subscribe 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); + } + op->base.root->callbacks.subscribe_response(op,sss,SalErrorNone,SalReasonUnknown); + } + 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("subscribe op [%p] receive answer [%i] not implemented",op,code); + } + /* no break */ + } +} + +static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_message("subscribe_process_timeout not implemented yet"); +} + +static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_message("subscribe_process_transaction_terminated not implemented yet"); +} + +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_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + 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; + SalSubscribeStatus sub_state; + belle_sip_response_t* resp; + const char *eventname=NULL; + + belle_sip_object_ref(server_transaction); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + + event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event"); + eventname=belle_sip_header_get_unparsed_value(event_header); + sal_op_get_body(op,(belle_sip_message_t*)req,&body); + + if (eventname==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->dialog) { + 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)); + } + 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",belle_sip_request_get_method(req))==0) { + 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; + + 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); + } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { + /*either a refresh of an unsubscribe*/ + if (expires && belle_sip_header_expires_get_expires(expires)>0) { + + } else if(expires) { + ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.subscribe_closed(op); + } + } + break; + default: { + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + } + } +} + +void sal_op_subscribe_fill_cbs(SalOp*op) { + op->callbacks.process_io_error=subscribe_process_io_error; + op->callbacks.process_response_event=subscribe_response_event; + op->callbacks.process_timeout=subscribe_process_timeout; + op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; + op->callbacks.process_request_event=subscribe_process_request_event; + op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + op->type=SalOpSubscribe; +} + +static int set_event_name(SalOp *op, belle_sip_message_t *msg){ + belle_sip_transaction_t *last_transaction; + belle_sip_request_t *req; + belle_sip_header_t *event; + + if (!op->dialog) return -1; + + last_transaction=belle_sip_dialog_get_last_transaction(op->dialog); + + if (!last_transaction) return -1; + + req=belle_sip_transaction_get_request(last_transaction); + event=belle_sip_message_get_header((belle_sip_message_t*)req,"Event"); + if (!event){ + ms_error("No event header in last request."); + return -1; + } + belle_sip_message_add_header(msg,event); + return 0; +} + +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"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); + }else{ + belle_sip_transaction_t *last=belle_sip_dialog_get_last_transaction(op->dialog); + belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last)); + req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); + if (expires==-1){ + belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t); + expires=belle_sip_header_expires_get_expires(eh); + } + set_event_name(op,(belle_sip_message_t*)req); + } + 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_request(op,req); +} + +int sal_unsubscribe(SalOp *op){ + belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ + if (!req) { + ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); + return -1; + } + if (op->refresher) + belle_sip_refresher_stop(op->refresher); + set_event_name(op,(belle_sip_message_t*)req); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); + return sal_op_send_request(op,req); +} + +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; + + notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + if (set_event_name(op,(belle_sip_message_t*)notify)==-1){ + belle_sip_object_unref(notify); + return -1; + } + + 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; + notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + set_event_name(op,(belle_sip_message_t*)notify); + 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 index ffd2b3b86..ea8dd9c34 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -256,56 +256,93 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { return _sal_op_send_request_with_contact(op, request,need_contact); } +SalReason sal_reason_to_sip_code(SalReason r){ + int ret=500; + switch(r){ + case SalReasonUnknown: + ret=400; + break; + + case SalReasonBusy: + ret=486; + break; + case SalReasonDeclined: + ret=603; + break; + case SalReasonDoNotDisturb: + ret=600; + break; + case SalReasonForbidden: + ret=403; + break; + case SalReasonMedia: + ret=415; + break; + case SalReasonNotFound: + ret=404; + break; + case SalReasonRedirect: + ret=302; + break; + case SalReasonTemporarilyUnavailable: + ret=480; + break; + case SalReasonServiceUnavailable: + ret=503; + break; + } + return ret; +} void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { - switch(code) { - case 400: - *sal_err=SalErrorUnknown; - break; - case 403: + switch(code) { + case 400: + *sal_err=SalErrorUnknown; + break; + case 403: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonForbidden; + break; + case 404: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNotFound; + break; + case 415: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonMedia; + break; + case 422: + ms_error ("422 not implemented yet");; + break; + case 480: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonTemporarilyUnavailable; + break; + case 486: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonBusy; + break; + case 487: + break; + case 600: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDoNotDisturb; + break; + case 603: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDeclined; + break; + case 503: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonServiceUnavailable; + break; + default: + if (code>0){ *sal_err=SalErrorFailure; - *sal_reason=SalReasonForbidden; - break; - case 404: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonNotFound; - break; - case 415: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonMedia; - break; - case 422: - ms_error ("422 not implemented yet");; - break; - case 480: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonTemporarilyUnavailable; - break; - case 486: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonBusy; - break; - case 487: - break; - case 503: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonServiceUnavailable; - break; - case 600: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonDoNotDisturb; - break; - case 603: - *sal_err=SalErrorFailure; - *sal_reason=SalReasonDeclined; - break; - default: - if (code>0){ - *sal_err=SalErrorFailure; - *sal_reason=SalReasonUnknown; - }else *sal_err=SalErrorNoResponse; - /* no break */ - } + *sal_reason=SalReasonUnknown; + }else *sal_err=SalErrorNoResponse; + /* no break */ + } } /*return TRUE if error code*/ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { @@ -415,4 +452,35 @@ const char *sal_op_get_remote_contact(const SalOp *op){ return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); } +void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){ + 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); + } +} + +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; + + 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); + } + + 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); + return TRUE; + } + memset(salbody,0,sizeof(salbody)); + return FALSE; +} diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index a86328fbb..c3f600aaa 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -31,23 +31,10 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t SalOp* op = (SalOp*)op_base; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); - belle_sip_header_content_type_t* content_type; - belle_sip_header_content_length_t *clen=NULL; belle_sip_response_t* resp; SalBody salbody; - const char *body = NULL; - content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); - if (content_type){ - body=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - clen=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_length_t); - } - - 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 (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { op->base.root->callbacks.info_received(op,&salbody); } else { op->base.root->callbacks.info_received(op,NULL); @@ -60,13 +47,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ belle_sip_request_t *req=sal_op_build_request(op,"INFO"); sal_op_info_fill_cbs(op); - 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); - } + sal_op_add_body(op,(belle_sip_message_t*)req,body); return sal_op_send_request(op,req); } diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 08eef45c7..140dbe85f 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -149,6 +149,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co return sal_op_send_request(op,req); } + int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { return sal_message_send(op,from,to,"text/plain",msg); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 8d800ef9d..b68ef1f33 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -424,6 +424,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; belle_sip_header_expires_t* expires; + if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); @@ -436,9 +437,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } dialog_state=belle_sip_dialog_get_state(op->dialog); - - switch(dialog_state) { - + 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); @@ -450,6 +449,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even 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); @@ -475,9 +475,11 @@ static void presence_response_event(void *op_base, const belle_sip_response_even 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 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)); @@ -504,7 +506,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { - op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op)); + op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); break; } case BELLE_SIP_DIALOG_EARLY: @@ -553,7 +555,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { /*either a refresh of an unsubscribe*/ if (expires && belle_sip_header_expires_get_expires(expires)>0) { - op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op)); + 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); @@ -566,9 +568,8 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques } /* no break */ } - - } + void sal_op_presence_fill_cbs(SalOp*op) { op->callbacks.process_io_error=presence_process_io_error; op->callbacks.process_response_event=presence_response_event; @@ -597,29 +598,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ return sal_op_send_request(op,req); } -int sal_unsubscribe(SalOp *op){ - belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ - if (!req) { - ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0))); - return sal_op_send_request(op,req); -} -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){ - belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),403); - belle_sip_server_transaction_send_response(op->pending_server_trans,resp); - return 0; -} + static belle_sip_request_t *create_presence_notify(SalOp *op){ belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); @@ -635,7 +614,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ return sal_op_send_request(op,notify); } -int sal_notify_close(SalOp *op){ +int sal_notify_presence_close(SalOp *op){ belle_sip_request_t* notify=create_presence_notify(op); sal_add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*FIXME, what about expires ??*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 29d78cd72..cf9dc8f54 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -30,7 +30,7 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher } /*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ +int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) @@ -53,3 +53,27 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus s } } +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); + + op->type=SalOpPublish; + req=sal_op_build_request(op,"PUBLISH"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); + if (body) sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); + return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); + } else { + /*update status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*update body*/ + if (body) sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),body); + return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + } +} + + diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 35ae87a24..1fe12bd1a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -872,25 +872,17 @@ static void text_received(SalOp *op, const SalMessage *msg){ } } -static void notify(SalOp *op, const char *from, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); - ms_message("get a %s notify from %s",msg,from); - if(lc->vtable.notify_recv) - lc->vtable.notify_recv(lc,call,from,msg); -} - static void 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); } @@ -1008,6 +1000,62 @@ static void info_received(SalOp *op, const SalBody *body){ linphone_core_notify_info_message(lc,op,body); } +static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + if (lev==NULL) return; + + if (status==SalSubscribeActive){ + linphone_event_set_state(lev,LinphoneSubscriptionActive); + }else if (status==SalSubscribePending){ + linphone_event_set_state(lev,LinphoneSubscriptionPending); + }else{ + linphone_event_set_reason(lev, linphone_reason_from_sal(reason)); + linphone_event_set_state(lev,LinphoneSubscriptionError); + linphone_event_destroy(lev); + } +} + +static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, const SalBody *body){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneContent content; + + if (lev==NULL) { + /*out of subscribe notify */ + lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing); + } + if (lc->vtable.notify_received){ + lc->vtable.notify_received(lc,lev,eventname,linphone_content_from_sal_body(&content,body)); + } + if (st!=SalSubscribeNone){ + linphone_event_set_state(lev,linphone_subscription_state_from_sal(st)); + if (st==SalSubscribeTerminated) + linphone_event_destroy(lev); + } + +} + +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); + 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); + linphone_event_destroy(lev); +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -1030,11 +1078,14 @@ SalCallbacks linphone_sal_callbacks={ refer_received, text_received, text_delivery_update, - notify, - notify_presence, notify_refer, subscribe_received, subscribe_closed, + subscribe_response, + notify, + subscribe_presence_received, + subscribe_presence_closed, + notify_presence, ping_reply, auth_requested, info_received diff --git a/coreapi/event.c b/coreapi/event.c new file mode 100644 index 000000000..d3a774fb1 --- /dev/null +++ b/coreapi/event.c @@ -0,0 +1,178 @@ +/* +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" + + +struct _LinphoneEvent{ + LinphoneSubscriptionDir dir; + LinphoneCore *lc; + SalOp *op; + LinphoneSubscriptionState state; + LinphoneReason reason; + void *userdata; +}; + +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; +} + +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir){ + LinphoneEvent *lev=ms_new0(LinphoneEvent,1); + lev->lc=lc; + lev->dir=dir; + lev->op=sal_op_new(lc->sal); + sal_op_set_user_pointer(lev->op,lev); + return lev; +} + +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir){ + LinphoneEvent *lev=ms_new0(LinphoneEvent,1); + lev->lc=lc; + lev->dir=LinphoneSubscriptionIncoming; + lev->op=op; + sal_op_set_user_pointer(lev->op,lev); + return lev; +} + +void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){ + LinphoneCore *lc=lev->lc; + if (lev->state!=state){ + lev->state=state; + if (lc->vtable.subscription_state_changed){ + lc->vtable.subscription_state_changed(lev->lc,lev,state); + } + } +} + +void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){ + lev->reason=reason; +} + +LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ + return lev->reason; +} + +LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing); + SalBody salbody; + linphone_configure_op(lc,lev->op,resource,NULL,TRUE); + sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); + linphone_event_set_state(lev,LinphoneSubscriptionOutoingInit); + return lev; +} + + +int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ + SalBody salbody; + if (lev->state!=LinphoneSubscriptionActive){ + ms_error("linphone_event_update_subscribe(): cannot update subscription if subscription wasn't accepted."); + return -1; + } + if (lev->dir!=LinphoneSubscriptionOutgoing){ + ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription."); + return -1; + } + return sal_subscribe(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); +} + +int linphone_event_accept_subscription(LinphoneEvent *lev){ + int err; + if (lev->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){ + if (lev->state!=LinphoneSubscriptionIncomingReceived){ + ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received."); + return -1; + } + return sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason)); +} + +int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ + SalBody salbody; + if (lev->state!=LinphoneSubscriptionActive){ + ms_error("linphone_event_notify(): cannot notify if subscription is not active."); + return -1; + } + if (lev->dir!=LinphoneSubscriptionIncoming){ + ms_error("linphone_event_notify(): cannot notify if not an incoming subscription."); + return -1; + } + return sal_notify(lev->op,sal_body_from_content(&salbody,body)); +} + +LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + SalBody salbody; + LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir); + linphone_configure_op(lc,lev->op,resource,NULL,FALSE); + sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); + return lev; +} + + +int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){ + SalBody salbody; + return sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); +} + +void linphone_event_set_user_pointer(LinphoneEvent *ev, void *up){ + ev->userdata=up; +} + +void *linphone_event_get_user_pointer(const LinphoneEvent *ev){ + return ev->userdata; +} + +void linphone_event_terminate(LinphoneEvent *lev){ + if (lev->dir==LinphoneSubscriptionIncoming){ + sal_notify_close(lev->op); + }else if (lev->dir==LinphoneSubscriptionOutgoing){ + sal_unsubscribe(lev->op); + } + + if (lev->state!=LinphoneSubscriptionNone){ + linphone_event_set_state(lev,LinphoneSubscriptionTerminated); + } + linphone_event_destroy(lev); +} + +void linphone_event_destroy(LinphoneEvent *lev){ + if (lev->op) + sal_op_release(lev->op); + ms_free(lev); +} + +LinphoneSubscriptionDir linphone_event_get_dir(LinphoneEvent *lev){ + return lev->dir; +} diff --git a/coreapi/event.h b/coreapi/event.h index 68417a846..aa87a42cc 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -19,6 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef LINPHONEEVENT_H #define LINPHONEEVENT_H +/** + * @addtogroup subscriptions + * @{ +**/ + struct _LinphoneEvent; typedef struct _LinphoneEvent LinphoneEvent; @@ -28,13 +33,14 @@ typedef struct _LinphoneEvent LinphoneEvent; **/ enum _LinphoneSubscriptionDir{ LinphoneSubscriptionIncoming, - LinphoneSubscriptionOutgoing + LinphoneSubscriptionOutgoing, + LinphoneSubscriptionInvalidDir }; /** * Typedef alias for _LinphoneSubscriptionDir **/ -typedef _LinphoneSubscriptionDir LinphoneSubscriptionDir; +typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir; /** * Enum for subscription states. @@ -49,7 +55,7 @@ enum _LinphoneSubscriptionState{ LinphoneSubscriptionError /**insub){ - sal_notify_close(lf->insub); + sal_notify_presence_close(lf->insub); } } diff --git a/coreapi/info.c b/coreapi/info.c index 961fa0b04..11ec0b7fd 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -58,13 +58,13 @@ static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *r obj->size=ref->size; } -static void linphone_content_uninit(LinphoneContent * obj){ +void linphone_content_uninit(LinphoneContent * obj){ if (obj->type) ms_free(obj->type); if (obj->subtype) ms_free(obj->subtype); if (obj->data) ms_free(obj->data); } -static LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ +LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ SET_STRING(obj,type,ref->type); SET_STRING(obj,subtype,ref->subtype); if (obj->data) { @@ -80,7 +80,17 @@ static LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj return obj; } -static SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ +const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref){ + if (ref && ref->type){ + obj->type=(char*)ref->type; + obj->subtype=(char*)ref->subtype; + obj->data=(void*)ref->data; + obj->size=ref->size; + } + return NULL; +} + +SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ if (lc->type){ body->type=lc->type; body->subtype=lc->subtype; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b420dbd3c..f90124fd0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5655,6 +5655,10 @@ 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"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e363192ac..5cbffe51c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -91,10 +91,58 @@ typedef struct _LCSipTransports{ * @var LinphoneAddress */ typedef struct SalAddress LinphoneAddress; + +/** + * The LinphoneContent struct holds data that can be embedded in a signaling message. + * @ingroup misc +**/ +struct _LinphoneContent{ + char *type; /**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.*/ diff --git a/coreapi/private.h b/coreapi/private.h index 6afc16c4b..a93bcec47 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -742,6 +742,17 @@ const char *linphone_core_create_uuid(LinphoneCore *lc); void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); void linphone_call_create_op(LinphoneCall *call); void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); +LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref); +SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc); +SalReason linphone_reason_to_sal(LinphoneReason reason); +LinphoneReason linphone_reason_from_sal(SalReason reason); +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir); +void linphone_event_destroy(LinphoneEvent *lev); +void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); +void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); +LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); +const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); #ifdef __cplusplus } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 253922713..b5d613f5f 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -858,7 +858,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); } - err=sal_publish(proxy->publish_op,NULL,NULL,linphone_online_status_to_sal(presence_mode)); + err=sal_publish_presence(proxy->publish_op,NULL,NULL,linphone_online_status_to_sal(presence_mode)); return err; } diff --git a/include/sal/sal.h b/include/sal/sal.h index 9759f2931..d3efc5722 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -255,6 +255,7 @@ typedef struct SalOpBase{ typedef enum SalError{ + SalErrorNone, SalErrorNoResponse, SalErrorProtocol, SalErrorFailure, /* see SalReason for more details */ @@ -298,6 +299,8 @@ typedef enum SalReferStatus{ }SalReferStatus; typedef enum SalSubscribeStatus{ + SalSubscribeNone, + SalSubscribePending, SalSubscribeActive, SalSubscribeTerminated }SalSubscribeStatus; @@ -345,11 +348,14 @@ typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg); typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); -typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); +typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); +typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body); +typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body); +typedef void (*SalOnSubscribeClosed)(SalOp *salop); typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg); -typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); -typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); +typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); +typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body); /*allows sal implementation to access auth info if available, return TRUE if found*/ @@ -378,11 +384,14 @@ typedef struct SalCallbacks{ SalOnRefer refer_received; SalOnTextReceived text_received; SalOnTextDeliveryUpdate text_delivery_update; - SalOnNotify notify; - SalOnNotifyPresence notify_presence; SalOnNotifyRefer notify_refer; SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; + SalOnSubscribeResponse subscribe_response; + SalOnNotify notify; + SalOnSubscribePresenceReceived subscribe_presence_received; + SalOnSubscribePresenceClosed subscribe_presence_closed; + SalOnNotifyPresence notify_presence; SalOnPingReply ping_reply; SalOnAuthRequested auth_requested; SalOnInfoReceived info_received; @@ -516,14 +525,11 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to); -int sal_unsubscribe(SalOp *op); -int sal_subscribe_accept(SalOp *op); -int sal_subscribe_decline(SalOp *op); int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message); -int sal_notify_close(SalOp *op); +int sal_notify_presence_close(SalOp *op); /*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status); +int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status); /*ping: main purpose is to obtain its own contact address behind firewalls*/ @@ -532,6 +538,14 @@ int sal_ping(SalOp *op, const char *from, const char *to); /*info messages*/ int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body); +/*generic subscribe/notify/publish api*/ +int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body); +int sal_unsubscribe(SalOp *op); +int sal_subscribe_accept(SalOp *op); +int sal_subscribe_decline(SalOp *op, SalReason reason); +int sal_notify(SalOp *op, const SalBody *body); +int sal_notify_close(SalOp *op); +int sal_publish(SalOp *op, const char *from, const char *to, const char*event_name, int expires, const SalBody *body); #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); diff --git a/mediastreamer2 b/mediastreamer2 index 5b7873ee3..dd0116eb8 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5b7873ee3cbc460138015ba244330d99aa861d7f +Subproject commit dd0116eb8e26f128a2366b38115b602def4b4073 diff --git a/tester/Makefile.am b/tester/Makefile.am index 6b5e9edae..25ac64865 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -6,7 +6,14 @@ if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester TESTS=$(noinst_PROGRAMS) -liblinphone_tester_SOURCES= liblinphone_tester.c setup_tester.c register_tester.c message_tester.c call_tester.c presence_tester.c upnp_tester.c +liblinphone_tester_SOURCES= liblinphone_tester.c \ + setup_tester.c \ + register_tester.c \ + message_tester.c \ + call_tester.c \ + presence_tester.c \ + upnp_tester.c \ + eventapi_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c new file mode 100644 index 000000000..c132abd65 --- /dev/null +++ b/tester/eventapi_tester.c @@ -0,0 +1,108 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2010 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include +#include "liblinphone_tester.h" + + +static const char *subscribe_content="blabla"; +static const char *notify_content="blabla"; + +void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ +} + +void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { + stats* counters = (stats*)linphone_core_get_user_data(lc); + LinphoneContent content; + + content.type="application"; + content.subtype="somexml2"; + content.data=(void*)notify_content; + content.size=strlen(notify_content); + + switch(state){ + case LinphoneSubscriptionNone: + break; + case LinphoneSubscriptionIncomingReceived: + counters->number_of_LinphoneSubscriptionIncomingReceived++; + linphone_event_accept_subscription(lev); + break; + case LinphoneSubscriptionOutoingInit: + counters->number_of_LinphoneSubscriptionOutgoingInit++; + break; + case LinphoneSubscriptionPending: + counters->number_of_LinphoneSubscriptionPending++; + break; + case LinphoneSubscriptionActive: + counters->number_of_LinphoneSubscriptionActive++; + if (linphone_event_get_dir(lev)==LinphoneSubscriptionIncoming) + linphone_event_notify(lev,&content); + break; + case LinphoneSubscriptionTerminated: + counters->number_of_LinphoneSubscriptionTerminated++; + break; + case LinphoneSubscriptionError: + counters->number_of_LinphoneSubscriptionError++; + break; + } +} + + + + + +static void subscribe_test() { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneContent content; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +test_t subscribe_tests[] = { + { "Subscribe", subscribe_test }, +}; + +test_suite_t subscribe_test_suite = { + "Subscribe", + NULL, + NULL, + sizeof(subscribe_tests) / sizeof(subscribe_tests[0]), + subscribe_tests +}; + diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 40cf3df09..f71b29345 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -192,6 +192,8 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc mgr->v_table.notify_presence_recv=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->lc=configure_lc_from(&mgr->v_table, path, rc_file, check_for_proxies?(rc_file?1:0):0); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); @@ -297,6 +299,7 @@ void liblinphone_tester_init(void) { #ifdef UPNP add_test_suite(&upnp_test_suite); #endif + add_test_suite(&subscribe_test_suite); } void liblinphone_tester_uninit(void) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 7aa3cebb9..9e8eb6f24 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -51,6 +51,7 @@ 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 subscribe_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -137,6 +138,12 @@ typedef struct _stats { int number_of_inforeceived; int number_of_inforeceived_with_body; + int number_of_LinphoneSubscriptionIncomingReceived; + int number_of_LinphoneSubscriptionOutgoingInit; + int number_of_LinphoneSubscriptionPending; + int number_of_LinphoneSubscriptionActive; + int number_of_LinphoneSubscriptionTerminated; + int number_of_LinphoneSubscriptionError; }stats; @@ -162,6 +169,8 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg); void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); +void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; LinphoneAddress * create_linphone_address(const char * domain); From 9c72c72415772b66d89ed269469e8f74ab229f8b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 11:12:17 +0200 Subject: [PATCH 416/909] fix warning in gtk app --- gtk/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index e914e42bd..1aa2e287c 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -568,7 +568,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ if (id!=0){ ms_message("Updating window decorations"); #ifndef WIN32 - w=gdk_window_foreign_new(id); + w=gdk_window_foreign_new((GdkNativeWindow)id); #else w=gdk_window_foreign_new((HANDLE)id); #endif @@ -587,7 +587,7 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ if (id!=0){ ms_message("Updating window decorations for preview"); #ifndef WIN32 - w=gdk_window_foreign_new(id); + w=gdk_window_foreign_new((GdkNativeWindow)id); #else w=gdk_window_foreign_new((HANDLE)id); #endif From aa0fedfa02895d5595f8cb205ef2389ce036feaa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 6 Jun 2013 15:44:11 +0200 Subject: [PATCH 417/909] Update ms2 for VP8 fixes. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b40cd2308..60edaade5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b40cd2308ed594e2f4f311654a4291b22c72b5ac +Subproject commit 60edaade52a6f123f2cde6140ca90378d95c9d87 From 75f41e680aefeb15dab3f8fa77149cf316143e8e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 6 Jun 2013 15:26:21 +0200 Subject: [PATCH 418/909] Add linphone_core_get_camera_sensor_rotation(). --- coreapi/linphonecore.c | 10 ++++++++++ coreapi/linphonecore.h | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f0963f904..202519d76 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4744,6 +4744,16 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { #endif } +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 + return -1; +} + static MSVideoSizeDef supported_resolutions[]={ #ifdef ENABLE_HD { {MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H} , "1080p" }, diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 67d4fb255..50686a2c9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1354,6 +1354,17 @@ void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); int linphone_core_get_device_rotation(LinphoneCore *lc ); void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); +/** + * @brief Get the camera sensor rotation. + * + * 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 + */ +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); From c1c4ff6e0acbee350810d99401c5e73067cdbdcb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 6 Jun 2013 15:32:22 +0200 Subject: [PATCH 419/909] Add missing exports. --- coreapi/linphonecore.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c8494434f..c5df3eadb 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1403,11 +1403,11 @@ int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); float linphone_core_get_static_picture_fps(LinphoneCore *lc); /*function to be used for eventually setting window decorations (icons, title...)*/ -unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); -void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id); +LINPHONE_PUBLIC unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id); -unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); -void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); +LINPHONE_PUBLIC unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); int linphone_core_get_device_rotation(LinphoneCore *lc ); @@ -1422,7 +1422,7 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); * @param lc The linphone core related to the operation * @return The camera sensor rotation in degrees (0 to 360) or -1 if it could not be retrieved */ -int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc); /* start or stop streaming video in case of embedded window */ void linphone_core_show_video(LinphoneCore *lc, bool_t show); From 01f746a4b22bc57d7ecc16774e8e22e5f3571588 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 6 Jun 2013 15:41:22 +0200 Subject: [PATCH 420/909] Add missing files to compile in the Visual Studio project. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 693f6c9c7..f7f456fa3 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -176,6 +176,7 @@ + @@ -188,6 +189,7 @@ + @@ -209,6 +211,7 @@ + @@ -237,9 +240,6 @@ {d22bd217-d0f8-4274-9b3a-f3f35f46482c} - - {0565952a-ea62-46a2-8261-f5b4b490da42} - {ffc7b532-0502-4d88-ac98-9e89071cbc97} false @@ -268,4 +268,4 @@ - + \ No newline at end of file From 5183b2176146d09a83148e1736215dbe48bbb44f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 21:01:01 +0200 Subject: [PATCH 421/909] change info api so that INFO message can only be sent through calls (as requested by the RFC) --- coreapi/bellesip_sal/sal_impl.c | 6 +-- coreapi/bellesip_sal/sal_impl.h | 4 -- coreapi/bellesip_sal/sal_op_call.c | 19 ++++++-- coreapi/bellesip_sal/sal_op_events.c | 1 + coreapi/bellesip_sal/sal_op_info.c | 42 +++-------------- coreapi/event.c | 5 +- coreapi/info.c | 44 +++++++----------- coreapi/linphonecore.h | 28 +++++------ tester/call_tester.c | 11 +++-- tester/eventapi_tester.c | 69 ++++++++++++++++++++++++---- tester/liblinphone_tester.c | 20 ++++++-- tester/liblinphone_tester.h | 7 ++- tester/message_tester.c | 18 +++++--- tester/presence_tester.c | 4 +- tester/register_tester.c | 38 +++++++-------- 15 files changed, 179 insertions(+), 137 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 6f7fe2124..641884964 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -167,9 +167,9 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; }else if (strcmp("INFO",belle_sip_request_get_method(req))==0) { - op=sal_op_new((Sal*)sal); - op->dir=SalOpDirIncoming; - sal_op_info_fill_cbs(op); + resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ + belle_sip_provider_send_response(((Sal*)sal)->prov,resp); + return; }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,501); diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 0b3e7ae24..ef4db521d 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -66,7 +66,6 @@ typedef enum SalOpType { SalOpMessage, SalOpPresence, SalOpPublish, - SalOpInfo, SalOpSubscribe }SalOpType_t; const char* sal_op_type_to_string(const SalOpType_t type); @@ -125,9 +124,6 @@ void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ void sal_op_message_fill_cbs(SalOp*op); -/*info*/ -void sal_op_info_fill_cbs(SalOp*op); - void sal_op_subscribe_fill_cbs(SalOp*op); /*call transfer*/ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index dd7ede609..f9cb812fe 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -192,6 +192,7 @@ static void cancelling_invite(SalOp* op ){ sal_op_send_request(op,cancel); op->state=SalOpStateTerminating; } + static void call_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; @@ -438,7 +439,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else { - belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); + 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; @@ -480,8 +481,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t process_sdp_for_invite(op,req); op->base.root->callbacks.call_updating(op); - } else if (strcmp("INFO",belle_sip_request_get_method(req))==0 - && belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) + } else if (strcmp("INFO",belle_sip_request_get_method(req))==0){ + if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { /*vfu request*/ ms_message("Receiving VFU request on op [%p]",op); @@ -489,8 +490,16 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->base.root->callbacks.vfu_request(op); } - resp=sal_op_create_response_from_request(op,req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); + }else{ + SalBody salbody; + if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { + op->base.root->callbacks.info_received(op,&salbody); + } else { + op->base.root->callbacks.info_received(op,NULL); + } + } + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { sal_op_process_refer(op,event); } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 4923f2269..952c58a6a 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -85,6 +85,7 @@ static void subscribe_response_event(void *op_base, const belle_sip_response_eve if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); } + if (sss==SalSubscribeNone) sss=SalSubscribeActive; /*without Subscription-state header, consider subscription is accepted.*/ op->base.root->callbacks.subscribe_response(op,sss,SalErrorNone,SalReasonUnknown); } break; diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index c3f600aaa..3b329515f 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -18,43 +18,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" -static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ -} - -static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { -} - -static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ -} - -static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { - SalOp* op = (SalOp*)op_base; - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); - belle_sip_response_t* resp; - SalBody salbody; - - if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { - op->base.root->callbacks.info_received(op,&salbody); - } else { - op->base.root->callbacks.info_received(op,NULL); - } - resp = belle_sip_response_create_from_request(req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); - sal_op_release(op); -} int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ - belle_sip_request_t *req=sal_op_build_request(op,"INFO"); - sal_op_info_fill_cbs(op); - sal_op_add_body(op,(belle_sip_message_t*)req,body); - return sal_op_send_request(op,req); + if (op->dialog){ + belle_sip_request_t *req=belle_sip_dialog_create_request(op->dialog,"INFO"); + sal_op_add_body(op,(belle_sip_message_t*)req,body); + return sal_op_send_request(op,req); + } + return -1; } -void sal_op_info_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=process_io_error; - op->callbacks.process_response_event=process_response_event; - op->callbacks.process_timeout=process_timeout; - op->callbacks.process_request_event=process_request_event; - op->type=SalOpInfo; -} diff --git a/coreapi/event.c b/coreapi/event.c index d3a774fb1..3d350b578 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -112,11 +112,14 @@ int linphone_event_accept_subscription(LinphoneEvent *lev){ } int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){ + int err; if (lev->state!=LinphoneSubscriptionIncomingReceived){ ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received."); return -1; } - return sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason)); + 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){ diff --git a/coreapi/info.c b/coreapi/info.c index 11ec0b7fd..6d92a0db8 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -30,7 +30,6 @@ struct _LinphoneInfoMessage{ LinphoneContent content; - SalOp *op; SalCustomHeader *headers; }; @@ -105,8 +104,6 @@ SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ * Destroy a LinphoneInfoMessage **/ void linphone_info_message_destroy(LinphoneInfoMessage *im){ - /* FIXME: op is leaked. If we release it now, there is a high risk that the request won't be resent with authentication*/ - /*if (im->op) sal_op_release(im->op);*/ linphone_content_uninit(&im->content); sal_custom_header_free(im->headers); ms_free(im); @@ -117,13 +114,12 @@ LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig) LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); linphone_content_copy(&im->content,&orig->content); if (orig->headers) im->headers=sal_custom_header_clone(orig->headers); - if (orig->op) im->op=sal_op_ref(orig->op); return im; } /** * Creates an empty info message. - * @param lc the LinphoneCore object. + * @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(), @@ -131,20 +127,18 @@ LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig) **/ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){ LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); - im->op=sal_op_new(lc->sal); return im; } /** - * Send a LinphoneInfoMessage to a specified address. - * @param lc the LinphoneCore + * Send a LinphoneInfoMessage through an established call + * @param call the call * @param info the info message - * @param addr the destination address **/ -int linphone_core_send_info_message(LinphoneCore *lc, const LinphoneInfoMessage *info, const LinphoneAddress *addr){ +int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info){ SalBody body; - linphone_configure_op(lc,info->op,addr,info->headers,FALSE); - return sal_send_info(info->op,NULL, NULL, sal_body_from_content(&body,&info->content)); + 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)); } /** @@ -164,15 +158,7 @@ void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *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){ - const SalCustomHeader *ch=sal_op_get_recv_custom_header(im->op); - return sal_custom_header_find(ch,name); -} - -/** - * Returns origin of received LinphoneInfoMessage -**/ -const char *linphone_info_message_get_from(const LinphoneInfoMessage *im){ - return sal_op_get_from(im->op); + return sal_custom_header_find(im->headers,name); } /** @@ -193,11 +179,13 @@ const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMess } void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){ - LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1); - info->op=sal_op_ref(op); - info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op)); - if (body) linphone_content_copy_from_sal_body(&info->content,body); - if (lc->vtable.info_received) - lc->vtable.info_received(lc,info); - linphone_info_message_destroy(info); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + if (call){ + LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1); + info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op)); + if (body) linphone_content_copy_from_sal_body(&info->content,body); + if (lc->vtable.info_received) + lc->vtable.info_received(lc,call,info); + linphone_info_message_destroy(info); + } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c5df3eadb..b148e1f3e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -109,6 +109,17 @@ struct _LinphoneContent{ **/ typedef struct _LinphoneContent LinphoneContent; +/** + * The LinphoneCall object represents a call issued or received by the LinphoneCore + * @ingroup call_control +**/ +struct _LinphoneCall; +/** + * The LinphoneCall object represents a call issued or received by the LinphoneCore + * @ingroup call_control +**/ +typedef struct _LinphoneCall LinphoneCall; + /** * Enum describing failure reasons. * @ingroup misc @@ -277,8 +288,8 @@ struct _LinphoneInfoMessage; **/ typedef struct _LinphoneInfoMessage LinphoneInfoMessage; -LINPHONE_PUBLIC LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc); -LINPHONE_PUBLIC int linphone_core_send_info_message(LinphoneCore *lc, const LinphoneInfoMessage *info, const LinphoneAddress *addr); +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); @@ -305,16 +316,7 @@ struct _LinphoneVideoPolicy{ **/ typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore - * @ingroup call_control -**/ -struct _LinphoneCall; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore - * @ingroup call_control -**/ -typedef struct _LinphoneCall LinphoneCall; + /** @@ -872,7 +874,7 @@ typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneC typedef void (*CallStatsUpdated)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); /** Callback prototype for receiving info messages*/ -typedef void (*LinphoneInfoReceivedCb)(struct _LinphoneCore *lc, const LinphoneInfoMessage *msg); +typedef void (*LinphoneInfoReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); /** * This structure holds all callbacks that the application should implement. * None is mandatory. diff --git a/tester/call_tester.c b/tester/call_tester.c index a5d05e0e4..32f43d9f4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -34,7 +34,7 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState ,linphone_call_state_to_string(cstate)); ms_free(to); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); switch (cstate) { case LinphoneCallIncomingReceived:counters->number_of_LinphoneCallIncomingReceived++;break; case LinphoneCallOutgoingInit :counters->number_of_LinphoneCallOutgoingInit++;break; @@ -67,7 +67,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, ms_free(to); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); switch (new_call_state) { case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; case LinphoneCallOutgoingProgress :counters->number_of_LinphoneTransferCallOutgoingProgress++;break; @@ -88,7 +88,7 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { ms_message("call from [%s] to [%s] receive iFrame",from,to); ms_free(to); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = (stats*)get_stats(lc); counters->number_of_IframeDecoded++; } @@ -444,8 +444,11 @@ static void call_with_ice(void) { CU_ASSERT_TRUE(call(pauline,marie)); CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + /*wait for the ICE reINVITE to complete*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - /*just to sleep*/ + /*then close the call*/ linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index c132abd65..9b156771d 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -31,7 +31,8 @@ void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char * } void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); + LinphoneCoreManager *mgr=get_manager(lc); LinphoneContent content; content.type="application"; @@ -44,7 +45,10 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li break; case LinphoneSubscriptionIncomingReceived: counters->number_of_LinphoneSubscriptionIncomingReceived++; - linphone_event_accept_subscription(lev); + if (!mgr->decline_subscribe) + linphone_event_accept_subscription(lev); + else + linphone_event_deny_subscription(lev, LinphoneReasonDeclined); break; case LinphoneSubscriptionOutoingInit: counters->number_of_LinphoneSubscriptionOutgoingInit++; @@ -54,48 +58,95 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li break; case LinphoneSubscriptionActive: counters->number_of_LinphoneSubscriptionActive++; - if (linphone_event_get_dir(lev)==LinphoneSubscriptionIncoming) + if (linphone_event_get_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; } } - - - - -static void subscribe_test() { +static void subscribe_test_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneContent content; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); + content.type="application"; content.subtype="somexml"; content.data=(char*)subscribe_content; content.size=strlen(subscribe_content); + pauline->decline_subscribe=TRUE; + linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void subscribe_test_with_args(bool_t terminated_by_subscriber) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneContent content; + LinphoneEvent *lev; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + if (terminated_by_subscriber){ + linphone_event_terminate(lev); + }else{ + linphone_event_terminate(pauline->lev); + } + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void subscribe_test_terminated_by_subscriber(void){ + subscribe_test_with_args(TRUE); +} + +static void subscribe_test_terminated_by_notifier(void){ + subscribe_test_with_args(FALSE); +} + test_t subscribe_tests[] = { - { "Subscribe", subscribe_test }, + { "Subscribe declined" , subscribe_test_declined }, + { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, + { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier } }; test_suite_t subscribe_test_suite = { diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f71b29345..05ea483d8 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -75,7 +75,7 @@ void auth_info_requested(LinphoneCore *lc, const char *realm, const char *userna ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); counters->number_of_auth_info_requested++; info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ @@ -116,7 +116,7 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c sprintf(filepath, "%s/%s", path, file); lc = linphone_core_new(v_table,NULL,filepath,NULL); linphone_core_set_user_data(lc,&global_stat); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); /* until we have good certificates on our test server... linphone_core_verify_server_certificates(lc,FALSE);*/ @@ -180,8 +180,18 @@ static void enable_codec(LinphoneCore* lc,const char* type,int rate) { ms_list_free(codecs); } +stats * get_stats(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return &manager->stat; +} + +LinphoneCoreManager *get_manager(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return manager; +} + LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies) { - LinphoneCoreManager* mgr= malloc(sizeof(LinphoneCoreManager)); + LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); LinphoneProxyConfig* proxy; memset (mgr,0,sizeof(LinphoneCoreManager)); mgr->v_table.registration_state_changed=registration_state_changed; @@ -196,7 +206,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc mgr->v_table.notify_received=linphone_notify_received; mgr->lc=configure_lc_from(&mgr->v_table, path, rc_file, check_for_proxies?(rc_file?1:0):0); enable_codec(mgr->lc,"PCMU",8000); - linphone_core_set_user_data(mgr->lc,&mgr->stat); + linphone_core_set_user_data(mgr->lc,mgr); linphone_core_get_default_proxy(mgr->lc,&proxy); if (proxy) { mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); @@ -212,7 +222,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { if (mgr->lc) linphone_core_destroy(mgr->lc); if (mgr->identity) linphone_address_destroy(mgr->identity); - free(mgr); + ms_free(mgr); } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 9e8eb6f24..8a751d622 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -152,6 +152,8 @@ typedef struct _LinphoneCoreManager { LinphoneCore* lc; stats stat; LinphoneAddress* identity; + LinphoneEvent *lev; + bool_t decline_subscribe; } LinphoneCoreManager; LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies); @@ -166,7 +168,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); -void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg); +void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); @@ -179,5 +181,8 @@ 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 call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); +stats * get_stats(LinphoneCore *lc); +LinphoneCoreManager *get_manager(LinphoneCore *lc); + #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/message_tester.c b/tester/message_tester.c index a9beef3ed..7d2b1ea7e 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -24,7 +24,7 @@ void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); counters->number_of_LinphoneMessageReceivedLegacy++; } @@ -35,7 +35,7 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess ,linphone_chat_message_get_text(message) ,linphone_chat_message_get_external_body_url(message)); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; if (linphone_chat_message_get_external_body_url(message)) counters->number_of_LinphoneMessageExtBodyReceived++; @@ -43,7 +43,7 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { LinphoneCore* lc=(LinphoneCore*)ud; - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); switch (state) { case LinphoneChatMessageStateDelivered: @@ -163,8 +163,8 @@ static void text_message_with_send_error(void) { static const char *info_content="blabla"; -void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg){ - stats* counters = (stats*)linphone_core_get_user_data(lc); +void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneInfoMessage *msg){ + stats* counters = get_stats(lc); const char *hvalue=linphone_info_message_get_header(msg, "Weather"); const LinphoneContent *content=linphone_info_message_get_content(msg); CU_ASSERT_PTR_NOT_NULL_FATAL(hvalue); @@ -189,7 +189,11 @@ void info_message_received(LinphoneCore *lc, const LinphoneInfoMessage *msg){ static void info_message_with_args(bool_t with_content) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - LinphoneInfoMessage *info=linphone_core_create_info_message(marie->lc); + LinphoneInfoMessage *info; + + CU_ASSERT_TRUE(call(pauline,marie)); + + info=linphone_core_create_info_message(marie->lc); linphone_info_message_add_header(info,"Weather","still bad"); if (with_content) { LinphoneContent ct; @@ -199,7 +203,7 @@ static void info_message_with_args(bool_t with_content) { ct.size=strlen(info_content); linphone_info_message_set_content(info,&ct); } - linphone_core_send_info_message(marie->lc,info,pauline->identity); + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),info); linphone_info_message_destroy(info); if (with_content){ diff --git a/tester/presence_tester.c b/tester/presence_tester.c index bc9bf24bd..18308f13e 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -36,7 +36,7 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * stats* counters; ms_message("New subscription request from [%s] url [%s]",from,url); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); counters->number_of_NewSubscriptionRequest++; linphone_core_add_friend(lc,lf); /*accept subscription*/ } @@ -46,7 +46,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { char* from=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("New Notify request from [%s] ",from); ms_free(from); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); counters->number_of_NotifyReceived++; switch(linphone_friend_get_status(lf)) { diff --git a/tester/register_tester.c b/tester/register_tester.c index 16916df2c..2ca84945b 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -34,7 +34,7 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c ,linphone_registration_state_to_string(cstate) ,linphone_proxy_config_get_identity(cfg) ,linphone_proxy_config_get_addr(cfg)); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); switch (cstate) { case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; @@ -58,7 +58,7 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const CU_ASSERT_PTR_NOT_NULL(lc); if (!lc) return; - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); reset_counters(counters); linphone_core_set_sip_transports(lc,&transport); @@ -106,7 +106,7 @@ static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const ch } static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); register_with_refresh_base(lc,refresh,domain,route); linphone_core_destroy(lc); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); @@ -117,7 +117,7 @@ static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* d static void register_with_refresh_with_send_error() { int retry=0; LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); @@ -140,7 +140,7 @@ static void register_with_refresh_with_send_error() { static void simple_register(){ LinphoneCore* lc = create_lc(); - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); register_with_refresh(lc,FALSE,NULL,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } @@ -148,14 +148,14 @@ static void simple_register(){ /*take care of min expires configuration from server*/ static void simple_register_with_refresh() { LinphoneCore* lc = create_lc(); - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); register_with_refresh(lc,TRUE,NULL,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } static void simple_auth_register_with_refresh() { LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = (stats*)linphone_core_get_user_data(lc); + stats* counters = get_stats(lc); char route[256]; sprintf(route,"sip:%s",test_route); register_with_refresh(lc,TRUE,auth_domain,route); @@ -195,7 +195,7 @@ static void simple_authenticated_register(){ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_with_refresh(lc,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } @@ -210,7 +210,7 @@ static void ha1_authenticated_register(){ info=linphone_auth_info_new(test_username,NULL,NULL,ha1,auth_domain); /*create authentication structure from identity*/ sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_with_refresh(lc,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } @@ -227,7 +227,7 @@ static void authenticated_register_with_no_initial_credentials(){ v_table.auth_info_requested=auth_info_requested; lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); - counters= (stats*)linphone_core_get_user_data(lc); + counters= get_stats(lc); counters->number_of_auth_info_requested=0; register_with_refresh(lc,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); @@ -238,7 +238,7 @@ static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); counters->number_of_auth_info_requested++; } @@ -255,7 +255,7 @@ static void authenticated_register_with_late_credentials(){ v_table.auth_info_requested=auth_info_requested2; lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_with_refresh_base_2(lc,FALSE,auth_domain,route,TRUE,transport); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_destroy(lc); @@ -276,7 +276,7 @@ static void authenticated_register_with_wrong_credentials(){ lc = linphone_core_new(&v_table,NULL,NULL,NULL); linphone_core_set_user_data(lc,&stat); linphone_core_add_auth_info(lc,info); /*add wrong authentication info to LinphoneCore*/ - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_with_refresh_base_2(lc,TRUE,auth_domain,route,TRUE,transport); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_destroy(lc); @@ -304,7 +304,7 @@ static void network_state_change(){ memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; linphone_core_set_network_reachable(lc,FALSE); CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); @@ -336,7 +336,7 @@ static void transport_change(){ memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); @@ -364,7 +364,7 @@ static void io_recv_error(){ memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); - counters = (stats*)linphone_core_get_user_data(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); @@ -388,7 +388,7 @@ static void io_recv_error_without_active_register(){ memset (&v_table,0,sizeof(LinphoneCoreVTable)); v_table.registration_state_changed=registration_state_changed; lc=configure_lc(&v_table); - counters = (stats*)linphone_core_get_user_data(lc); + counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); @@ -418,14 +418,14 @@ static void tls_certificate_failure(){ LinphoneCoreVTable v_table; LinphoneCore* lc; stats stat; - //stats* counters; + char rootcapath[256]; memset (&v_table,0,sizeof(v_table)); reset_counters(&stat); v_table.registration_state_changed=registration_state_changed; lc = configure_lc_from(&v_table,liblinphone_tester_file_prefix, "pauline_rc", 0); linphone_core_set_user_data(lc,&stat); - //counters = (stats*)linphone_core_get_user_data(lc); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ linphone_core_set_root_ca(lc,rootcapath); linphone_core_set_network_reachable(lc,TRUE); From fbf909e3b06dfb6dac072244e9804915e77c6725 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 21:03:51 +0200 Subject: [PATCH 422/909] update oRTP and ms2 --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3f06cd60f..795498987 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3f06cd60f1864b8c811e0f4e4590991802ce5ea7 +Subproject commit 7954989874f35e23c6580e1ba9a0b17ce64bd0b3 diff --git a/oRTP b/oRTP index 1a103971b..462296433 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 1a103971b84d39510ad14f327bd6834b3d88063f +Subproject commit 462296433f10bd84cb605edb0b38d16a4cd81d9e From 8c3fd2d4325fe1be53e3fb26a07afa52f0361a10 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 21:39:57 +0200 Subject: [PATCH 423/909] adapt java to modifications of info api --- build/android/common.mk | 4 +++- .../core/tutorials/TutorialBuddyStatus.java | 2 +- .../core/tutorials/TutorialChatRoom.java | 2 +- .../core/tutorials/TutorialHelloWorld.java | 2 +- .../core/tutorials/TutorialRegistration.java | 2 +- coreapi/linphonecore_jni.cc | 20 ++++++------------- .../org/linphone/core/LinphoneCall.java | 5 +++++ .../org/linphone/core/LinphoneCore.java | 8 +------- .../linphone/core/LinphoneCoreListener.java | 2 +- .../linphone/core/LinphoneInfoMessage.java | 6 +----- .../org/linphone/core/LinphoneCallImpl.java | 5 +++++ .../org/linphone/core/LinphoneCoreImpl.java | 5 ----- .../core/LinphoneInfoMessageImpl.java | 6 ------ 13 files changed, 26 insertions(+), 43 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index aeedab67b..67bcd336c 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -45,6 +45,7 @@ LOCAL_SRC_FILES := \ bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_op_publish.c \ bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_events.c \ bellesip_sal/sal_sdp.c \ sal.c \ offeranswer.c \ @@ -54,7 +55,8 @@ LOCAL_SRC_FILES := \ ec-calibrator.c \ linphone_tunnel_config.c \ message_storage.c \ - info.c + info.c \ + event.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index a65e0528c..1f1dce9f2 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -250,7 +250,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } @Override - public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { // TODO Auto-generated method stub } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index e64750122..ecd5846d6 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -172,7 +172,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } @Override - public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { // TODO Auto-generated method stub } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index ea659e60b..10d3a2ce5 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -176,7 +176,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } @Override - public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { // TODO Auto-generated method stub } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index c8a827511..e8373b0d4 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -207,7 +207,7 @@ public class TutorialRegistration implements LinphoneCoreListener { } @Override - public void infoReceived(LinphoneCore lc, LinphoneInfoMessage info) { + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { // TODO Auto-generated method stub } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 85dd369d5..0e0eae1b4 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -197,7 +197,8 @@ public: textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); - infoReceivedId = env->GetMethodID(listenerClass,"infoReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneInfoMessage;)V"); + infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V"); proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -536,7 +537,7 @@ public: ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)remote_call_state) ); } - static void infoReceived(LinphoneCore *lc, const LinphoneInfoMessage *info){ + static void infoReceived(LinphoneCore *lc, LinphoneCall*call, const LinphoneInfoMessage *info){ JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); jobject jcall; @@ -549,6 +550,7 @@ public: env->CallVoidMethod(lcData->listener ,lcData->infoReceivedId ,lcData->core + ,lcData->getCall(env,call) ,env->NewObject(lcData->infoMessageClass,lcData->infoMessageCtor,(jlong)copy_info) ); } @@ -606,8 +608,8 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneCoreImpl_createInfoMessag return (jlong) linphone_core_create_info_message((LinphoneCore*)lcptr); } -JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_sendInfoMessage(JNIEnv *env, jobject jobj, jlong lcptr, jlong infoptr, jlong addrptr){ - return linphone_core_send_info_message((LinphoneCore*)lcptr,(LinphoneInfoMessage*)infoptr,(LinphoneAddress*)addrptr); +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_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) { @@ -2696,16 +2698,6 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getHead return ret ? env->NewStringUTF(ret) : NULL; } -/* - * Class: org_linphone_core_LinphoneInfoMessageImpl - * Method: getFrom - * Signature: (J)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getFrom(JNIEnv *env , jobject jobj, jlong infoptr){ - const char *from=linphone_info_message_get_from((LinphoneInfoMessage*)infoptr); - return from ? env->NewStringUTF(from) : NULL; -} - /* * Class: org_linphone_core_LinphoneInfoMessageImpl * Method: delete diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 3328b2959..35dc9008b 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -298,4 +298,9 @@ public interface LinphoneCall { * @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); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index c3c26e946..0424a797c 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1262,16 +1262,10 @@ public interface LinphoneCore { /** * Create an empty INFO message. - * It can later be sent using {@link LinphoneCore.sendInfoMessage() }. + * It can later be sent using {@link LinphoneCall.sendInfoMessage() }. * @return the new info message. */ public LinphoneInfoMessage createInfoMessage(); - /** - * Send an INFO message to specified destination. - * @param info the info message - * @param dest the destination sip address. - */ - public void sendInfoMessage(LinphoneInfoMessage info, LinphoneAddress dest); } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 1d85a07ca..b3ff9bbfc 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -130,7 +130,7 @@ public interface LinphoneCoreListener { * @param lc the LinphoneCore. * @param info the info message */ - void infoReceived(LinphoneCore lc, LinphoneInfoMessage info); + void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info); /**< @Deprecated Notifies the application that it should show up * @return */ diff --git a/java/common/org/linphone/core/LinphoneInfoMessage.java b/java/common/org/linphone/core/LinphoneInfoMessage.java index 93ee6a7ec..00362e987 100644 --- a/java/common/org/linphone/core/LinphoneInfoMessage.java +++ b/java/common/org/linphone/core/LinphoneInfoMessage.java @@ -2,6 +2,7 @@ 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 * */ @@ -28,9 +29,4 @@ public interface LinphoneInfoMessage { * @return the header's value */ String getHeader(String name); - /** - * Get the origin of the info message as a string URI. - * @return origin of the message. - */ - String getFrom(); } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index afe0afc00..5c681506f 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -212,4 +212,9 @@ class LinphoneCallImpl implements LinphoneCall { 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); + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index a414baf7a..4b0232113 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -954,9 +954,4 @@ class LinphoneCoreImpl implements LinphoneCore { public LinphoneInfoMessage createInfoMessage() { return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); } - private native int sendInfoMessage(long corePtr, long infoptr, long destptr); - @Override - public void sendInfoMessage(LinphoneInfoMessage info, LinphoneAddress dest) { - sendInfoMessage(nativePtr,((LinphoneInfoMessageImpl)info).nativePtr, ((LinphoneAddressImpl)dest).nativePtr); - } } diff --git a/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java index 06c31dd42..7b9fad362 100644 --- a/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java @@ -33,12 +33,6 @@ public class LinphoneInfoMessageImpl implements LinphoneInfoMessage { public String getHeader(String name) { return getHeader(nativePtr,name); } - - private native String getFrom(long nativePtr); - @Override - public String getFrom() { - return getFrom(nativePtr); - } private native void delete(long nativePtr); protected void finalize(){ From 59b86f49ccce0c3984e1619886dc192c3c6b504b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Jun 2013 22:06:37 +0200 Subject: [PATCH 424/909] fix test --- tester/eventapi_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 9b156771d..b21d9eb79 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -93,7 +93,7 @@ static void subscribe_test_declined(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip will wait 20 secs in case of forking*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); linphone_core_manager_destroy(marie); From 5bf2d283efdf9094bff2c1ce0598b9f4b50426ca Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 7 Jun 2013 16:23:07 +0200 Subject: [PATCH 425/909] update ms2 with better opus integration --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 60edaade5..ff9b20e9f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 60edaade52a6f123f2cde6140ca90378d95c9d87 +Subproject commit ff9b20e9fbccb0c3ca401544d2cdc39dd8ee629e From d7c4864e4e52dae2cf4aaafef5c26449ef2900fd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 7 Jun 2013 16:33:24 +0200 Subject: [PATCH 426/909] fix compilation issue --- coreapi/bellesip_sal/sal_op_call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index dd7ede609..173998b3f 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -438,7 +438,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else { - belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); + 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; From f9c30db4919ba4924ecba49ced7a7f4530f4c803 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 7 Jun 2013 15:41:59 +0200 Subject: [PATCH 427/909] Add missing exports. --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b148e1f3e..8d0c3deb8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1386,8 +1386,8 @@ LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); -void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); -bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); /* returns a null terminated static array of string describing the webcams */ From a9cf6dc87e1b2642b645976f66e25ccc35c1bc28 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 10 Jun 2013 15:28:01 +0200 Subject: [PATCH 428/909] Use new marshalling API. --- coreapi/bellesip_sal/sal_op_call.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f9cb812fe..43ae70aaa 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -81,13 +81,14 @@ static void sdp_process(SalOp *h){ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; - int length; + belle_sip_error_code error = BELLE_SIP_OK; + unsigned int length = 0; char buff[2048]; if (session_desc) { content_type = belle_sip_header_content_type_create("application","sdp"); - length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff)); - if (length>=sizeof(buff)) { + error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,sizeof(buff),&length); + if (error != BELLE_SIP_OK) { ms_error("Buffer too small or sdp too big"); return -1; } From b7a487bef46dc92c89a230e1279d636f018b5b1c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 10 Jun 2013 17:39:53 +0200 Subject: [PATCH 429/909] add privacy support --- coreapi/bellesip_sal/sal_impl.c | 2 +- coreapi/bellesip_sal/sal_impl.h | 3 +++ coreapi/bellesip_sal/sal_op_impl.c | 6 +++++ coreapi/linphonecall.c | 7 ++++++ coreapi/linphonecore.h | 14 +++++++++++ coreapi/private.h | 1 + tester/call_tester.c | 39 ++++++++++++++++++++++++++++++ 7 files changed, 71 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 641884964..9c2fd6cc0 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -605,7 +605,7 @@ static void set_tls_properties(Sal *ctx){ 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; - if (ctx->root_ca) belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); + 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); } } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index ef4db521d..80ba748c2 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -90,6 +90,7 @@ struct SalOp{ belle_sip_refresher_t* refresher; int ref; SalOpType_t type; + bool_t privacy_enabled; }; @@ -144,4 +145,6 @@ 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_enable_privacy(SalOp* op,bool_t enable); +bool_t sal_op_privacy_enabled(const SalOp* op); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index ea8dd9c34..41572caa9 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -484,3 +484,9 @@ bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){ memset(salbody,0,sizeof(salbody)); return FALSE; } +void sal_op_enable_privacy(SalOp* op,bool_t enable) { + op->privacy_enabled=enable; +} + bool_t sal_op_privacy_enabled(const SalOp* op) { + return op->privacy_enabled; +} diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5ddf0bbdf..55dca4762 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1141,6 +1141,13 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); } +void linphone_call_params_enable_privacy(LinphoneCallParams *params, bool_t enable) { + params->privacy_enabled=enable; +} +bool_t linphone_call_params_privacy_enabled(const LinphoneCallParams *params) { + return params->privacy_enabled; +} + /** * Copy existing LinphoneCallParams to a new LinphoneCallParams object. **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b148e1f3e..c6915a32c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -280,6 +280,20 @@ LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); +/** + * @ingroup call_control + * indicates if from must be replaced by anonymous value as described by rfc3325. + * @param params to be modified + * @param enable TRUE to enable privacy + * */ +LINPHONE_PUBLIC void linphone_call_params_enable_privacy(LinphoneCallParams *params, bool_t enable); +/** + * @ingroup call_control + * indicates if from must be replaced by anonymous value as described by rfc3325. + * @param params object + * @return TRUE if privacy enabled + * */ +LINPHONE_PUBLIC bool_t linphone_call_params_privacy_enabled(const LinphoneCallParams *params); struct _LinphoneInfoMessage; diff --git a/coreapi/private.h b/coreapi/private.h index a93bcec47..7af6b302d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -91,6 +91,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t pad; bool_t low_bandwidth; + bool_t privacy_enabled; }; struct _LinphoneCallLog{ diff --git a/tester/call_tester.c b/tester/call_tester.c index 32f43d9f4..f67b70d0a 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -608,6 +608,44 @@ static void call_with_video_added(void) { #endif +static void call_with_privacy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + + params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_privacy(params,TRUE); + + CU_ASSERT_TRUE(call_with_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure local identity is unchanged*/ + CU_ASSERT_TRUE(linphone_address_weak_equal(linphone_call_log_get_from(linphone_call_get_call_log(c1)),pauline->identity)); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_TRUE(linphone_call_params_privacy_enabled(linphone_call_get_current_params(c2))); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + + + static void simple_conference(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); @@ -919,6 +957,7 @@ test_t call_tests[] = { #else { "SRTP ice call", srtp_ice_call }, #endif + { "Call with privacy", call_with_privacy }, { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, From 86d1df7afb5dab415e5ff7ccaa6b98bf6d39bf90 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 10 Jun 2013 16:45:41 +0200 Subject: [PATCH 430/909] rework liblinphone tester, so that every tests uses a LinphoneCoreManager object. --- tester/eventapi_tester.c | 2 +- tester/liblinphone_tester.c | 103 +++++++------- tester/liblinphone_tester.h | 3 +- tester/register_tester.c | 272 ++++++++++++++++++------------------ 4 files changed, 185 insertions(+), 195 deletions(-) diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index b21d9eb79..23f0158ab 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -93,7 +93,7 @@ static void subscribe_test_declined(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip will wait 20 secs in case of forking*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); linphone_core_manager_destroy(marie); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 05ea483d8..9f9efc237 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -24,6 +24,7 @@ #include "CUnit/CUCurses.h" #endif +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file); static test_suite_t **test_suite = NULL; static int nb_test_suites = 0; @@ -34,7 +35,7 @@ static unsigned char curses = 0; #endif -static stats global_stat; + const char* test_domain="sipopen.example.org"; const char* auth_domain="sip.example.org"; const char* test_username="liblinphone_tester"; @@ -82,63 +83,39 @@ void auth_info_requested(LinphoneCore *lc, const char *realm, const char *userna } -LinphoneCore* create_lc_with_auth(unsigned int with_auth) { - LinphoneCoreVTable v_table; - LinphoneCore* lc; - memset (&v_table,0,sizeof(v_table)); - v_table.registration_state_changed=registration_state_changed; - if (with_auth) { - v_table.auth_info_requested=auth_info_requested; - } - lc = linphone_core_new(&v_table,NULL,NULL,NULL); - linphone_core_set_user_data(lc,&global_stat); - /* until we have good certificates on our test server... */ - linphone_core_verify_server_certificates(lc,FALSE); - /*to allow testing with 127.0.0.1*/ - linphone_core_set_network_reachable(lc,TRUE); - return lc; -} + void reset_counters( stats* counters) { memset(counters,0,sizeof(stats)); } -LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, int proxy_count) { +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file) { LinphoneCore* lc; - int retry=0; - stats* counters; - char filepath[256]; - char ringpath[256]; - char ringbackpath[256]; - char rootcapath[256]; - char dnsuserhostspath[256]; + char filepath[256]={0}; + char ringpath[256]={0}; + char ringbackpath[256]={0}; + char rootcapath[256]={0}; + char dnsuserhostspath[256]={0}; - sprintf(filepath, "%s/%s", path, file); - lc = linphone_core_new(v_table,NULL,filepath,NULL); - linphone_core_set_user_data(lc,&global_stat); - counters = get_stats(lc); - - /* until we have good certificates on our test server... - linphone_core_verify_server_certificates(lc,FALSE);*/ - sprintf(rootcapath, "%s/certificates/cacert.pem", path); - linphone_core_set_root_ca(lc,rootcapath); - - sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); - sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); - - sprintf(ringpath, "%s/%s", path, "oldphone.wav"); - sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); - linphone_core_set_ring(lc, ringpath); - linphone_core_set_ringback(lc, ringbackpath); - - reset_counters(counters); - /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ - - while (counters->number_of_LinphoneRegistrationOksal, dnsuserhostspath); + + sprintf(ringpath, "%s/%s", path, "oldphone.wav"); + sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); } - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,proxy_count); return lc; } @@ -193,8 +170,12 @@ LinphoneCoreManager *get_manager(LinphoneCore *lc){ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies) { LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); LinphoneProxyConfig* proxy; - memset (mgr,0,sizeof(LinphoneCoreManager)); + int proxy_count=check_for_proxies?(rc_file?1:0):0; + int retry=0; + + memset(mgr,0,sizeof(LinphoneCoreManager)); 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; @@ -204,9 +185,18 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc 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->lc=configure_lc_from(&mgr->v_table, path, rc_file, check_for_proxies?(rc_file?1:0):0); - enable_codec(mgr->lc,"PCMU",8000); + mgr->lc=configure_lc_from(&mgr->v_table, path, rc_file); linphone_core_set_user_data(mgr->lc,mgr); + reset_counters(&mgr->stat); + /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ + + while (mgr->stat.number_of_LinphoneRegistrationOklc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count); + enable_codec(mgr->lc,"PCMU",8000); + linphone_core_get_default_proxy(mgr->lc,&proxy); if (proxy) { mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); @@ -219,6 +209,13 @@ LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_ return linphone_core_manager_new2(path, rc_file, TRUE); } +void linphone_core_manager_stop(LinphoneCoreManager *mgr){ + if (mgr->lc) { + linphone_core_destroy(mgr->lc); + mgr->lc=NULL; + } +} + void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { if (mgr->lc) linphone_core_destroy(mgr->lc); if (mgr->identity) linphone_address_destroy(mgr->identity); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 8a751d622..434c6a0a9 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -158,6 +158,7 @@ typedef struct _LinphoneCoreManager { LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies); LinphoneCoreManager* linphone_core_manager_new(const char * path, const char* rc_file); +void linphone_core_manager_stop(LinphoneCoreManager *mgr); void linphone_core_manager_destroy(LinphoneCoreManager* mgr); void reset_counters( stats* counters); @@ -174,9 +175,7 @@ void auth_info_requested(LinphoneCore *lc, const char *realm, const char *userna void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); -LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; LinphoneAddress * create_linphone_address(const char * domain); -LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, int proxy_count); 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); diff --git a/tester/register_tester.c b/tester/register_tester.c index 2ca84945b..d7dafb76f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -22,10 +22,22 @@ #include "private.h" #include "liblinphone_tester.h" +static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { + LinphoneCoreManager* mgr=linphone_core_manager_new(NULL,NULL); + + if (with_auth) { + mgr->lc->vtable.auth_info_requested=auth_info_requested; + } + + /* until we have good certificates on our test server... */ + linphone_core_verify_server_certificates(mgr->lc,FALSE); + /*to allow testing with 127.0.0.1*/ + linphone_core_set_network_reachable(mgr->lc,TRUE); + return mgr; +} - -static LinphoneCore* create_lc() { - return create_lc_with_auth(0); +static LinphoneCoreManager* create_lcm() { + return create_lcm_with_auth(0); } void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ @@ -105,132 +117,134 @@ static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const ch register_with_refresh_base_2(lc,refresh,domain,route,FALSE,transport); } -static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { - stats* counters = get_stats(lc); - register_with_refresh_base(lc,refresh,domain,route); - linphone_core_destroy(lc); +static void register_with_refresh(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route) { + stats* counters = &lcm->stat; + register_with_refresh_base(lcm->lc,refresh,domain,route); + linphone_core_manager_stop(lcm); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); - - } static void register_with_refresh_with_send_error() { int retry=0; - LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = get_stats(lc); + 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); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ - register_with_refresh_base(lc,TRUE,auth_domain,route); + register_with_refresh_base(lcm->lc,TRUE,auth_domain,route); /*simultate a network error*/ - sal_set_send_error(lc->sal, -1); + sal_set_send_error(lcm->lc->sal, -1); while (counters->number_of_LinphoneRegistrationProgress<2 && retry++ <20) { - linphone_core_iterate(lc); + linphone_core_iterate(lcm->lc); ms_usleep(100000); } CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); - linphone_core_destroy(lc); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + linphone_core_manager_destroy(lcm); } static void simple_register(){ - LinphoneCore* lc = create_lc(); - stats* counters = get_stats(lc); - register_with_refresh(lc,FALSE,NULL,NULL); + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + register_with_refresh(lcm,FALSE,NULL,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); + linphone_core_manager_destroy(lcm); } /*take care of min expires configuration from server*/ static void simple_register_with_refresh() { - LinphoneCore* lc = create_lc(); - stats* counters = get_stats(lc); - register_with_refresh(lc,TRUE,NULL,NULL); + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + register_with_refresh(lcm,TRUE,NULL,NULL); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); + linphone_core_manager_destroy(lcm); } static void simple_auth_register_with_refresh() { - LinphoneCore* lc = create_lc_with_auth(1); - stats* counters = get_stats(lc); + LinphoneCoreManager* lcm = create_lcm_with_auth(1); + stats* counters = &lcm->stat; char route[256]; sprintf(route,"sip:%s",test_route); - register_with_refresh(lc,TRUE,auth_domain,route); + register_with_refresh(lcm,TRUE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(lcm); } static void simple_tcp_register(){ char route[256]; - LinphoneCore* lc; + LinphoneCoreManager* lcm; sprintf(route,"sip:%s;transport=tcp",test_route); - lc = create_lc(); - register_with_refresh(lc,FALSE,test_domain,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]; - LinphoneCore* lc; + LinphoneCoreManager* lcm; LCSipTransports transport = {0,5070,0,0}; sprintf(route,"sip:%s",test_route); - lc = create_lc(); - register_with_refresh_base_2(lc,FALSE,test_domain,route,FALSE,transport); + lcm = create_lcm(); + register_with_refresh_base_2(lcm->lc,FALSE,test_domain,route,FALSE,transport); + linphone_core_manager_destroy(lcm); } static void simple_tls_register(){ char route[256]; - LinphoneCore* lc; + LinphoneCoreManager* lcm; sprintf(route,"sip:%s;transport=tls",test_route); - lc = create_lc(); - register_with_refresh(lc,FALSE,test_domain,route); + lcm = create_lcm(); + register_with_refresh(lcm,FALSE,test_domain,route); + linphone_core_manager_destroy(lcm); } static void simple_authenticated_register(){ stats* counters; - LinphoneCore* lc = create_lc(); + LinphoneCoreManager* lcm = create_lcm(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - counters = get_stats(lc); - register_with_refresh(lc,FALSE,auth_domain,route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } static void ha1_authenticated_register(){ stats* counters; - LinphoneCore* lc = create_lc(); + 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); /*create authentication structure from identity*/ sprintf(route,"sip:%s",test_route); - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - counters = get_stats(lc); - register_with_refresh(lc,FALSE,auth_domain,route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); } static void authenticated_register_with_no_initial_credentials(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - stats stat; + LinphoneCoreManager *mgr; stats* counters; char route[256]; + sprintf(route,"sip:%s",test_route); - memset (&v_table,0,sizeof(v_table)); - v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested; - lc = linphone_core_new(&v_table,NULL,NULL,NULL); - linphone_core_set_user_data(lc,&stat); - counters= get_stats(lc); + + mgr = linphone_core_manager_new(NULL,NULL); + + counters= get_stats(mgr->lc); counters->number_of_auth_info_requested=0; - register_with_refresh(lc,FALSE,auth_domain,route); + register_with_refresh(mgr,FALSE,auth_domain,route); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(mgr); } static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username) { @@ -243,74 +257,65 @@ static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char } static void authenticated_register_with_late_credentials(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - stats stat; + LinphoneCoreManager *mgr; stats* counters; LCSipTransports transport = {5070,5070,0,5071}; char route[256]; + sprintf(route,"sip:%s",test_route); - memset (&v_table,0,sizeof(v_table)); - v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested2; - lc = linphone_core_new(&v_table,NULL,NULL,NULL); - linphone_core_set_user_data(lc,&stat); - counters = get_stats(lc); - register_with_refresh_base_2(lc,FALSE,auth_domain,route,TRUE,transport); + + mgr = linphone_core_manager_new(NULL,NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + counters = get_stats(mgr->lc); + register_with_refresh_base_2(mgr->lc,FALSE,auth_domain,route,TRUE,transport); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } static void authenticated_register_with_wrong_credentials(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - stats stat; + LinphoneCoreManager *mgr; stats* counters; LCSipTransports transport = {5070,5070,0,5071}; LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain); /*create authentication structure from identity*/ char route[256]; + sprintf(route,"sip:%s",test_route); - memset (&v_table,0,sizeof(v_table)); - v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested2; - lc = linphone_core_new(&v_table,NULL,NULL,NULL); - linphone_core_set_user_data(lc,&stat); - linphone_core_add_auth_info(lc,info); /*add wrong authentication info to LinphoneCore*/ - counters = get_stats(lc); - register_with_refresh_base_2(lc,TRUE,auth_domain,route,TRUE,transport); + + mgr=linphone_core_manager_new(NULL,NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + + linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/ + counters = get_stats(mgr->lc); + register_with_refresh_base_2(mgr->lc,TRUE,auth_domain,route,TRUE,transport); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } -static LinphoneCore* configure_lc(LinphoneCoreVTable* v_table) { - return configure_lc_from(v_table, liblinphone_tester_file_prefix, "multi_account_lrc", 3); +static LinphoneCoreManager* configure_lcm(void) { + LinphoneCoreManager *mgr=linphone_core_manager_new( liblinphone_tester_file_prefix, "multi_account_lrc"); + stats *counters=&mgr->stat; + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)))); + return mgr; } static void multiple_proxy(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); - linphone_core_destroy(lc); + LinphoneCoreManager *mgr=configure_lcm(); + linphone_core_manager_destroy(mgr); } static void network_state_change(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; int register_ok; - stats* counters ; - - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); + stats *counters; + LinphoneCoreManager *mgr=configure_lcm(); + LinphoneCore *lc=mgr->lc; + counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; linphone_core_set_network_reachable(lc,FALSE); CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); linphone_core_set_network_reachable(lc,TRUE); wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } static int get_number_of_udp_proxy(const LinphoneCore* lc) { int number_of_udp_proxy=0; @@ -324,7 +329,7 @@ static int get_number_of_udp_proxy(const LinphoneCore* lc) { return number_of_udp_proxy; } static void transport_change(){ - LinphoneCoreVTable v_table; + LinphoneCoreManager *mgr; LinphoneCore* lc; int register_ok; stats* counters ; @@ -333,9 +338,9 @@ static void transport_change(){ int number_of_udp_proxy=0; int total_number_of_proxies; memset(&sip_tr,0,sizeof(sip_tr)); - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); + + mgr=configure_lcm(); + lc=mgr->lc; counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; @@ -351,19 +356,19 @@ static void transport_change(){ CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,total_number_of_proxies-number_of_udp_proxy)); - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } static void io_recv_error(){ - LinphoneCoreVTable v_table; + LinphoneCoreManager *mgr; LinphoneCore* lc; int register_ok; stats* counters ; int number_of_udp_proxy=0; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); + + mgr=configure_lcm(); + lc=mgr->lc; counters = get_stats(lc); register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); @@ -374,21 +379,21 @@ static void io_recv_error(){ sal_set_recv_error(lc->sal, 1); /*reset*/ - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } static void io_recv_error_without_active_register(){ - LinphoneCoreVTable v_table; + LinphoneCoreManager *mgr; LinphoneCore* lc; int register_ok; stats* counters ; int number_of_udp_proxy=0; MSList* proxys; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - lc=configure_lc(&v_table); + mgr=configure_lcm(); + lc=mgr->lc; counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; number_of_udp_proxy=get_number_of_udp_proxy(lc); @@ -410,63 +415,52 @@ static void io_recv_error_without_active_register(){ sal_set_recv_error(lc->sal, 1); /*reset*/ - linphone_core_destroy(lc); + linphone_core_manager_destroy(mgr); } static void tls_certificate_failure(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - stats stat; - + LinphoneCoreManager* mgr; + LinphoneCore *lc; char rootcapath[256]; - memset (&v_table,0,sizeof(v_table)); - reset_counters(&stat); - v_table.registration_state_changed=registration_state_changed; - lc = configure_lc_from(&v_table,liblinphone_tester_file_prefix, "pauline_rc", 0); - linphone_core_set_user_data(lc,&stat); + mgr=linphone_core_manager_new2(liblinphone_tester_file_prefix, "pauline_rc",FALSE); + lc=mgr->lc; snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ - linphone_core_set_root_ca(lc,rootcapath); + linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_set_network_reachable(lc,TRUE); - CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,1)); - linphone_core_set_root_ca(lc,NULL); /*no root ca*/ - linphone_core_refresh_registers(lc); - CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,2)); + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); + linphone_core_set_root_ca(mgr->lc,NULL); /*no root ca*/ + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,2)); snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ - linphone_core_set_root_ca(lc,rootcapath); - linphone_core_refresh_registers(lc); - CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationOk,1)); - CU_ASSERT_EQUAL(stat.number_of_LinphoneRegistrationFailed,2); - linphone_core_destroy(lc); + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,2); + linphone_core_destroy(mgr->lc); } static void tls_with_non_tls_server(){ - LinphoneCoreVTable v_table; - LinphoneCore* lc; - stats stat; - //stats* counters; - + LinphoneCoreManager *mgr; LinphoneProxyConfig* proxy_cfg; LinphoneAddress* addr; char tmp[256]; - memset (&v_table,0,sizeof(v_table)); - reset_counters(&stat); - v_table.registration_state_changed=registration_state_changed; - lc = configure_lc_from(&v_table,liblinphone_tester_file_prefix, "marie_rc", 0); - linphone_core_set_user_data(lc,&stat); - //counters = (stats*)linphone_core_get_user_data(lc); + LinphoneCore *lc; + + mgr=linphone_core_manager_new2(liblinphone_tester_file_prefix, "marie_rc", 0); + lc=mgr->lc; linphone_core_get_default_proxy(lc,&proxy_cfg); linphone_proxy_config_edit(proxy_cfg); addr=linphone_address_new(linphone_proxy_config_get_addr(proxy_cfg)); snprintf(tmp,sizeof(tmp),"sip:%s:%i;transport=tls" ,linphone_address_get_domain(addr) - ,(linphone_address_get_port_int(addr)>0?linphone_address_get_port_int(addr):5060)); + ,(linphone_address_get_port_int(addr)>0?linphone_address_get_port_int(addr):5060)); linphone_proxy_config_set_server_addr(proxy_cfg,tmp); linphone_proxy_config_done(proxy_cfg); linphone_address_destroy(addr); - CU_ASSERT_TRUE(wait_for(lc,lc,&stat.number_of_LinphoneRegistrationFailed,1)); - linphone_core_destroy(lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); + linphone_core_manager_destroy(mgr); } test_t register_tests[] = { From cebe1f1055808b8a24198962bf73f091a1f8c933 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 11 Jun 2013 09:14:28 +0200 Subject: [PATCH 431/909] start privacy impelmentation --- coreapi/linphonecall.c | 17 ++++++++++++----- coreapi/linphonecore.c | 1 + coreapi/linphonecore.h | 35 +++++++++++++++++++++++++++++------ coreapi/private.h | 5 ++++- tester/call_tester.c | 4 ++-- 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 55dca4762..ef97be71e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1141,13 +1141,20 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); } -void linphone_call_params_enable_privacy(LinphoneCallParams *params, bool_t enable) { - params->privacy_enabled=enable; +void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacy privacy) { + params->privacy=privacy; } -bool_t linphone_call_params_privacy_enabled(const LinphoneCallParams *params) { - return params->privacy_enabled; +LinphonePrivacy linphone_call_params_get_privacy(const LinphoneCallParams *params) { + return params->privacy; +} +const char* linphone_privacy_to_string(LinphonePrivacy privacy) { + switch(privacy) { + case LinphonePrivacyDefault: return "LinphonePrivacyDefault"; + case LinphonePrivacyId: return "LinphonePrivacyId"; + case LinphonePrivacyNone: return "LinphonePrivacyNone"; + default: return "Unknown privacy mode"; + } } - /** * Copy existing LinphoneCallParams to a new LinphoneCallParams object. **/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 13529889e..7ecc917b2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5888,6 +5888,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate; params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; + params->privacy=LinphonePrivacyNone; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6848b4f43..9e82de6c7 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -280,20 +280,43 @@ LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); +/*** + * @ingroup call_control + * Defines privacy policy to apply as described by rfc3325 + * */ +typedef enum _LinphonePrivacy { + /** + * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy + */ + LinphonePrivacyDefault, + /** + * With this mode, "from" header is hidden, usually replaced by From: "Anonymous" + */ + LinphonePrivacyId, + /** + * No privacy action are taken + */ + LinphonePrivacyNone +} LinphonePrivacy; /** * @ingroup call_control - * indicates if from must be replaced by anonymous value as described by rfc3325. + * @return string value of LinphonePrivacy enum + * */ +const char* linphone_privacy_to_string(LinphonePrivacy privacy); +/** + * @ingroup call_control + * Indicates if "from" must be replaced by anonymous value as described by rfc3325. * @param params to be modified - * @param enable TRUE to enable privacy + * @param LinphonePrivacy to configure privacy * */ -LINPHONE_PUBLIC void linphone_call_params_enable_privacy(LinphoneCallParams *params, bool_t enable); +LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacy privacy); /** * @ingroup call_control - * indicates if from must be replaced by anonymous value as described by rfc3325. + * indicates if "from" must be replaced by anonymous value as described by rfc3325. * @param params object - * @return TRUE if privacy enabled + * @return Privacy mode * */ -LINPHONE_PUBLIC bool_t linphone_call_params_privacy_enabled(const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphonePrivacy linphone_call_params_get_privacy(const LinphoneCallParams *params); struct _LinphoneInfoMessage; diff --git a/coreapi/private.h b/coreapi/private.h index 7af6b302d..db628274b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -74,6 +74,9 @@ extern "C" { #endif #endif +struct LinphoneParams { + +}; struct _LinphoneCallParams{ 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 */ @@ -91,7 +94,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t pad; bool_t low_bandwidth; - bool_t privacy_enabled; + LinphonePrivacy privacy; }; struct _LinphoneCallLog{ diff --git a/tester/call_tester.c b/tester/call_tester.c index f67b70d0a..f075add6a 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -615,7 +615,7 @@ static void call_with_privacy(void) { LinphoneCallParams *params; params=linphone_core_create_default_call_parameters(pauline->lc); - linphone_call_params_enable_privacy(params,TRUE); + linphone_call_params_set_privacy(params,LinphonePrivacyId); CU_ASSERT_TRUE(call_with_params(pauline,marie,params)); linphone_call_params_destroy(params); @@ -632,7 +632,7 @@ static void call_with_privacy(void) { /*make sure remote identity is hidden*/ CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); - CU_ASSERT_TRUE(linphone_call_params_privacy_enabled(linphone_call_get_current_params(c2))); + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); From 411b841bb04289e21e053e02970830fb8b9e0f3c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 11 Jun 2013 12:32:50 +0200 Subject: [PATCH 432/909] Use size_t instead of unsigned int for offset parameter of marshal function. --- coreapi/bellesip_sal/sal_op_call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 43ae70aaa..05157cb04 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -82,7 +82,7 @@ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* ses belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; belle_sip_error_code error = BELLE_SIP_OK; - unsigned int length = 0; + size_t length = 0; char buff[2048]; if (session_desc) { From 4042c86ad4477c4cd4098a343a9386e67e4111a4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 11 Jun 2013 14:23:27 +0200 Subject: [PATCH 433/909] Added setDomain to Java LinphoneAddress --- coreapi/linphonecore_jni.cc | 9 ++++++++- java/impl/org/linphone/core/LinphoneAddressImpl.java | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 5619993ab..1dfaf3c3c 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1387,7 +1387,14 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* return NULL; } } - +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jdomain) { + const char* domain = env->GetStringUTFChars(jdomain, NULL); + linphone_address_set_domain((LinphoneAddress*)ptr, domain); + env->ReleaseStringUTFChars(jdomain, domain); +} extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index b9d290971..8d76da77a 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -31,6 +31,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { private native String toUri(long ptr); private native void setDisplayName(long ptr,String name); private native String toString(long ptr); + private native void setDomain(long ptr, String domain); protected LinphoneAddressImpl(String identity) { nativePtr = newLinphoneAddressImpl(identity, null); @@ -85,7 +86,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { return getPortInt(); } public void setDomain(String domain) { - throw new RuntimeException("Not implemented"); + setDomain(nativePtr, domain); } public void setPort(String port) { throw new RuntimeException("Not implemented"); From 9e60a96b18b385d9a92193abe372a6314765fda5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 11 Jun 2013 22:34:04 +0200 Subject: [PATCH 434/909] add contact header in REFER requests update ms2 --- coreapi/bellesip_sal/sal_op_impl.c | 3 ++- mediastreamer2 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 41572caa9..625cc6ef4 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -250,7 +250,8 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { 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),"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); diff --git a/mediastreamer2 b/mediastreamer2 index ff9b20e9f..ff71abf33 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff9b20e9fbccb0c3ca401544d2cdc39dd8ee629e +Subproject commit ff71abf33ae17a2f1221514f3fa7a7fec54c2168 From 8d0c8ff41c069684242ac7cf1974e9e802eb7be3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Jun 2013 11:11:35 +0200 Subject: [PATCH 435/909] update ms2 for H263 4CIF support --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ff9b20e9f..f4b3768c9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff9b20e9fbccb0c3ca401544d2cdc39dd8ee629e +Subproject commit f4b3768c9b92bf8d0977374b4a8b5d229c4d393e From 686a4709782039ae37dfac9c2c32e93570d9fd7e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Jun 2013 22:09:27 +0200 Subject: [PATCH 436/909] fix mistake in resolution table --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7ecc917b2..edaae9434 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4838,7 +4838,7 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { static MSVideoSizeDef supported_resolutions[]={ #ifdef ENABLE_HD { {MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H} , "1080p" }, - { {MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H} , "1080p" }, + { {MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H} , "720p" }, #endif { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, From e5f1ae5773553c17e0341e2eb6d308df95d2cc61 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Jun 2013 22:19:26 +0200 Subject: [PATCH 437/909] add patch for vacation status --- coreapi/bellesip_sal/sal_op_presence.c | 22 +++++++++++++++++++++- coreapi/friend.c | 5 +++++ coreapi/linphonefriend.h | 5 +++++ coreapi/presence.c | 3 +++ coreapi/sal_eXosip2_presence.c | 22 +++++++++++++++++++++- include/sal/sal.h | 1 + tester/presence_tester.c | 3 ++- 7 files changed, 58 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index b68ef1f33..af321069b 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -325,6 +325,23 @@ entity=\"%s\">\n\ \n\ \n\ ", +contact_info, contact_info); + } + else if (online_status == SalPresenceOnVacation) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +", contact_info, contact_info); } else if (online_status==SalPresenceOnthephone) @@ -356,7 +373,7 @@ entity=\"%s\">\n\ %s\n\ \n\ \n\ -\n\ +\n\ Out to lunch \n\ \n\ ", @@ -533,12 +550,15 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques || strstr(body,"on-the-phone")!=NULL){ estatus=SalPresenceOnthephone; }else if (strstr(body,"outtolunch")!=NULL + || strstr(body,"lunch")!=NULL || strstr(body,"meal")!=NULL){ estatus=SalPresenceOuttolunch; }else if (strstr(body,"closed")!=NULL){ estatus=SalPresenceOffline; }else if ((strstr(body,"online")!=NULL) || (strstr(body,"open")!=NULL)) { estatus=SalPresenceOnline; + }else if((strstr(body,"vacation")!=NULL)) { + estatus = SalPresenceOnVacation; }else{ estatus=SalPresenceOffline; } diff --git a/coreapi/friend.c b/coreapi/friend.c index 5c548d706..8bd252aed 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -62,6 +62,8 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ case LinphoneStatusPending: str=_("Pending"); break; + case LinphoneStatusVacation: + str=_("Vacation"); default: str=_("Unknown-bug"); } @@ -259,6 +261,9 @@ SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){ case LinphoneStatusPending: return SalPresenceOffline; break; + case LinphoneStatusVacation: + return SalPresenceOnVacation; + break; default: return SalPresenceOffline; break; diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index b8a041b14..cd5e74a48 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -97,6 +97,11 @@ typedef enum _LinphoneOnlineStatus{ */ LinphoneStatusPending, + /** + * Vacation + */ + LinphoneStatusVacation, + LinphoneStatusEnd }LinphoneOnlineStatus; diff --git a/coreapi/presence.c b/coreapi/presence.c index 5289a2301..2eb11ff64 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -131,6 +131,9 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa case SalPresenceDonotdisturb: estatus=LinphoneStatusDoNotDisturb; break; + case SalPresenceOnVacation: + estatus=LinphoneStatusVacation; + break; case SalPresenceMoved: case SalPresenceAltService: estatus=LinphoneStatusMoved; diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index b9f7b5763..c99a48793 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -520,6 +520,23 @@ contact_info, contact_info); "\n" "\n" "", +contact_info, contact_info); + } + else if (online_status == SalPresenceOnVacation) + { + snprintf(buf, buflen, "\n" +"\n" +"\n" +"open\n" +"%s\n" +"\n" +"\n" +"\n" +"\n" +"", contact_info, contact_info); } else if (online_status==SalPresenceOnthephone) @@ -551,7 +568,7 @@ contact_info, contact_info); "%s\n" "\n" "\n" -"\n" +"\n" "Out to lunch \n" "\n" "", @@ -737,12 +754,15 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ || strstr(body->body,"on-the-phone")!=NULL){ estatus=SalPresenceOnthephone; }else if (strstr(body->body,"outtolunch")!=NULL + || strstr(body->body,"lunch") != 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 if(strstr(body->body,"vacation") != NULL) { + estatus = SalPresenceOnVacation; }else{ estatus=SalPresenceOffline; } diff --git a/include/sal/sal.h b/include/sal/sal.h index d3efc5722..7ace50bdb 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -288,6 +288,7 @@ typedef enum SalPresenceStatus{ SalPresenceDonotdisturb, SalPresenceMoved, SalPresenceAltService, + SalPresenceOnVacation }SalPresenceStatus; const char* sal_presence_status_to_string(const SalPresenceStatus status); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 18308f13e..543caccbe 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -62,7 +62,8 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { case LinphoneStatusAltService: counters->number_of_LinphoneStatusMoved++; break; case LinphoneStatusPending: counters->number_of_LinphoneStatusPending++; break; case LinphoneStatusEnd: counters->number_of_LinphoneStatusEnd++; break; - + default: + break; } } From 500d97e548cd8c90c55e20048c04fc395e46c8f5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 13 Jun 2013 08:35:38 +0200 Subject: [PATCH 438/909] add privacy settings at proxy level --- coreapi/bellesip_sal/sal_impl.c | 41 ++++++++++++++++++- coreapi/bellesip_sal/sal_impl.h | 4 +- coreapi/bellesip_sal/sal_op_impl.c | 36 ++++++++++++++--- coreapi/callbacks.c | 7 +++- coreapi/linphonecall.c | 21 ++++++++-- coreapi/linphonecore.c | 6 ++- coreapi/linphonecore.h | 65 ++++++++++++++++++++++++++---- coreapi/private.h | 6 +-- coreapi/proxy.c | 10 +++++ coreapi/sal.c | 11 +++++ include/sal/sal.h | 18 +++++++++ tester/call_tester.c | 29 +++++++++++-- tester/message_tester.c | 30 ++++++++++++++ 13 files changed, 254 insertions(+), 30 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 9c2fd6cc0..1583871e1 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -22,7 +22,40 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif - +/* +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) { @@ -206,7 +239,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev if (!op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_call_id_t)))); } - + /*It is worth noting that proxies can (and + will) remove this header field*/ + sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req); + sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); if (op->callbacks.process_request_event) { op->callbacks.process_request_event(op,event); @@ -246,6 +282,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (!op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); } + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); if (op->callbacks.process_response_event) { diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 80ba748c2..61ef731d8 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -90,7 +90,7 @@ struct SalOp{ belle_sip_refresher_t* refresher; int ref; SalOpType_t type; - bool_t privacy_enabled; + SalPrivacyMask privacy; }; @@ -145,6 +145,4 @@ 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_enable_privacy(SalOp* op,bool_t enable); -bool_t sal_op_privacy_enabled(const SalOp* op); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 625cc6ef4..ba5f1b2ef 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -24,6 +24,7 @@ SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new0(SalOp,1); __sal_op_init(op,sal); op->type=SalOpUnknown; + op->privacy=SalPrivacyNone; sal_op_ref(op); return op; } @@ -107,8 +108,13 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_uri_t* req_uri; char token[10]; - from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) + + 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))); + } to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); @@ -122,6 +128,26 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_via_new(), 70); + if (op->privacy&SalPrivacyId) { + belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); + } + if (strcmp("REGISTER",method)!=0 && (op->privacy&(SalPrivacyNone|SalPrivacyDefault))==0 ) { /*at this level, default = none*/ + 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)); + } return req; } @@ -485,9 +511,9 @@ bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){ memset(salbody,0,sizeof(salbody)); return FALSE; } -void sal_op_enable_privacy(SalOp* op,bool_t enable) { - op->privacy_enabled=enable; +void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) { + op->privacy=privacy; } - bool_t sal_op_privacy_enabled(const SalOp* op) { - return op->privacy_enabled; +SalPrivacyMask sal_op_get_privacy(const SalOp* op) { + return op->privacy; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1fe12bd1a..1bd9bbc59 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -282,6 +282,9 @@ static void call_ringing(SalOp *h){ if (call==NULL) return; + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Remote ringing.")); @@ -339,6 +342,8 @@ static void call_accepted(SalOp *op){ ms_warning("No call to accept."); return ; } + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); /* Handle remote ICE attributes if any. */ if (call->ice_session != NULL) { @@ -351,7 +356,7 @@ static void call_accepted(SalOp *op){ #endif //BUILD_UPNP md=sal_call_get_final_media_description(op); - if (md) + if (md) /*make sure re-invite will not prose video again*/ call->params.has_video &= linphone_core_media_description_contains_video_stream(md); if (call->state==LinphoneCallOutgoingProgress || diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ef97be71e..f4a9c508f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -480,6 +480,9 @@ void linphone_call_create_op(LinphoneCall *call){ if (call->params.referer) sal_call_set_referer(call->op,call->params.referer->op); linphone_configure_op(call->core,call->op,call->log->to,call->params.custom_headers,FALSE); + if (call->params.privacy != LinphonePrivacyDefault) + sal_op_set_privacy(call->op,(SalPrivacyMask)call->params.privacy); + /*else privacy might be set by proxy */ } LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ @@ -526,6 +529,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->op=op; call->core=lc; + if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && @@ -549,6 +553,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + md=sal_call_get_remote_media_description(op); call->params.has_video &= !!lc->video_policy.automatically_accept; if (md) { @@ -1141,18 +1148,26 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); } -void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacy privacy) { +void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { params->privacy=privacy; } -LinphonePrivacy linphone_call_params_get_privacy(const LinphoneCallParams *params) { +LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { return params->privacy; } + + + + 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"; - default: return "Unknown privacy mode"; + case LinphonePrivacyCritical: return "LinphonePrivacyCritical"; + default: return "Unknown privacy mode"; } } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index edaae9434..09633cefc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2596,6 +2596,9 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d 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){ @@ -2608,6 +2611,7 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d if (with_contact && proxy && proxy->op && sal_op_get_contact(proxy->op)){ sal_op_set_contact(op,sal_op_get_contact(proxy->op)); } + } /** @@ -5888,7 +5892,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate; params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; - params->privacy=LinphonePrivacyNone; + params->privacy=LinphonePrivacyDefault; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9e82de6c7..0a16d779e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -282,22 +282,57 @@ LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams * LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); /*** * @ingroup call_control - * Defines privacy policy to apply as described by rfc3325 + * Defines privacy policy to apply as described by rfc3323 * */ typedef enum _LinphonePrivacy { /** * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy */ - LinphonePrivacyDefault, + LinphonePrivacyDefault=0x0, /** - * With this mode, "from" header is hidden, usually replaced by From: "Anonymous" + * Request that privacy services provide a user-level privacy + * function. + * With this mode, "from" header is hidden, usually replaced by From: "Anonymous" */ - LinphonePrivacyId, + LinphonePrivacyUser=0x1, /** - * No privacy action are taken + * Request that privacy services modify headers that cannot + * be set arbitrarily by the user (Contact/Via). */ - LinphonePrivacyNone + 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 services must not perform any privacy function + */ + LinphonePrivacyNone=0x10, + /** + * Privacy service must perform the specified services or + * fail the request + * + **/ + LinphonePrivacyCritical=0x20 + } LinphonePrivacy; +/* + * a mask of #LinphonePrivacy values + * */ +typedef unsigned int LinphonePrivacyMask; + /** * @ingroup call_control * @return string value of LinphonePrivacy enum @@ -309,14 +344,14 @@ const char* linphone_privacy_to_string(LinphonePrivacy privacy); * @param params to be modified * @param LinphonePrivacy to configure privacy * */ -LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacy privacy); +LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); /** * @ingroup call_control * indicates if "from" must be replaced by anonymous value as described by rfc3325. * @param params object * @return Privacy mode * */ -LINPHONE_PUBLIC LinphonePrivacy linphone_call_params_get_privacy(const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params); struct _LinphoneInfoMessage; @@ -668,6 +703,20 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr */ LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); +/** + * + * Indicates if "from" must be replaced by anonymous value as described by rfc3325. + * @param params to be modified + * @param LinphonePrivacy to configure privacy + * */ +LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy); +/** + * indicates if "from" must be replaced by anonymous value as described by rfc3325. + * @param params object + * @return Privacy mode + * */ +LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params); + /** * @} **/ diff --git a/coreapi/private.h b/coreapi/private.h index db628274b..383faa2f0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -74,9 +74,6 @@ extern "C" { #endif #endif -struct LinphoneParams { - -}; struct _LinphoneCallParams{ 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 */ @@ -94,7 +91,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t pad; bool_t low_bandwidth; - LinphonePrivacy privacy; + LinphonePrivacyMask privacy; }; struct _LinphoneCallLog{ @@ -400,6 +397,7 @@ struct _LinphoneProxyConfig void* user_data; time_t deletion_date; LinphoneReason error; + LinphonePrivacyMask privacy; }; struct _LinphoneAuthInfo diff --git a/coreapi/proxy.c b/coreapi/proxy.c index b5d613f5f..4bf6e6dc1 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -47,6 +47,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600); obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0')); obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0); + obj->privacy=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"privacy",LinphonePrivacyDefault); } /** @@ -1065,6 +1066,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config,key,"publish",obj->publish); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); + lp_config_set_int(config,key,"privacy",obj->privacy); } @@ -1108,6 +1110,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); + linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",LP_CONFIG_DEFAULT_INT(config,"privacy",LinphonePrivacyDefault))); + return cfg; } @@ -1384,3 +1388,9 @@ const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) return ret; } +void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy) { + params->privacy=privacy; +} +LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params) { + return params->privacy; +} diff --git a/coreapi/sal.c b/coreapi/sal.c index 6c4db977b..dbcf87c0c 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -555,3 +555,14 @@ const char* sal_presence_status_to_string(const SalPresenceStatus status) { } } +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; + } +} diff --git a/include/sal/sal.h b/include/sal/sal.h index 7ace50bdb..d0d0c4a8a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -127,6 +127,7 @@ typedef enum{ }SalStreamDir; const char* sal_stream_dir_to_string(SalStreamDir type); + #define SAL_ENDPOINT_CANDIDATE_MAX 2 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64 @@ -548,6 +549,23 @@ int sal_notify(SalOp *op, const SalBody *body); int sal_notify_close(SalOp *op); int sal_publish(SalOp *op, const char *from, const char *to, const char*event_name, int expires, const SalBody *body); +/*privacy, must be in sync with LinphonePrivacyMask*/ +typedef enum _SalPrivacy { + SalPrivacyDefault=0x0, + SalPrivacyUser=0x1, + SalPrivacyHeader=0x2, + SalPrivacySession=0x4, + SalPrivacyId=0x8, + SalPrivacyNone=0x10, + SalPrivacyCritical=0x20 +} SalPrivacy; +typedef unsigned int SalPrivacyMask; + +const char* sal_privacy_to_string(SalPrivacy privacy); +void sal_op_set_privacy(SalOp* op,SalPrivacy privacy); +SalPrivacy sal_op_get_privacy(const SalOp* op); + + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) diff --git a/tester/call_tester.c b/tester/call_tester.c index f075add6a..ddfde8990 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -132,8 +132,11 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* cal CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); if (!linphone_core_get_current_call_remote_address(callee_mgr->lc)) return 0; - CU_ASSERT_TRUE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); - + if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { + CU_ASSERT_TRUE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } else { + CU_ASSERT_FALSE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); @@ -613,7 +616,7 @@ static void call_with_privacy(void) { LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); LinphoneCall *c1,*c2; LinphoneCallParams *params; - + LinphoneProxyConfig* pauline_proxy; params=linphone_core_create_default_call_parameters(pauline->lc); linphone_call_params_set_privacy(params,LinphonePrivacyId); @@ -639,6 +642,26 @@ static void call_with_privacy(void) { CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + /*test proxy config privacy*/ + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + CU_ASSERT_TRUE(call(pauline,marie)); + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,2)); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } diff --git a/tester/message_tester.c b/tester/message_tester.c index 7d2b1ea7e..a56e9676a 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -64,14 +64,43 @@ void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMes static void text_message(void) { LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void text_message_with_privacy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneProxyConfig* pauline_proxy; + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + + /*test proxy config privacy*/ + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + CU_ASSERT_PTR_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void text_message_compatibility_mode(void) { char route[256]; LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); @@ -225,6 +254,7 @@ static void info_message_with_body(){ test_t message_tests[] = { { "Text message", text_message }, + { "Text message with privacy", text_message_with_privacy }, { "Text message compatibility mode", text_message_compatibility_mode }, { "Text message with ack", text_message_with_ack }, { "Text message with send error", text_message_with_send_error }, From 9c933011be33ca806bb76f8cc6daec04ace3e96f Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 13 Jun 2013 09:38:41 +0200 Subject: [PATCH 439/909] Depend on automake 1.9 and tar-pax (posix2001) make dist was limited to 99 character long filenames. --- configure.ac | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 0fcf38fc9..ddeebd5ce 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ 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]) AC_SUBST([LIBTOOL_DEPS]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) diff --git a/mediastreamer2 b/mediastreamer2 index f4b3768c9..64cf0f92e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f4b3768c9b92bf8d0977374b4a8b5d229c4d393e +Subproject commit 64cf0f92ee8550ce2a330726b46782eda9819a73 From 5d3526a77888450e65c67c0ec2ccea6ccae7d5a0 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 13 Jun 2013 12:00:42 +0200 Subject: [PATCH 440/909] add event.h to delivery list --- coreapi/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index c4c60fcf7..12e056a55 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -16,7 +16,7 @@ CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone -linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h +linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h event.h if BUILD_TUNNEL linphone_include_HEADERS+=linphone_tunnel.h @@ -46,7 +46,7 @@ liblinphone_la_SOURCES=\ conference.c \ message_storage.c \ info.c \ - event.c \ + event.c event.h \ $(GITVERSION_FILE) if BUILD_UPNP From 9b6477607e9739ec259c5e1e46bf49bd9e46b32d Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 14 Jun 2013 10:52:58 +0200 Subject: [PATCH 441/909] Update oRTP (strtok issue) --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 462296433..9853da618 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 462296433f10bd84cb605edb0b38d16a4cd81d9e +Subproject commit 9853da61897a3c01303f9b71f331231b65b2979e From 2eef978abf34a17394f13da791afad26505de23f Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 14 Jun 2013 14:37:52 +0200 Subject: [PATCH 442/909] Change silk payload bitrate. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 9853da618..020d921f8 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 9853da61897a3c01303f9b71f331231b65b2979e +Subproject commit 020d921f876ed04d434425fb2176642bbe9b3004 From f55699af8e9a6a0c595fbbc1adac612f96b48fc9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 14 Jun 2013 15:02:53 +0200 Subject: [PATCH 443/909] MS2:fix wrong sampling rate at first startup --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ff71abf33..7564a5073 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff71abf33ae17a2f1221514f3fa7a7fec54c2168 +Subproject commit 7564a50732292a017363bc39bba63e225c8b93c9 From 49ac735521a902e49090ad91c4f280a78b4d52ff Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 14 Jun 2013 15:03:42 +0200 Subject: [PATCH 444/909] MS2:fix wrong sampling rate at first startup --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 64cf0f92e..7564a5073 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 64cf0f92ee8550ce2a330726b46782eda9819a73 +Subproject commit 7564a50732292a017363bc39bba63e225c8b93c9 From 31b25e9f98e22c38c74ec9db54819e6c136b88d2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 14 Jun 2013 17:30:19 +0200 Subject: [PATCH 445/909] give a chance to update contact address during re-INVITEs --- coreapi/linphonecore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 09633cefc..f0beca008 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2887,6 +2887,10 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Modifying call parameters...")); sal_call_set_local_media_description (call->op,call->localdesc); + if (call->dest_proxy && call->dest_proxy->op && sal_op_get_contact(call->dest_proxy->op)){ + /*give a chance to update the contact address if connectivity has changed*/ + sal_op_set_contact(call->op,sal_op_get_contact(call->dest_proxy->op)); + } return sal_call_update(call->op,subject); } From 71c67a045b9124cc01025d405b913c30ab068804 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 14 Jun 2013 17:55:02 +0200 Subject: [PATCH 446/909] add java interfaces for LinphoneEvent --- .../core/tutorials/TutorialBuddyStatus.java | 17 ++++++ .../core/tutorials/TutorialChatRoom.java | 17 ++++++ .../core/tutorials/TutorialHelloWorld.java | 17 ++++++ .../core/tutorials/TutorialRegistration.java | 17 ++++++ .../org/linphone/core/LinphoneCore.java | 24 +++++++- .../linphone/core/LinphoneCoreListener.java | 17 ++++++ .../org/linphone/core/LinphoneEvent.java | 59 +++++++++++++++++++ .../org/linphone/core/SubscriptionDir.java | 7 +++ .../org/linphone/core/SubscriptionState.java | 32 ++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 12 ++++ 10 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 java/common/org/linphone/core/LinphoneEvent.java create mode 100644 java/common/org/linphone/core/SubscriptionDir.java create mode 100644 java/common/org/linphone/core/SubscriptionState.java diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index 1f1dce9f2..af3c7c187 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -23,11 +23,13 @@ import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCallStats; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; @@ -36,6 +38,7 @@ import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; import org.linphone.core.LinphoneFriend.SubscribePolicy; +import org.linphone.core.SubscriptionState; /** * @@ -255,5 +258,19 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index ecd5846d6..276d291e5 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -24,6 +24,7 @@ import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCallStats; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCore.GlobalState; @@ -31,9 +32,11 @@ import org.linphone.core.LinphoneCore.RegistrationState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.SubscriptionState; /** @@ -177,5 +180,19 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index 10d3a2ce5..c624a9e83 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -23,17 +23,20 @@ import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCallStats; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.SubscriptionState; /** @@ -181,5 +184,19 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index e8373b0d4..685997f11 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -23,17 +23,20 @@ import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCallStats; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.SubscriptionState; /** @@ -212,6 +215,20 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 0424a797c..c8a6d7b6f 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1267,5 +1267,27 @@ public interface LinphoneCore { */ public LinphoneInfoMessage createInfoMessage(); - + /** + * Sends an outgoing subscription for a resource with given event, expiration period, and content. + * The state changes of the new subscriptions can be followed thanks to { @link LinphoneCoreListener.subscriptionStateChanged() } and + * { @link LinphoneCoreListener.notifyReceived }. + * @param resource the address of the resource for which the event needs to be monitored. + * @param event the event name, as specified in the event package RFC. + * @param expires the expiration period in seconds. + * @param content optional content of the subscription. + * @return a LinphoneEvent representing the subscription context. + */ + public LinphoneEvent subscribe(LinphoneAddress resource, String event, int expires, LinphoneContent content ); + + /** + * Publish an event. + * After the initial publication, updates can be done with { @link LinphoneEvent.updatePublish() } + * @param resource the resource to which the event belongs. + * @param event the event name as specified in the event package RFC. + * @param expires valid time for the event. + * @param content content of the publish. + * @return a LinphoneEvent representing the publish context. + */ + public LinphoneEvent publish(LinphoneAddress resource, String event, int expires, LinphoneContent content); + } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index b3ff9bbfc..af5b07b84 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -132,6 +132,23 @@ public interface LinphoneCoreListener { */ void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info); + /** + * Notifies of subscription requests state changes, including new incoming subscriptions. + * @param lc the LinphoneCore + * @param ev LinphoneEvent object representing the subscription context. + * @param state actual state of the subscription. + */ + void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, SubscriptionState state); + + /** + * Notifies of an incoming NOTIFY received. + * @param lc the linphoneCore + * @param ev a LinphoneEvent representing the subscription context for which this notify belongs, or null if it is a NOTIFY out of of any subscription. + * @param eventName the event name + * @param content content of the NOTIFY request. + */ + void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content); + /**< @Deprecated Notifies the application that it should show up * @return */ void show(LinphoneCore lc); diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java new file mode 100644 index 000000000..26f55c9f1 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -0,0 +1,59 @@ +package org.linphone.core; + +public interface LinphoneEvent { + /** + * Get the event name as standardized by the event package RFC. + * @return the event name. + */ + String getEventName(); + /** + * Accept an incoming subscription. After it is accepted the application can immediately start to send notifications with + * {@link LinphoneEvent.notify() }. + */ + void acceptSubscription(); + + /** + * Reject an incoming subscription. + * @param reason reason code for rejection. + */ + void denySubscription(Reason reason); + + /** + * Sends a NOTIFY request in the context of a LinphoneEvent created by an incoming subscription. + * @param content the data to be put in the notification. + */ + void notify(LinphoneContent content); + + /** + * Update a subscription initiated previously with {@link LinphoneCore.subscribe() } + * @param content the data to be put in the subscribe request. + */ + void updateSubscribe(LinphoneContent content); + + /** + * Update a Publish previously started with {@link LinphoneCore.publish() }. + * @param content the data to be put in the publish request. + */ + void updatePublish(LinphoneContent content); + + /** + * Terminate an outgoing or incoming subscription, depending on the way the LinphoneEvent was created. + */ + void terminate(); + /** + * In the event where an error would be returned or notified relatively to this LinphoneEvent, returns a reason error code. + * @return + */ + Reason getReason(); + + /** + * Assign an application context to the LinphoneEvent, for later use. + * @param obj + */ + void setUserContext(Object obj); + /** + * Retrieve application context previously set by setUserContext(). + * @return + */ + Object getUserContext(); +} diff --git a/java/common/org/linphone/core/SubscriptionDir.java b/java/common/org/linphone/core/SubscriptionDir.java new file mode 100644 index 000000000..e18639efc --- /dev/null +++ b/java/common/org/linphone/core/SubscriptionDir.java @@ -0,0 +1,7 @@ +package org.linphone.core; + +public enum SubscriptionDir { + Incoming, + Outgoing, + 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..4ab9f7ca6 --- /dev/null +++ b/java/common/org/linphone/core/SubscriptionState.java @@ -0,0 +1,32 @@ +package org.linphone.core; + +public enum SubscriptionState { + /** + * Initial state, should not be used. + */ + LinphoneSubscriptionNone, + /** + * An outgoing subcription was created. + */ + LinphoneSubscriptionOutoingInit, + /** + * An incoming subcription is received. + */ + LinphoneSubscriptionIncomingReceived, + /** + * Subscription is pending, waiting for user approval + */ + LinphoneSubscriptionPending, + /** + * Subscription is accepted and now active. + */ + LinphoneSubscriptionActive, + /** + * Subscription is terminated normally + */ + LinphoneSubscriptionTerminated, + /** + * Subscription encountered an error, indicated by { @link LinphoneEvent.getReason() } + */ + LinphoneSubscriptionError +} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 4b0232113..bcf128f08 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -954,4 +954,16 @@ class LinphoneCoreImpl implements LinphoneCore { public LinphoneInfoMessage createInfoMessage() { return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); } + @Override + public LinphoneEvent subscribe(LinphoneAddress resource, String event, + int expires, LinphoneContent content) { + // TODO Auto-generated method stub + return null; + } + @Override + public LinphoneEvent publish(LinphoneAddress resource, String event, + int expires, LinphoneContent content) { + // TODO Auto-generated method stub + return null; + } } From 0d3258a6a78235a97791c61ffd7c3440e885973f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 17 Jun 2013 14:33:21 +0200 Subject: [PATCH 447/909] fix memory leak with some camera on windows (mainly) --- NEWS | 5 +++++ configure.ac | 2 +- mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 0eede9fa5..e1a271db1 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +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 diff --git a/configure.ac b/configure.ac index ddeebd5ce..eb4d533e8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.6.0],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.6.1],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) diff --git a/mediastreamer2 b/mediastreamer2 index 7564a5073..51d3c20b5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7564a50732292a017363bc39bba63e225c8b93c9 +Subproject commit 51d3c20b5ac8c0c8ad4be8fc73d8fa4df195d017 From 08fdd73272537e7e81ee6232a6da5544f6da2ffb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 12:05:31 +0200 Subject: [PATCH 448/909] LinphoneEvent improvements --- coreapi/callbacks.c | 9 ++------ coreapi/event.c | 51 ++++++++++++++++++++++++++++++++++----------- coreapi/event.h | 25 ++++++++++++++++++++-- coreapi/private.h | 5 ++--- mediastreamer2 | 2 +- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1bd9bbc59..f8ef9dfba 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1017,7 +1017,6 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError er }else{ linphone_event_set_reason(lev, linphone_reason_from_sal(reason)); linphone_event_set_state(lev,LinphoneSubscriptionError); - linphone_event_destroy(lev); } } @@ -1028,17 +1027,14 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, cons if (lev==NULL) { /*out of subscribe notify */ - lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing); + lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing,eventname); } if (lc->vtable.notify_received){ lc->vtable.notify_received(lc,lev,eventname,linphone_content_from_sal_body(&content,body)); } if (st!=SalSubscribeNone){ linphone_event_set_state(lev,linphone_subscription_state_from_sal(st)); - if (st==SalSubscribeTerminated) - linphone_event_destroy(lev); } - } static void subscribe_received(SalOp *op, const char *eventname, const SalBody *body){ @@ -1046,7 +1042,7 @@ static void subscribe_received(SalOp *op, const char *eventname, const SalBody * LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); if (lev==NULL) { - lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming); + lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname); linphone_event_set_state(lev,LinphoneSubscriptionIncomingReceived); }else{ /*subscribe refresh, unhandled*/ @@ -1058,7 +1054,6 @@ static void subscribe_closed(SalOp *op){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); linphone_event_set_state(lev,LinphoneSubscriptionTerminated); - linphone_event_destroy(lev); } SalCallbacks linphone_sal_callbacks={ diff --git a/coreapi/event.c b/coreapi/event.c index 3d350b578..12bccdf29 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -27,6 +27,8 @@ struct _LinphoneEvent{ LinphoneSubscriptionState state; LinphoneReason reason; void *userdata; + int refcnt; + char *name; }; LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){ @@ -39,21 +41,23 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu return LinphoneSubscriptionNone; } -LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir){ +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=sal_op_new(lc->sal); + lev->op=op; + lev->refcnt=1; sal_op_set_user_pointer(lev->op,lev); return lev; } -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir){ - LinphoneEvent *lev=ms_new0(LinphoneEvent,1); - lev->lc=lc; - lev->dir=LinphoneSubscriptionIncoming; - lev->op=op; - sal_op_set_user_pointer(lev->op,lev); +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal)); + return lev; +} + +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op); return lev; } @@ -64,6 +68,9 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat if (lc->vtable.subscription_state_changed){ lc->vtable.subscription_state_changed(lev->lc,lev,state); } + if (state==LinphoneSubscriptionError || state==LinphoneSubscriptionTerminated){ + linphone_event_unref(lev); + } } } @@ -76,7 +83,7 @@ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ } LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ - LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing); + LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event); SalBody salbody; linphone_configure_op(lc,lev->op,resource,NULL,TRUE); sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); @@ -137,7 +144,7 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ SalBody salbody; - LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir); + LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event); linphone_configure_op(lc,lev->op,resource,NULL,FALSE); sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); return lev; @@ -167,15 +174,35 @@ void linphone_event_terminate(LinphoneEvent *lev){ if (lev->state!=LinphoneSubscriptionNone){ linphone_event_set_state(lev,LinphoneSubscriptionTerminated); } - linphone_event_destroy(lev); } -void linphone_event_destroy(LinphoneEvent *lev){ + +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_dir(LinphoneEvent *lev){ return lev->dir; } + +LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){ + return lev->state; +} + +const char *linphone_event_get_name(const LinphoneEvent *lev){ + return lev->name; +} + diff --git a/coreapi/event.h b/coreapi/event.h index aa87a42cc..d4a2c9de7 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -59,9 +59,8 @@ typedef enum _LinphoneSubscriptionState LinphoneSubscriptionState; /** * Callback prototype for notifying the application about notification received from the network. - * If the notification is not associated with any outgoing subscription, then the LinphoneEvent argument is NULL. **/ -typedef void (*LinphoneEventIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *event_name, const LinphoneContent *body); +typedef void (*LinphoneEventIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); /** * Callback prototype for notifying the application about changes of subscription states, including arrival of new subscriptions. @@ -130,8 +129,14 @@ int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *bod **/ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev); +/** + * Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned. +**/ +LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev); + /** * Get subscription direction. + * If the object wasn't created by a subscription mechanism, #LinphoneSubscriptionInvalidDir is returned. **/ LinphoneSubscriptionDir linphone_event_get_dir(LinphoneEvent *lev); @@ -150,6 +155,22 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev); **/ void linphone_event_terminate(LinphoneEvent *lev); + +/** + * Increase reference count. +**/ +LinphoneEvent *linphone_event_ref(LinphoneEvent *lev); + +/** + * Decrease reference count. +**/ +void linphone_event_unref(LinphoneEvent *lev); + +/** + * Get the name of the event as specified in the event package RFC. +**/ +const char *linphone_event_get_name(const LinphoneEvent *lev); + /** * @} **/ diff --git a/coreapi/private.h b/coreapi/private.h index 383faa2f0..f64a59c86 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -748,9 +748,8 @@ LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc); SalReason linphone_reason_to_sal(LinphoneReason reason); LinphoneReason linphone_reason_from_sal(SalReason reason); -LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir); -LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir); -void linphone_event_destroy(LinphoneEvent *lev); +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name); +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); diff --git a/mediastreamer2 b/mediastreamer2 index 7564a5073..318a21921 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7564a50732292a017363bc39bba63e225c8b93c9 +Subproject commit 318a2192108cdfb4946fb9eb73c35f8a055d121f From 41fb12153326626774e872d80a8bad42e014773c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 12:25:55 +0200 Subject: [PATCH 449/909] fix function name. fix indentation problems and doc --- coreapi/event.c | 2 +- coreapi/event.h | 2 +- coreapi/linphonecore.h | 46 +++++++++++++++++++--------------------- tester/eventapi_tester.c | 2 +- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 12bccdf29..12e98b400 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -194,7 +194,7 @@ void linphone_event_unref(LinphoneEvent *lev){ if (lev->refcnt==0) linphone_event_destroy(lev); } -LinphoneSubscriptionDir linphone_event_get_dir(LinphoneEvent *lev){ +LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){ return lev->dir; } diff --git a/coreapi/event.h b/coreapi/event.h index d4a2c9de7..d535a4c8a 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -138,7 +138,7 @@ LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEv * Get subscription direction. * If the object wasn't created by a subscription mechanism, #LinphoneSubscriptionInvalidDir is returned. **/ -LinphoneSubscriptionDir linphone_event_get_dir(LinphoneEvent *lev); +LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev); /** * Set a user (application) pointer. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0a16d779e..35a683bc6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -280,10 +280,10 @@ LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); -/*** +/** * @ingroup call_control * Defines privacy policy to apply as described by rfc3323 - * */ +**/ typedef enum _LinphonePrivacy { /** * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy @@ -291,28 +291,28 @@ typedef enum _LinphonePrivacy { LinphonePrivacyDefault=0x0, /** * Request that privacy services provide a user-level privacy - * function. - * With this mode, "from" header is hidden, usually replaced by From: "Anonymous" + * function. + * With this mode, "from" header is hidden, usually replaced by From: "Anonymous" */ LinphonePrivacyUser=0x1, /** * Request that privacy services modify headers that cannot - * be set arbitrarily by the user (Contact/Via). + * be set arbitrarily by the user (Contact/Via). */ LinphonePrivacyHeader=0x2, - /* + /** * Request that privacy services provide privacy for session - * media - */ + * 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 + * 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, @@ -322,11 +322,10 @@ typedef enum _LinphonePrivacy { LinphonePrivacyNone=0x10, /** * Privacy service must perform the specified services or - * fail the request + * fail the request * **/ LinphonePrivacyCritical=0x20 - } LinphonePrivacy; /* * a mask of #LinphonePrivacy values @@ -340,15 +339,15 @@ typedef unsigned int LinphonePrivacyMask; const char* linphone_privacy_to_string(LinphonePrivacy privacy); /** * @ingroup call_control - * Indicates if "from" must be replaced by anonymous value as described by rfc3325. - * @param params to be modified + * Set requested level of privacy for the call. + * @param params the call parameters to be modified * @param LinphonePrivacy to configure privacy * */ -LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); +LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); /** * @ingroup call_control - * indicates if "from" must be replaced by anonymous value as described by rfc3325. - * @param params object + * Get requested level of privacy for the call. + * @param params the call parameters * @return Privacy mode * */ LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params); @@ -704,14 +703,13 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); /** - * - * Indicates if "from" must be replaced by anonymous value as described by rfc3325. + * Set default privacy policy for all calls routed through this proxy. * @param params to be modified * @param LinphonePrivacy to configure privacy * */ -LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy); +LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy); /** - * indicates if "from" must be replaced by anonymous value as described by rfc3325. + * Get default privacy policy for all calls routed through this proxy. * @param params object * @return Privacy mode * */ diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 23f0158ab..c7815f671 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -58,7 +58,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li break; case LinphoneSubscriptionActive: counters->number_of_LinphoneSubscriptionActive++; - if (linphone_event_get_dir(lev)==LinphoneSubscriptionIncoming){ + if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ mgr->lev=lev; linphone_event_notify(lev,&content); } From 91cf83d2f3e3a38af69291b2b5f5d1177b8dfb70 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 12:31:17 +0200 Subject: [PATCH 450/909] fix LinphoneEvent user_data funcs. --- coreapi/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 12e98b400..55a92d9f7 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -156,11 +156,11 @@ int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *bod return sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); } -void linphone_event_set_user_pointer(LinphoneEvent *ev, void *up){ +void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ ev->userdata=up; } -void *linphone_event_get_user_pointer(const LinphoneEvent *ev){ +void *linphone_event_get_user_data(const LinphoneEvent *ev){ return ev->userdata; } From 40071c3388be6c6a7391b5762c25f1690c5daf0f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 16:18:45 +0200 Subject: [PATCH 451/909] re-enable tutorials fix bugs in events add tutorial for subscribe/notify --- configure.ac | 7 +- coreapi/Makefile.am | 2 +- coreapi/event.c | 1 + coreapi/help/Makefile.am | 15 ++-- coreapi/help/notify.c | 181 +++++++++++++++++++++++++++++++++++++++ coreapi/linphonecore.h | 15 ++-- 6 files changed, 202 insertions(+), 19 deletions(-) create mode 100644 coreapi/help/notify.c diff --git a/configure.ac b/configure.ac index 4893e1b33..5c3b8bb92 100644 --- a/configure.ac +++ b/configure.ac @@ -62,7 +62,6 @@ case $target in ;; armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " - build_tests=no ios_found=yes ;; x86_64-apple-darwin*|i686-apple-darwin*) @@ -81,8 +80,6 @@ AC_SUBST(GUI_FLAGS) 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]) @@ -757,7 +754,7 @@ AC_ARG_ENABLE(tests_enabled, 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) @@ -780,7 +777,7 @@ case "$target_os" in CUNIT_LIBS+=" -lncurses" ;; esac -AM_CONDITIONAL([BUILD_CUNIT_TESTS], [test x$found_cunit = xyes && test x$enable_tests != xno]) +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 diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 12e056a55..c9c1b62b8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -95,7 +95,7 @@ liblinphone_la_LIBADD= \ $(SQLITE3_LIBS) -if BUILD_TESTS +if ENABLE_TESTS noinst_PROGRAMS=test_lsd test_ecc test_numbers test_lsd_SOURCES=test_lsd.c diff --git a/coreapi/event.c b/coreapi/event.c index 55a92d9f7..264b24472 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -47,6 +47,7 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri lev->dir=dir; lev->op=op; lev->refcnt=1; + lev->name=ms_strdup(name); sal_op_set_user_pointer(lev->op,lev); return lev; } diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 902d23c9c..8beceab22 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -33,8 +33,8 @@ clean-local: if ENABLE_TESTS #tutorials -if BUILD_TESTS -noinst_PROGRAMS=helloworld registration buddy_status chatroom + +noinst_PROGRAMS=helloworld registration buddy_status chatroom notify helloworld_SOURCES=helloworld.c LINPHONE_TUTOS=$(helloworld_SOURCES) @@ -57,17 +57,20 @@ chatroom_SOURCES=chatroom.c LINPHONE_TUTOS+=$(chatroom_SOURCES) chatroom_LDADD=$(helloworld_LDADD) -endif - + +notify_SOURCES=notify.c +LINPHONE_TUTOS+=$(notify_SOURCES) + +notify_LDADD=$(helloworld_LDADD) + endif AM_CFLAGS=\ + -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ -DIN_LINPHONE \ $(ORTP_CFLAGS) \ - $(OSIP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ - $(EXOSIP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ $(IPV6_CFLAGS) \ diff --git a/coreapi/help/notify.c b/coreapi/help/notify.c new file mode 100644 index 000000000..eb8cfbda3 --- /dev/null +++ b/coreapi/help/notify.c @@ -0,0 +1,181 @@ + +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** + * @defgroup notify_tutorials Generic subscribe/notify example + * @ingroup tutorials + *This program is a _very_ simple usage example of liblinphone. + *It demonstrates how to listen to a SIP subscription. + *It then sends notify requests back periodically. + *first argument must be like sip:jehan@sip.linphone.org , second must be password . + *
+ *ex registration sip:jehan@sip.linphone.org secret + *
Registration is cleared on SIGINT + *
+ *@include registration.c + + * + */ + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif + +#include + +static bool_t running=TRUE; + +static void stop(int signum){ + running=FALSE; +} + +typedef struct MyAppData{ + LinphoneEvent *ev; +}MyAppData; + +/** + * Registration state notification callback + */ +static void registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + printf("New registration state %s for user id [%s] at proxy [%s]\n" + ,linphone_registration_state_to_string(cstate) + ,linphone_proxy_config_get_identity(cfg) + ,linphone_proxy_config_get_addr(cfg)); +} + +static void subscription_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state){ + MyAppData *data=(MyAppData*)linphone_core_get_user_data(lc); + if (state==LinphoneSubscriptionIncomingReceived){ + printf("Receiving new subscription for event %s\n",linphone_event_get_name(ev)); + if (data->ev==NULL) { + linphone_event_accept_subscription(ev); + data->ev=linphone_event_ref(ev); + }else{ + linphone_event_deny_subscription(ev,LinphoneReasonBusy); + } + }else if (state==LinphoneSubscriptionTerminated){ + if (data->ev==ev){ + linphone_event_unref(data->ev); + data->ev=NULL; + } + } +} + +LinphoneCore *lc; +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + MyAppData *data=ms_new0(MyAppData,1); + char* identity=NULL; + char* password=NULL; + int i; + + /* takes sip uri identity from the command line arguments */ + if (argc>1){ + identity=argv[1]; + } + + /* takes password from the command line arguments */ + if (argc>2){ + password=argv[2]; + } + + signal(SIGINT,stop); + +#ifdef DEBUG + linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/ +#endif + /* + Fill the LinphoneCoreVTable with application callbacks. + All are optional. Here we only use the registration_state_changed callbacks + in order to get notifications about the progress of the registration. + */ + vtable.registration_state_changed=registration_state_changed; + vtable.subscription_state_changed=subscription_state_changed; + + /* + Instanciate a LinphoneCore object given the LinphoneCoreVTable + */ + lc=linphone_core_new(&vtable,NULL,NULL,data); + + LinphoneProxyConfig* proxy_cfg; + /*create proxy config*/ + proxy_cfg = linphone_proxy_config_new(); + /*parse identity*/ + LinphoneAddress *from = linphone_address_new(identity); + if (from==NULL){ + printf("%s not a valid sip uri, must be like sip:toto@sip.linphone.org \n",identity); + goto end; + } + LinphoneAuthInfo *info; + if (password!=NULL){ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + } + + // configure proxy entries + linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/ + const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/ + linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/ + linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/ + linphone_address_destroy(from); /*release resource*/ + + linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/ + linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/ + + i=0; + /* main loop for receiving notifications and doing background linphonecore work: */ + while(running){ + linphone_core_iterate(lc); /* first iterate initiates registration */ + ms_usleep(50000); + ++i; + if (data->ev && i%100==0){ + LinphoneContent content; + content.type="application"; + content.subtype="goodxml"; + content.data="really cool"; + content.size=strlen((const char*)content.data); + linphone_event_notify(data->ev,&content); + } + } + + linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/ + linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/ + linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/ + linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/ + + if (data->ev){ + linphone_event_terminate(data->ev); + } + + while(linphone_proxy_config_get_state(proxy_cfg) != LinphoneRegistrationCleared){ + linphone_core_iterate(lc); /*to make sure we receive call backs before shutting down*/ + ms_usleep(50000); + } + +end: + printf("Shutting down...\n"); + linphone_core_destroy(lc); + ms_free(data); + printf("Exited\n"); + return 0; +} + diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 35a683bc6..bb4f4afe5 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -286,9 +286,9 @@ LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const Linphon **/ typedef enum _LinphonePrivacy { /** - * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy + * Privacy services must not perform any privacy function */ - LinphonePrivacyDefault=0x0, + LinphonePrivacyNone=0x0, /** * Request that privacy services provide a user-level privacy * function. @@ -316,16 +316,17 @@ typedef enum _LinphonePrivacy { * */ LinphonePrivacyId=0x8, - /** - * Privacy services must not perform any privacy function - */ - LinphonePrivacyNone=0x10, /** * Privacy service must perform the specified services or * fail the request * **/ - LinphonePrivacyCritical=0x20 + LinphonePrivacyCritical=0x10, + + /** + * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy + */ + LinphonePrivacyDefault=0x8000, } LinphonePrivacy; /* * a mask of #LinphonePrivacy values From ed655060c8efd5a450c9074d260a82f178b39c13 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 16:33:59 +0200 Subject: [PATCH 452/909] few privacy cleanups --- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/linphonecore.h | 6 +++++- include/sal/sal.h | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index ba5f1b2ef..eb799fad9 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -132,7 +132,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); } - if (strcmp("REGISTER",method)!=0 && (op->privacy&(SalPrivacyNone|SalPrivacyDefault))==0 ) { /*at this level, default = none*/ + if (strcmp("REGISTER",method)!=0 && (op->privacy !=SalPrivacyNone)==0 ) { /*at this level, default = none*/ 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)); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index bb4f4afe5..9f66bfd81 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -280,6 +280,10 @@ LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); + +/* + * Note for developers: this enum must be kept synchronized with the SalPrivacy enum declared in sal.h + */ /** * @ingroup call_control * Defines privacy policy to apply as described by rfc3323 @@ -324,7 +328,7 @@ typedef enum _LinphonePrivacy { LinphonePrivacyCritical=0x10, /** - * Default privacy as defined either globally or by proxy using #linphone_proxy_config_set_privacy + * Special keyword to use privacy as defined either globally or by proxy using linphone_proxy_config_set_privacy() */ LinphonePrivacyDefault=0x8000, } LinphonePrivacy; diff --git a/include/sal/sal.h b/include/sal/sal.h index d0d0c4a8a..a96f5fb20 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -551,13 +551,13 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char*event_na /*privacy, must be in sync with LinphonePrivacyMask*/ typedef enum _SalPrivacy { - SalPrivacyDefault=0x0, + SalPrivacyNone=0x0, SalPrivacyUser=0x1, SalPrivacyHeader=0x2, SalPrivacySession=0x4, SalPrivacyId=0x8, - SalPrivacyNone=0x10, - SalPrivacyCritical=0x20 + SalPrivacyCritical=0x10, + SalPrivacyDefault=0x8000 } SalPrivacy; typedef unsigned int SalPrivacyMask; From f3630b5d37ffd94aebac83171208511925a1337f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 16:56:09 +0200 Subject: [PATCH 453/909] fix mistake --- coreapi/bellesip_sal/sal_op_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index eb799fad9..0002a013b 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -132,7 +132,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); } - if (strcmp("REGISTER",method)!=0 && (op->privacy !=SalPrivacyNone)==0 ) { /*at this level, default = none*/ + 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)); From b4478c85f757fc9670163bbaf24627037ef1e309 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 18:39:44 +0200 Subject: [PATCH 454/909] improve documentation of macos x compilation, especially regarding generating bundle compatible with older macos version. --- README.macos | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/README.macos b/README.macos index dd39c2f6e..e2f1593bd 100644 --- a/README.macos +++ b/README.macos @@ -7,6 +7,10 @@ You need: - Macports: http://www.macports.org/ Download and install macports using its user friendly installer. +- In order to enable generation of bundle for multiple macos version it is recommended to edit /opt/local/etc/macports/macports.conf to add the + following line: + macosx_deployment_target 10.6 + - Install build time dependencies $ sudo port install automake autoconf libtool intltool @@ -17,7 +21,22 @@ You need: $ sudo port install ffmpeg-devel -gpl2 $ sudo port install libvpx $ sudo port install readline - + + +- Install gtk. It is recommended to use the quartz backend for better integration. + $ sudo port install gtk2 +quartz +no_x11 + $ sudo port install gtk-osx-application -python27 + $ sudo port install hicolor-icon-theme + +- Install additional librairies required for wizard (linphone.org account creation assistant) + $ sudo port install libsoup + +- Install sqlite3 for message storage + $ sudo port install sqlite3 + +The softwares below need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do: + $ export MACOSX_DEPLOYMENT_TARGET=10.6 + - Install srtp (optional) for call encryption $ sudo port install srtp If that fails, get from source: @@ -31,17 +50,6 @@ You need: $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make $ sudo make install -- Install gtk. It is recommended to use the quartz backend for better integration. - $ sudo port install gtk2 +quartz +no_x11 - $ sudo port install gtk-osx-application -python27 - $ sudo port install hicolor-icon-theme - -- Install additional librairies required for wizard (linphone.org account creation assistant) - $ sudo port install libsoup - - - Install sqlite3 for message storage - $ sudo port install sqlite3 - ** WARNING 2013-03-06 glib-networking is currently broken in macports - generates crashes or hangs when used in a bundle ** As a temporary workaround, build a newer version by yourself: $ wget http://ftp.gnome.org/pub/gnome/sources/glib-networking/2.34/glib-networking-2.34.2.tar.xz @@ -58,7 +66,6 @@ You need: $ ./configure --prefix=/opt/local && make && sudo make install - - Compile linphone If you got the source code from git, run ./autogen.sh first. @@ -82,8 +89,7 @@ Use git: $ 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. - + Run configure as told before but with "--enable-relativeprefix" appended. $ make $ make bundle From ba53ca3ee62fdac13644d1277947f81e813983cb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 21:26:49 +0200 Subject: [PATCH 455/909] LinphoneEvent: add accessors to resource address and from. --- coreapi/event.c | 20 ++++++++++++++++++++ coreapi/event.h | 10 ++++++++++ coreapi/help/notify.c | 2 ++ 3 files changed, 32 insertions(+) diff --git a/coreapi/event.c b/coreapi/event.c index 264b24472..0b54f607a 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -29,6 +29,8 @@ struct _LinphoneEvent{ void *userdata; int refcnt; char *name; + LinphoneAddress *from; + LinphoneAddress *resource_addr; }; LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){ @@ -59,6 +61,12 @@ LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name){ LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op); + if (dir==LinphoneSubscriptionIncoming){ + lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_to_address(op)); + lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); + }else{ + lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(op)); + } return lev; } @@ -87,6 +95,8 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress * LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event); SalBody salbody; linphone_configure_op(lc,lev->op,resource,NULL,TRUE); + lev->resource_addr=linphone_address_clone(resource); + lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); linphone_event_set_state(lev,LinphoneSubscriptionOutoingInit); return lev; @@ -187,6 +197,8 @@ static void linphone_event_destroy(LinphoneEvent *lev){ if (lev->op) sal_op_release(lev->op); ms_free(lev->name); + if (lev->resource_addr) linphone_address_destroy(lev->resource_addr); + if (lev->from) linphone_address_destroy(lev->from); ms_free(lev); } @@ -207,3 +219,11 @@ const char *linphone_event_get_name(const LinphoneEvent *lev){ return lev->name; } +const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev){ + return lev->from; +} + +const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){ + return lev->resource_addr; +} + diff --git a/coreapi/event.h b/coreapi/event.h index d535a4c8a..6db01f46e 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -171,6 +171,16 @@ void linphone_event_unref(LinphoneEvent *lev); **/ const char *linphone_event_get_name(const LinphoneEvent *lev); +/** + * Get the "from" address of the subscription. +**/ +const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev); + +/** + * Get the resource address of the subscription or publish. +**/ +const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev); + /** * @} **/ diff --git a/coreapi/help/notify.c b/coreapi/help/notify.c index eb8cfbda3..0055346ee 100644 --- a/coreapi/help/notify.c +++ b/coreapi/help/notify.c @@ -34,6 +34,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +#define DEBUG 1 + #ifdef IN_LINPHONE #include "linphonecore.h" #else From 129bd04fd8a524239f00659304b056658923e0c7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 22:06:13 +0200 Subject: [PATCH 456/909] fix extracting of LinphoneContent from SalBody --- coreapi/info.c | 1 + tester/eventapi_tester.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/coreapi/info.c b/coreapi/info.c index 6d92a0db8..ab1c2cd6a 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -85,6 +85,7 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons obj->subtype=(char*)ref->subtype; obj->data=(void*)ref->data; obj->size=ref->size; + return obj; } return NULL; } diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index c7815f671..c8571c8b6 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -28,6 +28,8 @@ static const char *subscribe_content="blabla"; static const char *notify_content="blabla"; void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ + CU_ASSERT_PTR_NOT_NULL_FATAL(content); + CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); } void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { @@ -125,6 +127,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { if (terminated_by_subscriber){ linphone_event_terminate(lev); }else{ + CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); linphone_event_terminate(pauline->lev); } From ad406033c0f2043d2a3bf73f5b8c8204c48c35a5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Jun 2013 22:11:36 +0200 Subject: [PATCH 457/909] add java wrapper and jni for LinphoneEvent API --- coreapi/linphonecore_jni.cc | 349 +++++++++++++++++- .../org/linphone/core/LinphoneEvent.java | 12 + java/common/org/linphone/core/Privacy.java | 11 + .../org/linphone/core/SubscriptionDir.java | 19 +- .../org/linphone/core/SubscriptionState.java | 32 +- .../org/linphone/core/LinphoneCoreImpl.java | 15 +- .../org/linphone/core/LinphoneEventImpl.java | 91 +++++ 7 files changed, 496 insertions(+), 33 deletions(-) create mode 100644 java/common/org/linphone/core/Privacy.java create mode 100644 java/impl/org/linphone/core/LinphoneEventImpl.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 0e0eae1b4..4e638e233 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -56,6 +56,8 @@ static jclass handler_class; static jmethodID loghandler_id; static jobject handler_obj=NULL; +static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content); + #ifdef ANDROID void linphone_android_log_handler(int prio, char *str) { char *current; @@ -150,6 +152,8 @@ public: vTable.call_stats_updated = callStatsUpdated; vTable.transfer_state_changed = transferStateChanged; vTable.info_received = infoReceived; + vTable.subscription_state_changed=subscriptionStateChanged; + vTable.notify_received=notifyReceived; listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); @@ -200,6 +204,12 @@ public: infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V"); + subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V"); + notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V"); + + proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -225,6 +235,15 @@ public: infoMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneInfoMessageImpl")); infoMessageCtor = env->GetMethodID(infoMessageClass,"", "(J)V"); + + linphoneEventClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneEventImpl")); + linphoneEventCtrId = env->GetMethodID(linphoneEventClass,"", "(J)V"); + + subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState")); + subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;"); + + subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); + subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); } ~LinphoneCoreData() { @@ -244,6 +263,9 @@ public: env->DeleteGlobalRef(chatRoomClass); env->DeleteGlobalRef(friendClass); env->DeleteGlobalRef(infoMessageClass); + env->DeleteGlobalRef(linphoneEventClass); + env->DeleteGlobalRef(subscriptionStateClass); + env->DeleteGlobalRef(subscriptionDirClass); } jobject core; jobject listener; @@ -259,6 +281,8 @@ public: jmethodID callStatsUpdatedId; jmethodID transferStateId; jmethodID infoReceivedId; + jmethodID subscriptionStateId; + jmethodID notifyRecvId; jclass globalStateClass; jmethodID globalStateId; @@ -306,6 +330,15 @@ public: jclass infoMessageClass; jmethodID infoMessageCtor; + + jclass linphoneEventClass; + jmethodID linphoneEventCtrId; + + jclass subscriptionStateClass; + jmethodID subscriptionStateFromIntId; + + jclass subscriptionDirClass; + jmethodID subscriptionDirFromIntId; LinphoneCoreVTable vTable; @@ -319,7 +352,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -335,7 +368,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -349,7 +382,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -383,7 +416,7 @@ public: jint result = jvm->AttachCurrentThread(&env,NULL); jobject jcall; if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -402,7 +435,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -417,7 +450,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -430,7 +463,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -444,7 +477,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -458,7 +491,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -473,7 +506,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -487,7 +520,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -509,7 +542,7 @@ public: jobject callobj; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -526,7 +559,7 @@ public: jint result = jvm->AttachCurrentThread(&env,NULL); jobject jcall; if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -542,7 +575,7 @@ public: jint result = jvm->AttachCurrentThread(&env,NULL); jobject jcall; if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneInfoMessage *copy_info=linphone_info_message_copy(info); @@ -554,8 +587,60 @@ public: ,env->NewObject(lcData->infoMessageClass,lcData->infoMessageCtor,(jlong)copy_info) ); } - + jobject getEvent(JNIEnv *env, LinphoneEvent *lev){ + if (lev==NULL) return NULL; + jobject jev=(jobject)linphone_event_get_user_data(lev); + if (jev==NULL){ + jev=env->NewObject(linphoneEventClass,linphoneEventCtrId,(jlong)linphone_event_ref(lev)); + jev=env->NewGlobalRef(jev); + linphone_event_set_user_data(lev,jev); + } + return jev; + } + static void subscriptionStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + jobject jstate; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->subscriptionStateClass,lcData->subscriptionStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->subscriptionStateId + ,lcData->core + ,jevent + ,jstate + ); + if (state==LinphoneSubscriptionTerminated || state==LinphoneSubscriptionError){ + /*loose the java reference */ + linphone_event_set_user_data(ev,NULL); + env->DeleteGlobalRef(jevent); + } + } + static void notifyReceived(LinphoneCore *lc, LinphoneEvent *ev, const char *evname, const LinphoneContent *content){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + env->CallVoidMethod(lcData->listener + ,lcData->notifyRecvId + ,lcData->core + ,jevent + ,env->NewStringUTF(evname) + ,content ? create_java_linphone_content(env,content) : NULL + ); + } }; + extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env ,jobject thiz ,jobject jlistener @@ -2597,6 +2682,76 @@ 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, jstring jdata){ + LinphoneCore *lc=(LinphoneCore*)coreptr; + LinphoneAddress *addr=(LinphoneAddress*)addrptr; + LinphoneContent content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + } + ev=linphone_core_subscribe(lc,addr,evname,expires,content.type ? &content : NULL); + if (jtype){ + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); + } + env->ReleaseStringUTFChars(jevname,evname); + if (ev){ + jev=lcData->getEvent(env,ev); + } + return jev; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: publish + * Signature: (JJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv *env, jobject jobj, jlong coreptr, jlong addrptr, jstring jevname, jint expires, + jstring jtype, jstring jsubtype, jstring jdata){ + LinphoneCore *lc=(LinphoneCore*)coreptr; + LinphoneAddress *addr=(LinphoneAddress*)addrptr; + LinphoneContent content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + } + ev=linphone_core_publish(lc,addr,evname,expires,content.type ? &content : NULL); + if (jtype){ + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); + } + env->ReleaseStringUTFChars(jevname,evname); + if (ev){ + jev=lcData->getEvent(env,ev); + } + return jev; +} + + 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); @@ -2635,7 +2790,6 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent * jsubtype=env->NewStringUTF(content->subtype); jdata=content->data ? env->NewStringUTF((const char*)content->data) : NULL; jobject jobj=env->NewObject(contentClass,ctor,jtype, jsubtype, jdata); - env->DeleteGlobalRef(contentClass); return jobj; } @@ -2659,7 +2813,6 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getCont * 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){ - const char *type,*subtype,*data; LinphoneContent content; content.type=(char*)env->GetStringUTFChars(jtype,NULL); @@ -2725,4 +2878,166 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreFactoryImpl__1setLogHa } } +/* + * 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, jstring jdata){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + } + + err=linphone_event_notify(ev,content.type ? &content : NULL); + + if (jtype){ + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); + } + 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, jstring jdata){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + } + + err=linphone_event_update_subscribe(ev,content.type ? &content : NULL); + + if (jtype){ + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); + } + 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, jstring jdata){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + if (jtype){ + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + } + + err=linphone_event_update_publish(ev,content.type ? &content : NULL); + + if (jtype){ + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); + } + return err; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: terminate + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_terminate(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + linphone_event_terminate(ev); + return 0; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getReason + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getReason(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_reason(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getSubscriptionDir + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionDir(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_subscription_dir(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getSubscriptionState + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionState(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_subscription_state(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + linphone_event_unref(ev); +} diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java index 26f55c9f1..865200dfd 100644 --- a/java/common/org/linphone/core/LinphoneEvent.java +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -6,6 +6,18 @@ public interface LinphoneEvent { * @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() }. 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/SubscriptionDir.java b/java/common/org/linphone/core/SubscriptionDir.java index e18639efc..151bd4e15 100644 --- a/java/common/org/linphone/core/SubscriptionDir.java +++ b/java/common/org/linphone/core/SubscriptionDir.java @@ -1,7 +1,20 @@ package org.linphone.core; +import java.util.Vector; + public enum SubscriptionDir { - Incoming, - Outgoing, - Invalid + 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 index 4ab9f7ca6..a6e84ec6a 100644 --- a/java/common/org/linphone/core/SubscriptionState.java +++ b/java/common/org/linphone/core/SubscriptionState.java @@ -4,29 +4,47 @@ public enum SubscriptionState { /** * Initial state, should not be used. */ - LinphoneSubscriptionNone, + None(0), /** * An outgoing subcription was created. */ - LinphoneSubscriptionOutoingInit, + OutoingInit(1), /** * An incoming subcription is received. */ - LinphoneSubscriptionIncomingReceived, + IncomingReceived(2), /** * Subscription is pending, waiting for user approval */ - LinphoneSubscriptionPending, + Pending(3), /** * Subscription is accepted and now active. */ - LinphoneSubscriptionActive, + Active(4), /** * Subscription is terminated normally */ - LinphoneSubscriptionTerminated, + Terminated(5), /** * Subscription encountered an error, indicated by { @link LinphoneEvent.getReason() } */ - LinphoneSubscriptionError + Error(6); + + protected final int mValue; + private SubscriptionState(int value){ + mValue=value; + } + static protected SubscriptionState fromInt(int value) throws LinphoneCoreException{ + switch(value){ + case 0: return None; + case 1: return OutoingInit; + case 2: return IncomingReceived; + case 3: return Pending; + case 4: return Active; + case 5: return Terminated; + case 6: return Error; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for SubscriptionState"); + } + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index bcf128f08..ae9b26fe8 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -954,16 +954,19 @@ class LinphoneCoreImpl implements LinphoneCore { public LinphoneInfoMessage createInfoMessage() { return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); } + + private native Object subscribe(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, String data); @Override - public LinphoneEvent subscribe(LinphoneAddress resource, String event, + public LinphoneEvent subscribe(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { - // TODO Auto-generated method stub - return null; + return (LinphoneEvent)subscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getDataAsString() : null); } + private native Object publish(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, String data); @Override - public LinphoneEvent publish(LinphoneAddress resource, String event, + public LinphoneEvent publish(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { - // TODO Auto-generated method stub - return null; + return (LinphoneEvent)publish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getDataAsString() : null); } } diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java new file mode 100644 index 000000000..ab201af99 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -0,0 +1,91 @@ +package org.linphone.core; + +public class LinphoneEventImpl implements LinphoneEvent { + private Object mUserContext; + private long mNativePtr; + + protected LinphoneEventImpl(long nativePtr){ + mNativePtr=nativePtr; + } + + private native String getEventName(long nativeptr); + @Override + public String getEventName() { + return getEventName(mNativePtr); + } + + private native int acceptSubscription(long nativeptr); + @Override + public void acceptSubscription() { + acceptSubscription(mNativePtr); + } + + private native int denySubscription(long nativeptr, int reason); + @Override + public void denySubscription(Reason reason) { + denySubscription(mNativePtr,reason.mValue); + } + + private native int notify(long nativeptr, String type, String subtype, String data); + @Override + public void notify(LinphoneContent content) { + notify(mNativePtr,content.getType(),content.getSubtype(),content.getDataAsString()); + } + + private native int updateSubscribe(long nativePtr, String type, String subtype, String data); + @Override + public void updateSubscribe(LinphoneContent content) { + updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getDataAsString()); + } + + private native int updatePublish(long nativePtr, String type, String subtype, String data); + @Override + public void updatePublish(LinphoneContent content) { + updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getDataAsString()); + } + + private native int terminate(long nativePtr); + @Override + public void terminate() { + terminate(mNativePtr); + } + + private native int getReason(long nativePtr); + @Override + public Reason getReason() { + return Reason.fromInt(getReason(mNativePtr)); + } + + @Override + public void setUserContext(Object obj) { + mUserContext=obj; + } + + @Override + public Object getUserContext() { + return mUserContext; + } + + private native int getSubscriptionDir(long nativeptr); + @Override + public SubscriptionDir getSubscriptionDir() { + return SubscriptionDir.fromInt(getSubscriptionDir(mNativePtr)); + } + + private native int getSubscriptionState(long nativeptr); + @Override + public SubscriptionState getSubscriptionState() { + try { + return SubscriptionState.fromInt(getSubscriptionState(mNativePtr)); + } catch (LinphoneCoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return SubscriptionState.Error; + } + private native void unref(long nativeptr); + protected void finalize(){ + unref(mNativePtr); + } + +} From 9633a35601433a216741827f885827031e6823f6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Jun 2013 11:53:42 +0200 Subject: [PATCH 458/909] simplify tester --- scripts/mk-ca-bundle.pl | 2 +- tester/call_tester.c | 92 ++++++++++++++++++------------------- tester/eventapi_tester.c | 8 ++-- tester/liblinphone_tester.c | 8 ++-- tester/liblinphone_tester.h | 4 +- tester/message_tester.c | 28 +++++------ tester/presence_tester.c | 6 +-- tester/register_tester.c | 14 +++--- tester/upnp_tester.c | 6 +-- 9 files changed, 84 insertions(+), 84 deletions(-) diff --git a/scripts/mk-ca-bundle.pl b/scripts/mk-ca-bundle.pl index edede4261..283ebd13c 100755 --- a/scripts/mk-ca-bundle.pl +++ b/scripts/mk-ca-bundle.pl @@ -36,7 +36,7 @@ use LWP::UserAgent; use strict; use vars qw($opt_b $opt_f $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v $opt_w); -my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; +my $url = 'https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; diff --git a/tester/call_tester.c b/tester/call_tester.c index ddfde8990..d7f4ae0d6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -162,8 +162,8 @@ bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ } static void simple_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCore* lc_marie=marie->lc; LinphoneCore* lc_pauline=pauline->lc; @@ -213,8 +213,8 @@ static void simple_call(void) { static void simple_call_compatibility_mode(void) { char route[256]; - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCore* lc_marie=marie->lc; LinphoneCore* lc_pauline=pauline->lc; @@ -279,8 +279,8 @@ static void simple_call_compatibility_mode(void) { static void cancelled_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); @@ -299,7 +299,7 @@ static void cancelled_call(void) { } static void call_with_dns_time_out(void) { - LinphoneCoreManager* marie = linphone_core_manager_new2(liblinphone_tester_file_prefix, "empty_rc", FALSE); + LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; linphone_core_set_sip_transports(marie->lc,&transport); linphone_core_iterate(marie->lc); @@ -315,8 +315,8 @@ static void call_with_dns_time_out(void) { } static void cancelled_ringing_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); @@ -334,8 +334,8 @@ static void cancelled_ringing_call(void) { } static void early_declined_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCallLog* in_call; LinphoneCall* out_call; @@ -358,8 +358,8 @@ static void early_declined_call(void) { } static void call_declined(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* in_call; LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); @@ -383,8 +383,8 @@ static void call_declined(void) { } static void call_terminated_by_caller(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ @@ -397,8 +397,8 @@ static void call_terminated_by_caller(void) { } static void call_with_no_sdp(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_no_sdp_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_no_sdp_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(marie,pauline)); /*just to sleep*/ @@ -436,8 +436,8 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee return success; } static void call_with_ice(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); @@ -461,8 +461,8 @@ static void call_with_ice(void) { } static void call_with_custom_headers(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall *c1,*c2; LinphoneCallParams *params; const LinphoneCallParams *remote_params; @@ -498,8 +498,8 @@ static void call_with_custom_headers(void) { } static void call_paused_resumed(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_obj; CU_ASSERT_TRUE(call(pauline,marie)); @@ -536,8 +536,8 @@ static bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,Linph } static void call_paused_resumed_from_callee(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_obj; CU_ASSERT_TRUE(call(pauline,marie)); @@ -595,8 +595,8 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) } static void call_with_video_added(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); CU_ASSERT_TRUE(add_video(pauline,marie)); @@ -612,8 +612,8 @@ static void call_with_video_added(void) { #endif static void call_with_privacy(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall *c1,*c2; LinphoneCallParams *params; LinphoneProxyConfig* pauline_proxy; @@ -670,9 +670,9 @@ static void call_with_privacy(void) { static void simple_conference(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); stats initial_marie_stat; stats initial_pauline_stat; stats initial_laure_stat; @@ -728,8 +728,8 @@ static void simple_conference(void) { static void srtp_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); @@ -751,8 +751,8 @@ static void srtp_call(void) { linphone_core_manager_destroy(pauline); } static void call_with_declined_srtp(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); @@ -774,8 +774,8 @@ static void srtp_video_ice_call(void) { static void srtp_ice_call(void) { #endif int i=0; - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); @@ -817,8 +817,8 @@ static void srtp_ice_call(void) { static void early_media_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_early_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); @@ -834,9 +834,9 @@ static void early_media_call(void) { } static void simple_call_transfer(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); LinphoneCall* pauline_called_by_marie; char* laure_identity=linphone_address_as_string(laure->identity); @@ -883,9 +883,9 @@ static void simple_call_transfer(void) { } static void call_transfer_existing_call_outgoing_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new(liblinphone_tester_file_prefix, "laure_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); LinphoneCall* marie_call_pauline; LinphoneCall* pauline_called_by_marie; diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index c8571c8b6..9e3e15a36 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -77,8 +77,8 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li } static void subscribe_test_declined(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneContent content; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); @@ -104,8 +104,8 @@ static void subscribe_test_declined(void) { static void subscribe_test_with_args(bool_t terminated_by_subscriber) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneContent content; LinphoneEvent *lev; MSList* lcs=ms_list_append(NULL,marie->lc); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 9f9efc237..40e1f1b2d 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -167,7 +167,7 @@ LinphoneCoreManager *get_manager(LinphoneCore *lc){ return manager; } -LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies) { +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); LinphoneProxyConfig* proxy; int proxy_count=check_for_proxies?(rc_file?1:0):0; @@ -185,7 +185,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc 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->lc=configure_lc_from(&mgr->v_table, path, rc_file); + mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file); linphone_core_set_user_data(mgr->lc,mgr); reset_counters(&mgr->stat); /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ @@ -205,8 +205,8 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc return mgr; } -LinphoneCoreManager* linphone_core_manager_new(const char* path, const char* rc_file) { - return linphone_core_manager_new2(path, rc_file, TRUE); +LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { + return linphone_core_manager_new2(rc_file, TRUE); } void linphone_core_manager_stop(LinphoneCoreManager *mgr){ diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 434c6a0a9..9e98850c7 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -156,8 +156,8 @@ typedef struct _LinphoneCoreManager { bool_t decline_subscribe; } LinphoneCoreManager; -LinphoneCoreManager* linphone_core_manager_new2(const char* path, const char* rc_file, int check_for_proxies); -LinphoneCoreManager* linphone_core_manager_new(const char * path, const char* rc_file); +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); diff --git a/tester/message_tester.c b/tester/message_tester.c index a56e9676a..33536ff7f 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -62,8 +62,8 @@ void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMes } static void text_message(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); @@ -80,8 +80,8 @@ static void text_message(void) { } static void text_message_with_privacy(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneProxyConfig* pauline_proxy; char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); @@ -103,8 +103,8 @@ static void text_message_with_privacy(void) { static void text_message_compatibility_mode(void) { char route[256]; - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneProxyConfig* proxy; LinphoneAddress* proxy_address; char*tmp; @@ -141,8 +141,8 @@ static void text_message_compatibility_mode(void) { } static void text_message_with_ack(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -155,8 +155,8 @@ static void text_message_with_ack(void) { } static void text_message_with_external_body(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -172,8 +172,8 @@ static void text_message_with_external_body(void) { } static void text_message_with_send_error(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); char* to = linphone_address_as_string(pauline->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); @@ -216,8 +216,8 @@ void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneI static void info_message_with_args(bool_t with_content) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneInfoMessage *info; CU_ASSERT_TRUE(call(pauline,marie)); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 543caccbe..c6919bbdf 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -23,7 +23,7 @@ #include "liblinphone_tester.h" static LinphoneCoreManager* presence_linphone_core_manager_new(char* username) { - LinphoneCoreManager* mgr= linphone_core_manager_new2(liblinphone_tester_file_prefix, "empty_rc", FALSE); + 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); @@ -68,7 +68,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { } static void simple_publish(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneProxyConfig* proxy; int i=0; linphone_core_get_default_proxy(marie->lc,&proxy); @@ -124,7 +124,7 @@ static void simple_subscribe(void) { } static void unsubscribe_while_subscribing(void) { - LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ linphone_friend_edit(friend); linphone_friend_enable_subscribes(friend,TRUE); diff --git a/tester/register_tester.c b/tester/register_tester.c index d7dafb76f..0263a4567 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -23,7 +23,7 @@ #include "liblinphone_tester.h" static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { - LinphoneCoreManager* mgr=linphone_core_manager_new(NULL,NULL); + LinphoneCoreManager* mgr=linphone_core_manager_new(NULL); if (with_auth) { mgr->lc->vtable.auth_info_requested=auth_info_requested; @@ -238,7 +238,7 @@ static void authenticated_register_with_no_initial_credentials(){ sprintf(route,"sip:%s",test_route); - mgr = linphone_core_manager_new(NULL,NULL); + mgr = linphone_core_manager_new(NULL); counters= get_stats(mgr->lc); counters->number_of_auth_info_requested=0; @@ -264,7 +264,7 @@ static void authenticated_register_with_late_credentials(){ sprintf(route,"sip:%s",test_route); - mgr = linphone_core_manager_new(NULL,NULL); + mgr = linphone_core_manager_new(NULL); mgr->lc->vtable.auth_info_requested=auth_info_requested2; counters = get_stats(mgr->lc); register_with_refresh_base_2(mgr->lc,FALSE,auth_domain,route,TRUE,transport); @@ -281,7 +281,7 @@ static void authenticated_register_with_wrong_credentials(){ sprintf(route,"sip:%s",test_route); - mgr=linphone_core_manager_new(NULL,NULL); + mgr=linphone_core_manager_new(NULL); mgr->lc->vtable.auth_info_requested=auth_info_requested2; linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/ @@ -292,7 +292,7 @@ static void authenticated_register_with_wrong_credentials(){ } static LinphoneCoreManager* configure_lcm(void) { - LinphoneCoreManager *mgr=linphone_core_manager_new( liblinphone_tester_file_prefix, "multi_account_lrc"); + LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_lrc"); stats *counters=&mgr->stat; CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)))); return mgr; @@ -424,7 +424,7 @@ static void tls_certificate_failure(){ LinphoneCore *lc; char rootcapath[256]; - mgr=linphone_core_manager_new2(liblinphone_tester_file_prefix, "pauline_rc",FALSE); + mgr=linphone_core_manager_new2("pauline_rc",FALSE); lc=mgr->lc; snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ linphone_core_set_root_ca(mgr->lc,rootcapath); @@ -448,7 +448,7 @@ static void tls_with_non_tls_server(){ char tmp[256]; LinphoneCore *lc; - mgr=linphone_core_manager_new2(liblinphone_tester_file_prefix, "marie_rc", 0); + mgr=linphone_core_manager_new2( "marie_rc", 0); lc=mgr->lc; linphone_core_get_default_proxy(lc,&proxy_cfg); linphone_proxy_config_edit(proxy_cfg); diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c index f407808ac..8b1d13e1d 100644 --- a/tester/upnp_tester.c +++ b/tester/upnp_tester.c @@ -25,7 +25,7 @@ static void upnp_start_n_stop(void) { int tmp = 0; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); #ifdef BUILD_UPNP CU_ASSERT_TRUE(lc_upnp->lc->upnp != NULL); @@ -35,7 +35,7 @@ static void upnp_start_n_stop(void) { static void upnp_check_state(void) { int tmp = 0; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); CU_ASSERT_TRUE(linphone_core_get_upnp_state(lc_upnp->lc) == LinphoneUpnpStateOk); linphone_core_manager_destroy(lc_upnp); @@ -43,7 +43,7 @@ static void upnp_check_state(void) { static void upnp_check_ipaddress(void) { int tmp = 0; - LinphoneCoreManager* lc_upnp = linphone_core_manager_new2(liblinphone_tester_file_prefix, "upnp_rc", FALSE); + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); const char *addr = linphone_core_get_upnp_external_ipaddress(lc_upnp->lc); CU_ASSERT_TRUE(addr != NULL && strlen(addr)>=7); From 0c4216948db781fb1cdc7cb9729997e347cd080a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Jun 2013 14:49:07 +0200 Subject: [PATCH 459/909] fix liblinphone-tester for android --- build/android/liblinphone_tester.mk | 1 + tester/liblinphone_tester.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 0f621b35f..b606c6066 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -8,6 +8,7 @@ common_SRC_FILES := \ register_tester.c \ setup_tester.c \ upnp_tester.c \ + eventapi_tester.c # neon diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 40e1f1b2d..f66255e89 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -96,6 +96,8 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* char ringbackpath[256]={0}; char rootcapath[256]={0}; char dnsuserhostspath[256]={0}; + + if (path==NULL) path="."; if (path && file){ sprintf(filepath, "%s/%s", path, file); @@ -105,7 +107,11 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); if (path){ - sprintf(rootcapath, "%s/certificates/cacert.pem", path); +#ifndef ANDROID + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path); +#else + snprintf(rootcapath, sizeof(rootcapath), "%s/cacert.pem", path); +#endif linphone_core_set_root_ca(lc,rootcapath); sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); From 79c72fc860553b85df51cedb580342fe765cda00 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 12 Jun 2013 11:26:32 +0200 Subject: [PATCH 460/909] libxml2 is now mandatory. --- configure.ac | 13 ++++--------- coreapi/Makefile.am | 6 ++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 5c3b8bb92..5bbb5f645 100644 --- a/configure.ac +++ b/configure.ac @@ -202,15 +202,10 @@ if test "$build_upnp" != "false" ; then AC_DEFINE(BUILD_UPNP, 1, [Define if upnp enabled]) fi -dnl check libxml2 (needed for tools) -if test "$build_tools" != "false" ; then - PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[], - [if test "$build_tools" = "true" ; then - AC_MSG_ERROR([Could not found libxml2, tools cannot be compiled.]) - else - build_tools=false - fi] - ) +dnl check libxml2 +PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[libxml2_found=yes],foo=bar) +if test "$libxml2_found" != "yes" ; then + AC_MSG_ERROR([libxml2 not found. Install it and try again (the package is usually named libxml2-dev in the Linux distributions)]) fi AM_CONDITIONAL(BUILD_TOOLS, test x$build_tools != xfalse) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index c9c1b62b8..8184a3df0 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -92,7 +92,8 @@ liblinphone_la_LIBADD= \ $(ORTP_LIBS) $(OPENSSL_LIBS) \ $(TUNNEL_LIBS) \ $(LIBSOUP_LIBS) \ - $(SQLITE3_LIBS) + $(SQLITE3_LIBS) \ + $(LIBXML2_LIBS) if ENABLE_TESTS @@ -126,7 +127,8 @@ AM_CFLAGS=\ -DORTP_INET6 \ $(VIDEO_CFLAGS) \ $(TUNNEL_CFLAGS) \ - $(SQLITE3_CFLAGS) + $(SQLITE3_CFLAGS) \ + $(LIBXML2_CFLAGS) if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD From 220c4713694679d8c88965d563f318c0a6da8833 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 12 Jun 2013 17:36:30 +0200 Subject: [PATCH 461/909] Use xml parser to get presence status. --- coreapi/Makefile.am | 2 +- coreapi/bellesip_sal/sal_impl.c | 2 + coreapi/bellesip_sal/sal_op_presence.c | 71 +-- coreapi/callbacks.c | 9 +- coreapi/friend.c | 90 ++- coreapi/linphonefriend.h | 8 + coreapi/linphonepresence.h | 80 +++ coreapi/presence.c | 805 +++++++++++++++++++++++-- coreapi/private.h | 5 +- include/sal/sal.h | 7 +- 10 files changed, 998 insertions(+), 81 deletions(-) create mode 100644 coreapi/linphonepresence.h diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 8184a3df0..183fe92f0 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -16,7 +16,7 @@ CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone -linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h event.h +linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h if BUILD_TUNNEL linphone_include_HEADERS+=linphone_tunnel.h diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 1583871e1..61cc949fd 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -486,6 +486,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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.notify_presence==NULL) ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; if (ctx->callbacks.subscribe_presence_received==NULL) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index af321069b..4b4476b40 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -497,6 +497,26 @@ static void presence_process_transaction_terminated(void *user_ctx, const belle_ ms_message("presence_process_transaction_terminated not implemented yet"); } +static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_request_t *req) { + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t); + belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_length_t); + const char *body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + SalPresenceModel *result = NULL; + + if ((content_type == NULL) || (content_length == NULL)) + return NULL; + if (belle_sip_header_content_length_get_content_length(content_length) == 0) + return NULL; + + op->base.root->callbacks.parse_presence_requested(op, + belle_sip_header_content_type_get_type(content_type), + belle_sip_header_content_type_get_subtype(content_type), + body, + &result); + + return result; +} + static void 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)); @@ -505,7 +525,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques 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_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - SalPresenceStatus estatus=SalPresenceOffline; + SalPresenceModel *presence_model = NULL; SalSubscribeStatus sub_state; belle_sip_response_t* resp; belle_sip_object_ref(server_transaction); @@ -536,41 +556,22 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); return; } - if (strstr(body,"pending")!=NULL){ - estatus=SalPresenceOffline; - }else if (strstr(body,"busy")!=NULL){ - estatus=SalPresenceBusy; - }else if (strstr(body,"berightback")!=NULL - || strstr(body,"in-transit")!=NULL ){ - estatus=SalPresenceBerightback; - }else if (strstr(body,"away")!=NULL - || strstr(body,"idle")){ - estatus=SalPresenceAway; - }else if (strstr(body,"onthephone")!=NULL - || strstr(body,"on-the-phone")!=NULL){ - estatus=SalPresenceOnthephone; - }else if (strstr(body,"outtolunch")!=NULL - || strstr(body,"lunch")!=NULL - || strstr(body,"meal")!=NULL){ - estatus=SalPresenceOuttolunch; - }else if (strstr(body,"closed")!=NULL){ - estatus=SalPresenceOffline; - }else if ((strstr(body,"online")!=NULL) || (strstr(body,"open")!=NULL)) { - estatus=SalPresenceOnline; - }else if((strstr(body,"vacation")!=NULL)) { - estatus = SalPresenceOnVacation; - }else{ - estatus=SalPresenceOffline; + presence_model = process_presence_notification(op, req); + if (presence_model != NULL) { + /* Presence notification body parsed successfully. */ + if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { + sub_state=SalSubscribeTerminated; + ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + } else { + sub_state=SalSubscribeActive; + } + op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); + resp = sal_op_create_response_from_request(op, req, 200); + } else { + /* Formatting error in presence notification body. */ + ms_error("Wrongly formatted presence notification received"); + resp = sal_op_create_response_from_request(op, req, 400); } - ms_message("We are notified that [%s] has online status [%s]",sal_op_get_to(op),sal_presence_status_to_string(estatus)); - 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("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); - } else - sub_state=SalSubscribeActive; - - op->base.root->callbacks.notify_presence(op,sub_state, estatus,NULL); - resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { /*either a refresh of an unsubscribe*/ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f8ef9dfba..6d7e6d58e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -877,9 +877,13 @@ static void text_received(SalOp *op, const SalMessage *msg){ } } -static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){ +static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) { + linphone_notify_parse_presence(op, content_type, content_subtype, body, result); +} + +static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - linphone_notify_recv(lc,op,ss,status); + linphone_notify_recv(lc,op,ss,model); } static void subscribe_presence_received(SalOp *op, const char *from){ @@ -1085,6 +1089,7 @@ SalCallbacks linphone_sal_callbacks={ notify, subscribe_presence_received, subscribe_presence_closed, + parse_presence_requested, notify_presence, ping_reply, auth_requested, diff --git a/coreapi/friend.c b/coreapi/friend.c index 8bd252aed..df66ada73 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -119,7 +119,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ 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); @@ -138,7 +138,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ LinphoneFriend * linphone_friend_new(){ LinphoneFriend *obj=ms_new0(LinphoneFriend,1); obj->pol=LinphoneSPAccept; - obj->status=LinphoneStatusOffline; + obj->presence=NULL; obj->subscribe=TRUE; return obj; } @@ -304,6 +304,7 @@ void linphone_friend_destroy(LinphoneFriend *lf){ sal_op_release(lf->outsub); lf->outsub=NULL; } + if (lf->presence != NULL) linphone_presence_model_delete(lf->presence); if (lf->uri!=NULL) linphone_address_destroy(lf->uri); if (lf->info!=NULL) buddy_info_free(lf->info); ms_free(lf); @@ -322,7 +323,90 @@ 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 = LinphonePresenceActivityUnknown; + char *activity_description = NULL; + unsigned int nb_activities = 0; + int err = 0; + + if (lf->presence != NULL) { + basic_status = linphone_presence_model_get_basic_status(lf->presence); + nb_activities = linphone_presence_model_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) { + err = linphone_presence_model_get_activity(lf->presence, 0, &activity, &activity_description); + if (err == 0) { + switch (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: + break; + } + } + } + } + + return online_status; +} + +LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf) { + return lf->presence; +} + +void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *model) { + if (lf->presence != NULL) { + linphone_presence_model_delete(lf->presence); + } + lf->presence = model; } BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){ diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index cd5e74a48..e01a5fe44 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -19,9 +19,13 @@ 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 * @{ @@ -206,6 +210,10 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); * @return #LinphoneOnlineStatus */ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); + +LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf); +void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *presence); + 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); diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h new file mode 100644 index 000000000..317e25b2e --- /dev/null +++ b/coreapi/linphonepresence.h @@ -0,0 +1,80 @@ +/* +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 + + +/** Basic status as defined in section 4.1.4 of RFC 3863 */ +typedef enum LinphonePresenceBasicStatus { + LinphonePresenceBasicStatusOpen, + LinphonePresenceBasicStatusClosed +} LinphonePresenceBasicStatus; + +/** Activities as defined in section 3.2 of RFC 4480 */ +typedef enum LinphonePresenceActivity { + LinphonePresenceActivityAppointment, + LinphonePresenceActivityAway, + LinphonePresenceActivityBreakfast, + LinphonePresenceActivityBusy, + LinphonePresenceActivityDinner, + LinphonePresenceActivityHoliday, + LinphonePresenceActivityInTransit, + LinphonePresenceActivityLookingForWork, + LinphonePresenceActivityLunch, + LinphonePresenceActivityMeal, + LinphonePresenceActivityMeeting, + LinphonePresenceActivityOnThePhone, + LinphonePresenceActivityOther, + LinphonePresenceActivityPerformance, + LinphonePresenceActivityPermanentAbsence, + LinphonePresenceActivityPlaying, + LinphonePresenceActivityPresentation, + LinphonePresenceActivityShopping, + LinphonePresenceActivitySleeping, + LinphonePresenceActivitySpectator, + LinphonePresenceActivitySteering, + LinphonePresenceActivityTravel, + LinphonePresenceActivityTV, + LinphonePresenceActivityUnknown, + LinphonePresenceActivityVacation, + LinphonePresenceActivityWorking, + LinphonePresenceActivityWorship +} LinphonePresenceActivity; + +struct _LinphonePresenceModel; +typedef struct _LinphonePresenceModel LinphonePresenceModel; + + +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); +LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model); +LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); +LINPHONE_PUBLIC unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model); +LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description); + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONEPRESENCE_H_ */ diff --git a/coreapi/presence.c b/coreapi/presence.c index 2eb11ff64..9ad01bc07 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -19,11 +19,744 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +#include +#include +#include + + +#define XMLPARSING_BUFFER_LEN 2048 +#define MAX_XPATH_LENGTH 256 + extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); + +struct _LinphonePresenceNote { + char *lang; + char *content; +}; + +struct _LinphonePresenceService { + char *id; + LinphonePresenceBasicStatus status; +}; + +struct _LinphonePresenceActivity { + LinphonePresenceActivity activity; + char *description; +}; + +struct _LinphonePresencePerson { + 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 { + MSList *services; /**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */ + MSList *persons; /**< A list of _LinphonePresencePerson structures. */ + MSList *notes; /**< A list of _LinphonePresenceNote structures. */ +}; + +typedef struct _xmlparsing_context { + xmlDoc *doc; + xmlXPathContextPtr xpath_ctx; + char errorBuffer[XMLPARSING_BUFFER_LEN]; + char warningBuffer[XMLPARSING_BUFFER_LEN]; +} xmlparsing_context_t; + + + +static xmlparsing_context_t * xmlparsing_context_new() { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); + if (xmlCtx != NULL) { + xmlCtx->doc = NULL; + xmlCtx->xpath_ctx = NULL; + xmlCtx->errorBuffer[0] = '\0'; + xmlCtx->warningBuffer[0] = '\0'; + } + return xmlCtx; +} + +static void xmlparsing_context_destroy(xmlparsing_context_t *ctx) { + if (ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + if (ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(ctx->xpath_ctx); + ctx->xpath_ctx = NULL; + } + free(ctx); +} + +static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); + va_end(args); +} + +static struct _LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { + struct _LinphonePresenceNote * note = ms_new0(struct _LinphonePresenceNote, 1); + note->content = ms_strdup(content); + if (lang != NULL) { + note->lang = ms_strdup(lang); + } + return note; +} + +static void presence_note_delete(struct _LinphonePresenceNote *note) { + ms_free(note->content); + if (note->lang != NULL) { + ms_free(note->lang); + } + ms_free(note); +} + +static struct _LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) { + struct _LinphonePresenceService *service = ms_new0(struct _LinphonePresenceService, 1); + if (id != NULL) { + service->id = ms_strdup(id); + } + service->status = status; + return service; +} + +static void presence_service_delete(struct _LinphonePresenceService *service) { + if (service->id != NULL) { + ms_free(service->id); + } + ms_free(service); +}; + +static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivity activity, const char *description) { + struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1); + act->activity = activity; + if (description != NULL) { + act->description = ms_strdup(description); + } + return act; +} + +static void presence_activity_delete(struct _LinphonePresenceActivity *activity) { + if (activity->description != NULL) { + ms_free(activity->description); + } + ms_free(activity); +} + +static time_t parse_timestamp(const char *timestamp) { + struct tm ret; + time_t seconds; + + memset(&ret, 0, sizeof(ret)); + sscanf(timestamp, "%d-%d-%dT%d:%d:%d", + &ret.tm_year, &ret.tm_mon, &ret.tm_mday, &ret.tm_hour, &ret.tm_min, &ret.tm_sec); + ret.tm_mon--; + ret.tm_year -= 1900; + ret.tm_isdst = 0; + seconds = mktime(&ret); + if (seconds == (time_t)-1) { + ms_error("mktime() failed: %s", strerror(errno)); + return (time_t)-1; + } + return seconds - timezone; +} + +static struct _LinphonePresencePerson * presence_person_new(const char *id, const char *timestamp) { + struct _LinphonePresencePerson *person = ms_new0(struct _LinphonePresencePerson, 1); + if (id != NULL) { + person->id = ms_strdup(id); + } + if (timestamp != NULL) { + person->timestamp = parse_timestamp(timestamp); + if (person->timestamp == ((time_t)-1)) + person->timestamp = time(NULL); + } else { + person->timestamp = time(NULL); + } + return person; +} + +static void presence_person_delete(struct _LinphonePresencePerson *person) { + if (person->id != NULL) { + ms_free(person->id); + } + ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete); + ms_list_free(person->activities); + ms_list_for_each(person->activities_notes, (MSIterateFunc)presence_note_delete); + ms_list_free(person->activities_notes); + ms_list_for_each(person->notes, (MSIterateFunc)presence_note_delete); + ms_list_free(person->notes); + ms_free(person); +} + +static void presence_person_add_activity(struct _LinphonePresencePerson *person, struct _LinphonePresenceActivity *activity) { + person->activities = ms_list_append(person->activities, activity); +} + +static void presence_person_add_activities_note(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) { + person->activities_notes = ms_list_append(person->activities_notes, note); +} + +static void presence_person_add_note(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) { + person->notes = ms_list_append(person->notes, note); +} + +static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) { + model->services = ms_list_append(model->services, service); +} + +static void presence_model_add_person(LinphonePresenceModel *model, struct _LinphonePresencePerson *person) { + model->persons = ms_list_append(model->persons, person); +} + +static void presence_model_add_note(LinphonePresenceModel *model, struct _LinphonePresenceNote *note) { + model->notes = ms_list_append(model->notes, note); +} + +static void presence_model_find_open_basic_status(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { + if (service->status == LinphonePresenceBasicStatusOpen) { + *status = LinphonePresenceBasicStatusOpen; + } +} + +LinphonePresenceModel * linphone_presence_model_new(void) { + return ms_new0(LinphonePresenceModel, 1); +} + +void linphone_presence_model_delete(LinphonePresenceModel *model) { + ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); + ms_list_free(model->services); + ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); + ms_list_free(model->persons); + ms_list_for_each(model->notes, (MSIterateFunc)presence_note_delete); + ms_list_free(model->notes); + ms_free(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; + ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status); + return status; +} + +static void presence_model_count_activities(const struct _LinphonePresencePerson *person, unsigned int *nb) { + *nb += ms_list_size(person->activities); +} + +unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model) { + unsigned int nb = 0; + ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb); + return nb; +} + +struct _get_activity_st { + unsigned int requested_idx; + unsigned int current_idx; + LinphonePresenceActivity *activity; + char **description; +}; + +static void presence_model_get_activity(const struct _LinphonePresencePerson *person, struct _get_activity_st *st) { + struct _LinphonePresenceActivity *activity; + unsigned int size = ms_list_size(person->activities); + if (st->requested_idx < (st->current_idx + size)) { + activity = (struct _LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); + *st->activity = activity->activity; + if (st->description != NULL) { + *st->description = activity->description; + } + } else { + st->current_idx += size; + } +} + +int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) { + struct _get_activity_st st; + if ((activity == NULL) || (idx >= linphone_presence_model_nb_activities(model))) + return -1; + memset(&st, 0, sizeof(st)); + st.requested_idx = idx; + st.activity = activity; + *st.activity = LinphonePresenceActivityUnknown; + if (description != NULL) { + st.description = description; + } + ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st); + return 0; +} + +static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { + if (xml_ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(xml_ctx->xpath_ctx); + } + xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); + if (xml_ctx->xpath_ctx == NULL) return -1; + return 0; +} + +static char * get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + xmlXPathObjectPtr xpath_obj; + xmlChar *text = NULL; + int i; + + xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); + if (xpath_obj != NULL) { + if (xpath_obj->nodesetval != NULL) { + xmlNodeSetPtr nodes = xpath_obj->nodesetval; + for (i = 0; i < nodes->nodeNr; i++) { + xmlNodePtr node = nodes->nodeTab[i]; + if (node->children != NULL) { + text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); + } + } + } + xmlXPathFreeObject(xpath_obj); + } + + return (char *)text; +} + +static void free_xml_text_content(const char *text) { + xmlFree((xmlChar *)text); +} + +static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); +} + +static int process_rfcxxxx_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + LinphonePresenceBasicStatus basic_status; + struct _LinphonePresenceService *service; + struct _LinphonePresencePerson *person; + struct _LinphonePresenceActivity *activity = NULL; + char *status_text = NULL; + char *substatus_text = NULL; + + if (create_xml_xpath_context(xml_ctx) < 0) + return -1; + status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status"); + if (status_text == NULL) + return -1; + substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus"); + if (substatus_text == NULL) { + free_xml_text_content(status_text); + return -1; + } + + if (strcmp(status_text, "open") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + if (strcmp(substatus_text, "berightback") == 0) { + activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL); + } else if (strcmp(substatus_text, "away") == 0) { + activity = presence_activity_new(LinphonePresenceActivityAway, NULL); + } else if (strcmp(substatus_text, "outtolunch") == 0) { + activity = presence_activity_new(LinphonePresenceActivityMeal, NULL); + } + } else if (strcmp(status_text, "inuse") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + if (strcmp(substatus_text, "busy") == 0) { + activity = presence_activity_new(LinphonePresenceActivityBusy, NULL); + } else if (strcmp(substatus_text, "onthephone") == 0) { + activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL); + } + } else if (strcmp(status_text, "closed") == 0) { + basic_status = LinphonePresenceBasicStatusClosed; + } + service = presence_service_new(NULL, basic_status); + if (service != NULL) { + presence_model_add_service(model, service); + } + if (activity != NULL) { + person = presence_person_new(NULL, NULL); + if (person != NULL) { + presence_person_add_activity(person, activity); + presence_model_add_person(model, person); + } + } + free_xml_text_content(status_text); + free_xml_text_content(substatus_text); + + return 0; +} + +static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + LinphonePresenceBasicStatus basic_status; + struct _LinphonePresenceService *service; + struct _LinphonePresencePerson *person; + struct _LinphonePresenceActivity *activity = NULL; + char *status_text = NULL; + char *substatus_text = NULL; + + if (create_xml_xpath_context(xml_ctx) < 0) + return -1; + status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status"); + if (status_text == NULL) + return -1; + substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus"); + if (substatus_text == NULL) { + free_xml_text_content(status_text); + return -1; + } + + if (strcmp(status_text, "open") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + } else if (strcmp(status_text, "inuse") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + if (strcmp(substatus_text, "busy") == 0) { + activity = presence_activity_new(LinphonePresenceActivityBusy, NULL); + } else if (strcmp(substatus_text, "onthephone") == 0) { + activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL); + } + } else if (strcmp(status_text, "inactive") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + if (strcmp(substatus_text, "berightback") == 0) { + activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL); + } else if (strcmp(substatus_text, "idle") == 0) { + activity = presence_activity_new(LinphonePresenceActivityAway, NULL); + } else if (strcmp(substatus_text, "outtolunch") == 0) { + activity = presence_activity_new(LinphonePresenceActivityMeal, NULL); + } + } else if (strcmp(status_text, "closed") == 0) { + basic_status = LinphonePresenceBasicStatusClosed; + } + service = presence_service_new(NULL, basic_status); + if (service != NULL) { + presence_model_add_service(model, service); + } + if (activity != NULL) { + person = presence_person_new(NULL, NULL); + if (person != NULL) { + presence_person_add_activity(person, activity); + presence_model_add_person(model, person); + } + } + + return 0; +} + +static const char *service_prefix = "/pidf:presence/pidf:tuple"; + +static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr service_object; + struct _LinphonePresenceService *service; + const char *basic_status_str; + const char *service_id_str; + LinphonePresenceBasicStatus basic_status; + int i; + + service_object = get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); + if ((service_object != NULL) && (service_object->nodesetval != NULL)) { + for (i = 1; i <= service_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i); + basic_status_str = get_xml_text_content(xml_ctx, xpath_str); + if (basic_status_str == NULL) + continue; + + if (strcmp(basic_status_str, "open") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + } else if (strcmp(basic_status_str, "closed") == 0) { + basic_status = LinphonePresenceBasicStatusClosed; + } else { + /* Invalid value for basic status. */ + free_xml_text_content(basic_status_str); + return -1; + } + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i); + service_id_str = get_xml_text_content(xml_ctx, xpath_str); + service = presence_service_new(service_id_str, basic_status); + if (service != NULL) { + presence_model_add_service(model, service); + } + free_xml_text_content(basic_status_str); + if (service_id_str != NULL) free_xml_text_content(service_id_str); + } + } + if (service_object != NULL) xmlXPathFreeObject(service_object); + + return 0; +} + +static const char *person_prefix = "/pidf:presence/dm:person"; + +struct _presence_activity_name_map { + const char *name; + LinphonePresenceActivity activity; +}; + +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_linphone_presence_activity(const char *name, LinphonePresenceActivity *activity) { + unsigned int i; + for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) { + if (strcmp(name, activity_map[i].name) == 0) { + *activity = activity_map[i].activity; + return 0; + } + } + return -1; +} + +static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr activities_nodes_object; + xmlXPathObjectPtr activities_object; + xmlNodePtr activity_node; + struct _LinphonePresenceActivity *activity; + const char *description; + int i, j; + int err = 0; + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities", person_prefix, person_idx); + activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) { + for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/*", person_prefix, person_idx, i); + activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { + for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { + activity_node = activities_object->nodesetval->nodeTab[j]; + if ((activity_node->name != NULL) + && (activity_node->ns != NULL) + && (activity_node->ns->prefix != NULL) + && (strcmp((const char *)activity_node->ns->prefix, "rpid") == 0)) { + LinphonePresenceActivity linphone_activity; + description = (const char *)xmlNodeGetContent(activity_node); + if ((description != NULL) && (description[0] == '\0')) { + free_xml_text_content(description); + description = NULL; + } + err = activity_name_to_linphone_presence_activity((const char *)activity_node->name, &linphone_activity); + if (err < 0) break; + activity = presence_activity_new(linphone_activity, description); + presence_person_add_activity(person, activity); + if (description != NULL) free_xml_text_content(description); + } + } + } + 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, struct _LinphonePresencePerson *person, unsigned int person_idx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr note_object; + struct _LinphonePresenceNote *note; + const char *note_str; + const char *lang; + int i; + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note", person_prefix, person_idx); + note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]", person_prefix, person_idx, i); + note_str = get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); + lang = get_xml_text_content(xml_ctx, xpath_str); + + note = presence_note_new(note_str, lang); + presence_person_add_activities_note(person, note); + if (lang != NULL) free_xml_text_content(lang); + free_xml_text_content(note_str); + } + } + if (note_object != NULL) xmlXPathFreeObject(note_object); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", person_prefix, person_idx); + note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]", person_prefix, person_idx, i); + note_str = get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); + lang = get_xml_text_content(xml_ctx, xpath_str); + + note = presence_note_new(note_str, lang); + presence_person_add_note(person, note); + if (lang != NULL) free_xml_text_content(lang); + free_xml_text_content(note_str); + } + } + if (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + +static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr person_object; + struct _LinphonePresencePerson *person; + const char *person_id_str; + const char *person_timestamp_str; + int i; + int err = 0; + + person_object = get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); + if ((person_object != NULL) && (person_object->nodesetval != NULL)) { + for (i = 1; i <= person_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i); + person_id_str = get_xml_text_content(xml_ctx, xpath_str); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/timestamp", person_prefix, i); + person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + person = presence_person_new(person_id_str, person_timestamp_str); + 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 { + presence_person_delete(person); + break; + } + } + if (person_id_str != NULL) free_xml_text_content(person_id_str); + if (person_timestamp_str != NULL) free_xml_text_content(person_timestamp_str); + } + } + if (person_object != NULL) xmlXPathFreeObject(person_object); + + if (err < 0) { + /* Remove all the persons added since there was an error. */ + ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); + } + 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; + struct _LinphonePresenceNote *note; + const char *note_str; + const char *lang; + int i; + + note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/rpid: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/rpid:note[%i]", i); + note_str = get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/rpid:note[%i]/@xml:lang", i); + lang = get_xml_text_content(xml_ctx, xpath_str); + + note = presence_note_new(note_str, lang); + presence_model_add_note(model, note); + if (lang != NULL) free_xml_text_content(lang); + free_xml_text_content(note_str); + } + } + if (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + +static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) { + LinphonePresenceModel *model = NULL; + int err; + + if (create_xml_xpath_context(xml_ctx) < 0) + return NULL; + + model = linphone_presence_model_new(); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"pidf", (const xmlChar *)"urn:ietf:params:xml:ns:pidf"); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"dm", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model"); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"rpid", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid"); + err = process_pidf_xml_presence_services(xml_ctx, model); + if (err == 0) { + err = process_pidf_xml_presence_persons(xml_ctx, model); + } + if (err == 0) { + err = process_pidf_xml_presence_notes(xml_ctx, model); + } + + if (err < 0) { + linphone_presence_model_delete(model); + model = NULL; + } + + return model; +} + +static LinphonePresenceModel * process_xpidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) { + LinphonePresenceModel *model = NULL; + int err = -1; + xmlDtdPtr dtd = xmlGetIntSubset(xml_ctx->doc); + + if (dtd != NULL) { + if (strcmp((const char *)dtd->name, "presence") == 0) { + model = linphone_presence_model_new(); + if ((strcmp((const char *)dtd->SystemID, "xpidf.dtd") == 0) + && (strcmp((const char *)dtd->ExternalID, "-//IETF//DTD RFCxxxx XPIDF 1.0//EN") == 0)) { + err = process_rfcxxxx_presence_notification(xml_ctx, model); + } else if (strcmp((const char *)dtd->SystemID, "http://schemas.microsoft.com/2002/09/sip/presence") == 0) { + err = process_msoldpres_presence_notification(xml_ctx, model); + } + } + } + + if ((err < 0) && (model != NULL)) { + linphone_presence_model_delete(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); if (fl==NULL) return ; @@ -100,56 +833,54 @@ 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; + bool_t pidf_xml = FALSE; + bool_t xpidf_xml = FALSE; + LinphonePresenceModel *model = NULL; + + if (strcmp(content_type, "application") != 0) { + *result = NULL; + return; + } + + pidf_xml = (strcmp(content_subtype, "pidf+xml") == 0); + xpidf_xml = (strcmp(content_subtype, "xpidf+xml") == 0); + if (pidf_xml || xpidf_xml) { + xml_ctx = xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error); + xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + if (pidf_xml) + model = process_pidf_xml_presence_notification(xml_ctx); + if (xpidf_xml) + model = process_xpidf_xml_presence_notification(xml_ctx); + } else { + ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); + } + xmlparsing_context_destroy(xml_ctx); + } + + *result = (SalPresenceModel *)model; +} + +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 SalPresenceOnVacation: - estatus=LinphoneStatusVacation; - break; - case SalPresenceMoved: - case SalPresenceAltService: - estatus=LinphoneStatusMoved; - break; - } + lf=linphone_find_friend_by_out_subscribe(lc->friends,op); if (lf!=NULL){ friend=lf->uri; tmp=linphone_address_as_string(friend); - lf->status=estatus; + linphone_friend_set_presence(lf, (LinphonePresenceModel *)model); lf->subscribe_active=TRUE; if (lc->vtable.notify_presence_recv) lc->vtable.notify_presence_recv(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_delete((LinphonePresenceModel *)model); } if (ss==SalSubscribeTerminated){ sal_op_release(op); diff --git a/coreapi/private.h b/coreapi/private.h index f64a59c86..e2ecef9e8 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -290,7 +290,8 @@ 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_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); +void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op); void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); @@ -427,7 +428,7 @@ struct _LinphoneFriend{ SalOp *insub; SalOp *outsub; LinphoneSubscribePolicy pol; - LinphoneOnlineStatus status; + LinphonePresenceModel *presence; struct _LinphoneCore *lc; BuddyInfo *info; char *refkey; diff --git a/include/sal/sal.h b/include/sal/sal.h index a96f5fb20..6eabe3def 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -292,6 +292,9 @@ typedef enum SalPresenceStatus{ SalPresenceOnVacation }SalPresenceStatus; +struct _SalPresenceModel; +typedef struct _SalPresenceModel SalPresenceModel; + const char* sal_presence_status_to_string(const SalPresenceStatus status); typedef enum SalReferStatus{ @@ -355,7 +358,8 @@ typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, Sal typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body); typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body); typedef void (*SalOnSubscribeClosed)(SalOp *salop); -typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg); +typedef void (*SalOnParsePresenceRequested)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result); +typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg); typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); @@ -393,6 +397,7 @@ typedef struct SalCallbacks{ SalOnNotify notify; SalOnSubscribePresenceReceived subscribe_presence_received; SalOnSubscribePresenceClosed subscribe_presence_closed; + SalOnParsePresenceRequested parse_presence_requested; SalOnNotifyPresence notify_presence; SalOnPingReply ping_reply; SalOnAuthRequested auth_requested; From 8c9c96218a6e44233971c662ef3583fbffa5426a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 18 Jun 2013 11:45:54 +0200 Subject: [PATCH 462/909] Use presence model to notify presence. Use libxml2 to generate XML content. --- coreapi/bellesip_sal/sal_impl.c | 2 + coreapi/bellesip_sal/sal_impl.h | 2 +- coreapi/bellesip_sal/sal_op_presence.c | 402 +-------------- coreapi/bellesip_sal/sal_op_publish.c | 9 +- coreapi/callbacks.c | 43 +- coreapi/friend.c | 68 +-- coreapi/linphonecall.c | 8 +- coreapi/linphonecore.c | 128 ++++- coreapi/linphonefriend.h | 21 +- coreapi/linphonepresence.h | 11 +- coreapi/presence.c | 651 ++++++++++++++++++++++++- coreapi/private.h | 8 +- coreapi/proxy.c | 7 +- include/sal/sal.h | 6 +- 14 files changed, 861 insertions(+), 505 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 61cc949fd..cf46d4f74 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -488,6 +488,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 61ef731d8..7bc92e2c7 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -134,7 +134,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even 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(belle_sip_message_t *notify, SalPresenceStatus online_status); +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); diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 4b4476b40..321f2e0ac 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -18,404 +18,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.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; - -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 == SalPresenceOnVacation) - { - 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 - -} - -void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status) { - char buf[1000]; +void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence) { char *contact_info; + char *content = NULL; size_t content_length; 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))); - mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); - + op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content); + if (content == NULL) { + ms_free(contact_info); + return; + } belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application",presence_style?"xpidf+xml":"pidf+xml"))); + ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(buf)))); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),buf,content_length); + ,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(contact_info); } @@ -627,9 +251,9 @@ static belle_sip_request_t *create_presence_notify(SalOp *op){ return notify; } -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ +int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ belle_sip_request_t* notify=create_presence_notify(op); - sal_add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*FIXME, what about expires ??*/ + 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); @@ -637,7 +261,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ int sal_notify_presence_close(SalOp *op){ belle_sip_request_t* notify=create_presence_notify(op); - sal_add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*FIXME, what about expires ??*/ + 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 index cf9dc8f54..2445d20e4 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -30,7 +30,7 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher } /*presence publish */ -int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status){ +int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) @@ -41,14 +41,13 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenc op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); - sal_add_presence_info(BELLE_SIP_MESSAGE(req),status); + sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence); return sal_op_send_and_create_refresher(op,req,600,publish_refresher_listener); } else { - /*update status*/ + /*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)); - /*update status*/ - sal_add_presence_info(BELLE_SIP_MESSAGE(last_publish),status); + sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),presence); return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6d7e6d58e..9820ae4de 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -219,21 +219,31 @@ static void call_received(SalOp *h){ bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE); /* first check if we can answer successfully to this invite */ - if (lc->presence_mode==LinphoneStatusBusy || - lc->presence_mode==LinphoneStatusOffline || - lc->presence_mode==LinphoneStatusDoNotDisturb || - lc->presence_mode==LinphoneStatusMoved){ - if (lc->presence_mode==LinphoneStatusBusy ) - sal_call_decline(h,SalReasonBusy,NULL); - else if (lc->presence_mode==LinphoneStatusOffline) - sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->presence_mode==LinphoneStatusDoNotDisturb) - sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved) - sal_call_decline(h,SalReasonRedirect,lc->alt_contact); - sal_op_release(h); - return; + if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) { + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + if (linphone_presence_model_get_activity(lc->presence_model, &activity, NULL)) { + switch (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: + if (lc->alt_contact != NULL) + sal_call_decline(h,SalReasonRedirect,lc->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); @@ -881,6 +891,10 @@ static void parse_presence_requested(SalOp *op, const char *content_type, const 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)); linphone_notify_recv(lc,op,ss,model); @@ -1090,6 +1104,7 @@ SalCallbacks linphone_sal_callbacks={ subscribe_presence_received, subscribe_presence_closed, parse_presence_requested, + convert_presence_to_xml_requested, notify_presence, ping_reply, auth_requested, diff --git a/coreapi/friend.c b/coreapi/friend.c index df66ada73..fe33125d4 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -226,57 +226,12 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri return 0; } -SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){ - switch(os){ - case LinphoneStatusOffline: - return SalPresenceOffline; - break; - case LinphoneStatusOnline: - return SalPresenceOnline; - break; - case LinphoneStatusBusy: - return SalPresenceBusy; - break; - case LinphoneStatusBeRightBack: - return SalPresenceBerightback; - break; - case LinphoneStatusAway: - return SalPresenceAway; - break; - case LinphoneStatusOnThePhone: - return SalPresenceOnthephone; - break; - case LinphoneStatusOutToLunch: - return SalPresenceOuttolunch; - break; - case LinphoneStatusDoNotDisturb: - return SalPresenceDonotdisturb; - break; - case LinphoneStatusMoved: - return SalPresenceMoved; - break; - case LinphoneStatusAltService: - return SalPresenceAltService; - break; - case LinphoneStatusPending: - return SalPresenceOffline; - break; - case LinphoneStatusVacation: - return SalPresenceOnVacation; - break; - default: - return SalPresenceOffline; - break; - } - return SalPresenceOffline; -} - -void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){ +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){ char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("Want to notify %s, insub=%p",addr,lf->insub); ms_free(addr); if (lf->insub!=NULL){ - sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL); + sal_notify_presence(lf->insub,(SalPresenceModel *)presence); } } @@ -343,7 +298,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ nb_activities = 1; } if (nb_activities == 1) { - err = linphone_presence_model_get_activity(lf->presence, 0, &activity, &activity_description); + err = linphone_presence_model_get_activity(lf->presence, &activity, &activity_description); if (err == 0) { switch (activity) { case LinphonePresenceActivityBreakfast: @@ -389,6 +344,12 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ online_status = LinphoneStatusMoved; break; case LinphonePresenceActivityUnknown: + /* Rely on the basic status information. */ + break; + case LinphonePresenceActivityOnline: + case LinphonePresenceActivityOffline: + /* Should not happen! */ + ms_warning("LinphonePresenceActivityOnline or LinphonePresenceActivityOffline should not happen here!"); break; } } @@ -414,27 +375,30 @@ BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){ } void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ + LinphonePresenceModel *model; + if (fr->uri==NULL) { ms_warning("No sip url defined."); return; } - 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_delete(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; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f4a9c508f..e4d1bca6a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -412,8 +412,10 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) { } static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ + LinphonePresenceModel *model; int port_offset; int min_port, max_port; + call->magic=linphone_call_magic; call->refcnt=1; call->state=LinphoneCallIdle; @@ -422,7 +424,9 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; - linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone); + model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); + linphone_core_notify_all_friends(call->core,model); + linphone_presence_model_delete(model); linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ @@ -630,7 +634,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){ } if (ms_list_size(lc->calls)==0) - linphone_core_notify_all_friends(lc,lc->presence_mode); + linphone_core_notify_all_friends(lc,lc->presence_model); linphone_core_conference_check_uninit(lc); if (call->ringing_beep){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f0beca008..605521552 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1337,7 +1337,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta sip_config_read(lc); /* this will start eXosip*/ video_config_read(lc); //autoreplier_config_init(&lc->autoreplier_conf); - lc->presence_mode=LinphoneStatusOnline; + lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); misc_config_read(lc); ui_config_read(lc); #ifdef TUNNEL_ENABLED @@ -3568,12 +3568,12 @@ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const c } int linphone_core_send_publish(LinphoneCore *lc, - LinphoneOnlineStatus presence_mode) + LinphonePresenceModel *presence) { const MSList *elem; for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; - if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode); + if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence); } return 0; } @@ -3642,10 +3642,59 @@ 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; + LinphonePresenceActivity activity = LinphonePresenceActivityUnknown; + switch (os) { + case LinphoneStatusOffline: + activity = LinphonePresenceActivityOffline; + break; + case LinphoneStatusOnline: + activity = LinphonePresenceActivityOnline; + break; + case LinphoneStatusBusy: + activity = LinphonePresenceActivityBusy; + break; + case LinphoneStatusBeRightBack: + activity = LinphonePresenceActivityInTransit; + break; + case LinphoneStatusAway: + activity = LinphonePresenceActivityAway; + break; + case LinphoneStatusOnThePhone: + activity = LinphonePresenceActivityOnThePhone; + break; + case LinphoneStatusOutToLunch: + activity = LinphonePresenceActivityLunch; + break; + case LinphoneStatusDoNotDisturb: + activity = LinphonePresenceActivityBusy; + description = "Do not disturb"; + break; + case LinphoneStatusMoved: + activity = LinphonePresenceActivityPermanentAbsence; + break; + case LinphoneStatusAltService: + activity = LinphonePresenceActivityBusy; + description = "Using another messaging service"; + break; + case LinphoneStatusPending: + activity = LinphonePresenceActivityOther; + description = "Waiting for user acceptance"; + break; + case LinphoneStatusVacation: + activity = LinphonePresenceActivityVacation; + break; + case LinphoneStatusEnd: + ms_warning("Invalid status LinphoneStatusEnd"); + return; + } + presence = linphone_presence_model_new_with_activity(activity, description); + linphone_core_set_presence_model(lc, minutes_away, contact, presence); +} + +void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *contact, LinphonePresenceModel *presence) { if (minutes_away>0) lc->minutes_away=minutes_away; if (lc->alt_contact!=NULL) { @@ -3653,20 +3702,75 @@ void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, lc->alt_contact=NULL; } if (contact) lc->alt_contact=ms_strdup(contact); - if (lc->presence_mode!=presence_mode){ - linphone_core_notify_all_friends(lc,presence_mode); + if (!linphone_presence_model_equals(lc->presence_model,presence)){ + linphone_core_notify_all_friends(lc,presence); /* 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); + linphone_core_send_publish(lc,presence); + } + if ((lc->presence_model != NULL) && (lc->presence_model != presence)) { + linphone_presence_model_delete(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 = LinphonePresenceActivityOffline; + char *description = NULL; + + if ((lc->presence_model == NULL) + || (linphone_presence_model_get_activity(lc->presence_model, &activity, &description) < 0)) + return LinphoneStatusOffline; + + switch (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; } /** diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index e01a5fe44..8ea05e7b1 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -236,13 +236,30 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); * @param os #LinphoneOnlineStatus */ LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); + /** - * get my presence status + * 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 presence #LinphonePresenceModel + */ +LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *alternative_contact, LinphonePresenceModel *presence); + +/** + * Get my presence status * @param lc #LinphoneCore object * @return #LinphoneOnlineStatus */ LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); +/** + * Get my presence status + * @param lc #LinphoneCore object + * @return #LinphonePresenceModel + */ +LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); + 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. @@ -272,7 +289,7 @@ LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore * @param lc #LinphoneCore object * @param os #LinphoneOnlineStatus to notify * */ -void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os); +void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); 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); diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 317e25b2e..9244c4ea7 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -33,6 +33,8 @@ typedef enum LinphonePresenceBasicStatus { /** Activities as defined in section 3.2 of RFC 4480 */ typedef enum LinphonePresenceActivity { + LinphonePresenceActivityOffline, + LinphonePresenceActivityOnline, LinphonePresenceActivityAppointment, LinphonePresenceActivityAway, LinphonePresenceActivityBreakfast, @@ -67,10 +69,17 @@ typedef struct _LinphonePresenceModel LinphonePresenceModel; LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang); LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model); +LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2); LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); LINPHONE_PUBLIC unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model); -LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description); +LINPHONE_PUBLIC int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description); +LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description); +LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description); +LINPHONE_PUBLIC const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); +LINPHONE_PUBLIC int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang); #ifdef __cplusplus diff --git a/coreapi/presence.c b/coreapi/presence.c index 9ad01bc07..caab79581 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" #include +#include #include #include @@ -41,6 +42,9 @@ struct _LinphonePresenceNote { struct _LinphonePresenceService { char *id; LinphonePresenceBasicStatus status; + char *contact; + MSList *notes; /**< A list of _LinphonePresenceNote structures. */ + time_t timestamp; }; struct _LinphonePresenceActivity { @@ -107,6 +111,30 @@ static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { va_end(args); } +static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +static char * generate_presence_id(void) { + char id[7]; + int i; + + for (i = 0; i < 6; i++) { + id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)]; + } + id[6] = '\0'; + + return ms_strdup(id); +} + +static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus basic_status) { + switch (basic_status) { + case LinphonePresenceBasicStatusOpen: + return "open"; + case LinphonePresenceBasicStatusClosed: + default: + return "closed"; + } +} + static struct _LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { struct _LinphonePresenceNote * note = ms_new0(struct _LinphonePresenceNote, 1); note->content = ms_strdup(content); @@ -130,6 +158,7 @@ static struct _LinphonePresenceService * presence_service_new(const char *id, Li service->id = ms_strdup(id); } service->status = status; + service->timestamp = time(NULL); return service; } @@ -137,9 +166,26 @@ static void presence_service_delete(struct _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)presence_service_delete); + ms_list_free(service->notes); ms_free(service); }; +static void presence_service_set_timestamp(struct _LinphonePresenceService *service, time_t timestamp) { + service->timestamp = timestamp; +} + +static void presence_service_set_contact(struct _LinphonePresenceService *service, const char *contact) { + service->contact = ms_strdup(contact); +} + +static void presence_service_add_note(struct _LinphonePresenceService *service, struct _LinphonePresenceNote *note) { + service->notes = ms_list_append(service->notes, note); +} + static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivity activity, const char *description) { struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1); act->activity = activity; @@ -174,18 +220,29 @@ static time_t parse_timestamp(const char *timestamp) { return seconds - timezone; } -static struct _LinphonePresencePerson * presence_person_new(const char *id, const char *timestamp) { +static char * timestamp_to_string(time_t timestamp) { + char timestamp_str[22]; + struct tm *ret; +#ifndef WIN32 + struct tm gmt; + ret = gmtime_r(×tamp,&gmt); +#else + ret = gmtime(&curtime); +#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 struct _LinphonePresencePerson * presence_person_new(const char *id, time_t timestamp) { struct _LinphonePresencePerson *person = ms_new0(struct _LinphonePresencePerson, 1); if (id != NULL) { person->id = ms_strdup(id); } - if (timestamp != NULL) { - person->timestamp = parse_timestamp(timestamp); - if (person->timestamp == ((time_t)-1)) - person->timestamp = time(NULL); - } else { + if (person->timestamp == ((time_t)-1)) person->timestamp = time(NULL); - } + else + person->timestamp = timestamp; return person; } @@ -214,6 +271,11 @@ static void presence_person_add_note(struct _LinphonePresencePerson *person, str person->notes = ms_list_append(person->notes, note); } +static void presence_person_clear_activities(struct _LinphonePresencePerson *person) { + ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete); + ms_list_free(person->activities); +} + static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) { model->services = ms_list_append(model->services, service); } @@ -226,17 +288,151 @@ static void presence_model_add_note(LinphonePresenceModel *model, struct _Linpho model->notes = ms_list_append(model->notes, note); } +static int presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { + struct _LinphonePresenceService *service; + char *id; + if (ms_list_size(model->services) > 0) { + ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); + ms_list_free(model->services); + } + id = generate_presence_id(); + service = presence_service_new(id, basic_status); + ms_free(id); + if (service == NULL) return -1; + presence_model_add_service(model, service); + return 0; +} + +static void presence_model_clear_activities(LinphonePresenceModel *model) { + ms_list_for_each(model->persons, (MSIterateFunc)presence_person_clear_activities); +} + +static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description) { + char *id = NULL; + struct _LinphonePresencePerson *person = NULL; + struct _LinphonePresenceActivity *act = NULL; + + /* Do not add activity for special cases Offline and Online. */ + if ((activity == LinphonePresenceActivityOffline) || (activity == LinphonePresenceActivityOnline)) + return 0; + + 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 = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); + } + act = presence_activity_new(activity, description); + if (act == NULL) + return -1; + presence_person_add_activity(person, act); + + return 0; +} + static void presence_model_find_open_basic_status(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { if (service->status == LinphonePresenceBasicStatusOpen) { *status = LinphonePresenceBasicStatusOpen; } } +static bool_t presence_service_equals(const struct _LinphonePresenceService *s1, const struct _LinphonePresenceService *s2) { + if (s1->status != s2->status) + return FALSE; + return TRUE; +} + +static bool_t presence_note_equals(const struct _LinphonePresenceNote *n1, const struct _LinphonePresenceNote *n2) { + if (((n1->lang == NULL) && (n2->lang != NULL)) + || ((n1->lang != NULL) && (n2->lang == NULL))) + return FALSE; + + if (strcmp(n1->content, n2->content) != 0) + return FALSE; + if ((n1->lang != NULL) && (n2->lang != NULL)) { + if (strcmp(n1->lang, n2->lang) != 0) + return FALSE; + } + + return TRUE; +} + +static bool_t presence_activity_equals(const struct _LinphonePresenceActivity *a1, const struct _LinphonePresenceActivity *a2) { + if (((a1->description == NULL) && (a2->description != NULL)) + || ((a1->description != NULL) && (a2->description == NULL))) + return FALSE; + + if (a1->activity != a2->activity) + return FALSE; + + if ((a1->description != NULL) && (a2->description != NULL)) { + if (strcmp(a1->description, a2->description) != 0) + return FALSE; + } + + return TRUE; +} + +static bool_t presence_person_equals(const struct _LinphonePresencePerson *p1, const struct _LinphonePresencePerson *p2) { + int nb; + int i; + + if ((ms_list_size(p1->activities) != ms_list_size(p2->activities)) + || (ms_list_size(p1->activities_notes) != ms_list_size(p2->activities_notes)) + || (ms_list_size(p1->notes) != ms_list_size(p2->notes))) + return FALSE; + + nb = ms_list_size(p1->activities); + for (i = 0; i < nb; i++) { + if (presence_activity_equals(ms_list_nth_data(p1->activities, i), ms_list_nth_data(p2->activities, i)) == FALSE) + return FALSE; + } + + nb = ms_list_size(p1->activities_notes); + for (i = 0; i < nb; i++) { + if (presence_note_equals(ms_list_nth_data(p1->activities_notes, i), ms_list_nth_data(p2->activities_notes, i)) == FALSE) + return FALSE; + } + + nb = ms_list_size(p1->notes); + for (i = 0; i < nb; i++) { + if (presence_note_equals(ms_list_nth_data(p1->notes, i), ms_list_nth_data(p2->notes, i)) == FALSE) + return FALSE; + } + + return TRUE; +} + LinphonePresenceModel * linphone_presence_model_new(void) { return ms_new0(LinphonePresenceModel, 1); } +LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description) { + LinphonePresenceModel *model = linphone_presence_model_new(); + if (model != NULL) { + linphone_presence_model_set_activity(model, activity, description); + } + return model; +} + +LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang) { + LinphonePresenceModel *model = linphone_presence_model_new(); + if (model != NULL) { + linphone_presence_model_set_activity(model, activity, description); + linphone_presence_model_set_note(model, note, lang); + } + return model; +} + void linphone_presence_model_delete(LinphonePresenceModel *model) { + if (model == NULL) return; + ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); ms_list_free(model->services); ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); @@ -246,10 +442,61 @@ void linphone_presence_model_delete(LinphonePresenceModel *model) { ms_free(model); } +bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2) { + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + int nb; + int i; + + /* Two null activities are considered equal. */ + if ((m1 == NULL) && (m2 == NULL)) + return TRUE; + + /* A null activity is equal to an activity with no activity but a basic status of Closed. */ + if (m1 == NULL) { + if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0) + || (activity != LinphonePresenceActivityOffline)) + return FALSE; + return TRUE; + } + if (m2 == NULL) { + if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0) + || (activity != LinphonePresenceActivityOffline)) + return FALSE; + return TRUE; + } + + if ((ms_list_size(m1->services) != ms_list_size(m2->services)) + || (ms_list_size(m1->persons) != ms_list_size(m2->persons)) + || (ms_list_size(m1->notes) != ms_list_size(m2->notes))) + return FALSE; + + nb = ms_list_size(m1->services); + for (i = 0; i < nb; i++) { + if (presence_service_equals(ms_list_nth_data(m1->services, i), ms_list_nth_data(m2->services, i)) == FALSE) + return FALSE; + } + + nb = ms_list_size(m1->persons); + for (i = 0; i < nb; i++) { + if (presence_person_equals(ms_list_nth_data(m1->persons, i), ms_list_nth_data(m2->persons, i)) == FALSE) + return FALSE; + } + + nb = ms_list_size(m1->notes); + for (i = 0; i < nb; i++) { + if (presence_note_equals(ms_list_nth_data(m1->notes, i), ms_list_nth_data(m2->notes, i)) == FALSE) + return FALSE; + } + + return TRUE; +} + /* 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; - ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status); + if (model != NULL) { + ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status); + } return status; } @@ -284,10 +531,12 @@ static void presence_model_get_activity(const struct _LinphonePresencePerson *pe } } -int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) { +int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) { struct _get_activity_st st; - if ((activity == NULL) || (idx >= linphone_presence_model_nb_activities(model))) + + if ((model == NULL) || (activity == NULL) || (idx >= linphone_presence_model_nb_activities(model))) return -1; + memset(&st, 0, sizeof(st)); st.requested_idx = idx; st.activity = activity; @@ -296,9 +545,63 @@ int linphone_presence_model_get_activity(const LinphonePresenceModel *model, uns st.description = description; } ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st); + return 0; } +int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description) { + if ((model == NULL) || (activity == NULL)) + return -1; + + if (linphone_presence_model_get_nth_activity(model, 0, activity, description) < 0) { + /* There is no activities, base the result on the basic status. */ + LinphonePresenceBasicStatus basic_status = linphone_presence_model_get_basic_status(model); + if (basic_status == LinphonePresenceBasicStatusOpen) + *activity = LinphonePresenceActivityOnline; + else + *activity = LinphonePresenceActivityOffline; + } + + return 0; +} + +int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description) { + LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen; + + if (model == NULL) return -1; + + switch (activity) { + case LinphonePresenceActivityAppointment: + case LinphonePresenceActivityBusy: + case LinphonePresenceActivityMeeting: + case LinphonePresenceActivityPermanentAbsence: + case LinphonePresenceActivityOffline: + case LinphonePresenceActivityWorship: + basic_status = LinphonePresenceBasicStatusClosed; + break; + default: + basic_status = LinphonePresenceBasicStatusOpen; + break; + } + if (presence_model_set_basic_status(model, basic_status) < 0) + return -1; + presence_model_clear_activities(model); + if (presence_model_add_activity(model, activity, description) < 0) + return -1; + + return 0; +} + +const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { + // TODO + return NULL; +} + +int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang) { + // TODO + return -1; +} + static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { if (xml_ctx->xpath_ctx != NULL) { xmlXPathFreeContext(xml_ctx->xpath_ctx); @@ -381,7 +684,7 @@ static int process_rfcxxxx_presence_notification(xmlparsing_context_t *xml_ctx, presence_model_add_service(model, service); } if (activity != NULL) { - person = presence_person_new(NULL, NULL); + person = presence_person_new(NULL, time(NULL)); if (person != NULL) { presence_person_add_activity(person, activity); presence_model_add_person(model, person); @@ -438,7 +741,7 @@ static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx presence_model_add_service(model, service); } if (activity != NULL) { - person = presence_person_new(NULL, NULL); + person = presence_person_new(NULL, time(NULL)); if (person != NULL) { presence_person_add_activity(person, activity); presence_model_add_person(model, person); @@ -450,12 +753,43 @@ static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx static const char *service_prefix = "/pidf:presence/pidf:tuple"; +static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresenceService *service, unsigned int service_idx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr note_object; + struct _LinphonePresenceNote *note; + const char *note_str; + const char *lang; + int i; + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", service_prefix, service_idx); + note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + if ((note_object != NULL) && (note_object->nodesetval != NULL)) { + for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]", service_prefix, service_idx, i); + note_str = get_xml_text_content(xml_ctx, xpath_str); + if (note_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]/@xml:lang", service_prefix, service_idx, i); + lang = get_xml_text_content(xml_ctx, xpath_str); + + note = presence_note_new(note_str, lang); + presence_service_add_note(service, note); + if (lang != NULL) free_xml_text_content(lang); + free_xml_text_content(note_str); + } + } + if (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr service_object; struct _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; @@ -477,10 +811,25 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin return -1; } + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i); + timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i); + contact_str = get_xml_text_content(xml_ctx, xpath_str); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i); service_id_str = get_xml_text_content(xml_ctx, xpath_str); service = presence_service_new(service_id_str, basic_status); if (service != NULL) { + if (timestamp_str != NULL) { + presence_service_set_timestamp(service, parse_timestamp(timestamp_str)); + free_xml_text_content(timestamp_str); + } + if (contact_str != NULL) { + presence_service_set_contact(service, contact_str); + free_xml_text_content(contact_str); + } + process_pidf_xml_presence_service_notes(xml_ctx, service, i); presence_model_add_service(model, service); } free_xml_text_content(basic_status_str); @@ -540,6 +889,16 @@ static int activity_name_to_linphone_presence_activity(const char *name, Linphon return -1; } +static const char * presence_activity_to_string(LinphonePresenceActivity activity) { + unsigned int i; + for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) { + if (activity == activity_map[i].activity) { + return activity_map[i].name; + } + } + return NULL; +} + static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr activities_nodes_object; @@ -638,6 +997,7 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp struct _LinphonePresencePerson *person; const char *person_id_str; const char *person_timestamp_str; + time_t timestamp; int i; int err = 0; @@ -646,9 +1006,13 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp for (i = 1; i <= person_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i); person_id_str = get_xml_text_content(xml_ctx, xpath_str); - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/timestamp", person_prefix, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i); person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str); - person = presence_person_new(person_id_str, person_timestamp_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) { @@ -775,13 +1139,13 @@ 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); + ms_message("Notifying all friends"); 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); } } } @@ -864,6 +1228,259 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c *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_timestamp(xmlTextWriterPtr writer, time_t timestamp) { + int err; + char *timestamp_str = timestamp_to_string(timestamp); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"timestamp", (const xmlChar *)timestamp_str); + if (timestamp_str) ms_free(timestamp_str); + return err; +} + +static int write_xml_presence_service(xmlTextWriterPtr writer, struct _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) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)contact); + } + if (err >= 0) { + /* Close the "contact" element. */ + err = xmlTextWriterEndElement(writer); + } + 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 int write_xml_presence_activity(xmlTextWriterPtr writer, struct _LinphonePresenceActivity *activity) { + int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid", + (const xmlChar *)presence_activity_to_string(activity->activity), 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(struct _LinphonePresenceActivity *activity, struct _presence_activity_obj_st *st) { + int err = write_xml_presence_activity(st->writer, activity); + if (err < 0) *st->err = err; +} + +static int write_xml_presence_note(xmlTextWriterPtr writer, struct _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(struct _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_person(xmlTextWriterPtr writer, struct _LinphonePresencePerson *person) { + int 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->activities != NULL))) { + 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->activities_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(struct _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(struct _LinphonePresencePerson *person, struct _presence_person_obj_st *st) { + int err = write_xml_presence_person(st->writer, person); + if (err < 0) *st->err = err; +} + +void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) { + LinphonePresenceModel *model; + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + + if ((contact == NULL) || (content == NULL)) return; + + model = (LinphonePresenceModel *)presence; + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return; + } + + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"presence", (const xmlChar *)"urn:ietf:params:xml:ns:pidf"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"dm", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"rpid", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"entity", (const xmlChar *)contact); + } + if (err >= 0) { + if ((model == NULL) || (model->services == NULL)) { + err = write_xml_presence_service(writer, NULL, contact); + } else { + struct _presence_service_obj_st st; + st.writer = writer; + st.contact = contact; + st.err = &err; + ms_list_for_each2(model->services, (MSIterate2Func)write_xml_presence_service_obj, &st); + } + } + if ((err >= 0) && (model != NULL)) { + struct _presence_person_obj_st st; + st.writer = writer; + st.err = &err; + ms_list_for_each2(model->persons, (MSIterate2Func)write_xml_presence_person_obj, &st); + } + if ((err >= 0) && (model != NULL)) { + struct _presence_note_obj_st st; + st.writer = writer; + st.ns = NULL; + st.err = &err; + ms_list_for_each2(model->notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + } + if (err >= 0) { + /* Close the "presence" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + + xmlFreeTextWriter(writer); + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + *content = ms_strdup((char *)buf->content); + } + xmlBufferFree(buf); +} + void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){ char *tmp; LinphoneFriend *lf; diff --git a/coreapi/private.h b/coreapi/private.h index e2ecef9e8..e85c169fc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -233,7 +233,7 @@ 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_write_all_to_config_file(LinphoneCore *lc); /* @@ -245,7 +245,7 @@ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphonePro int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); -void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os); +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); @@ -286,11 +286,11 @@ static inline void set_string(char **dest, const char *src){ #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 -SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os); void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from); void linphone_notify_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); @@ -599,7 +599,7 @@ struct _LinphoneCore MSList *bl_reqs; MSList *subscribers; /* unknown subscribers */ int minutes_away; - LinphoneOnlineStatus presence_mode; + LinphonePresenceModel *presence_model; char *alt_contact; void *data; char *play_file; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 4bf6e6dc1..814c00766 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -849,8 +849,7 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm if (realm!=NULL) cfg->realm=ms_strdup(realm); } -int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, - LinphoneOnlineStatus presence_mode){ +int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){ int err; if (proxy->publish_op==NULL){ @@ -859,7 +858,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); } - err=sal_publish_presence(proxy->publish_op,NULL,NULL,linphone_online_status_to_sal(presence_mode)); + err=sal_publish_presence(proxy->publish_op,NULL,NULL,(SalPresenceModel *)presence); return err; } @@ -1190,7 +1189,7 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ } } if (cfg->publish && cfg->publish_op==NULL && cfg->state==LinphoneRegistrationOk){ - linphone_proxy_config_send_publish(cfg,lc->presence_mode); + linphone_proxy_config_send_publish(cfg,lc->presence_model); } } diff --git a/include/sal/sal.h b/include/sal/sal.h index 6eabe3def..0e94faf5b 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -359,6 +359,7 @@ typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *ev typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body); typedef void (*SalOnSubscribeClosed)(SalOp *salop); typedef void (*SalOnParsePresenceRequested)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result); +typedef void (*SalOnConvertPresenceToXMLRequested)(SalOp *salop, SalPresenceModel *presence, const char *contact, char **content); typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg); typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); @@ -398,6 +399,7 @@ typedef struct SalCallbacks{ SalOnSubscribePresenceReceived subscribe_presence_received; SalOnSubscribePresenceClosed subscribe_presence_closed; SalOnParsePresenceRequested parse_presence_requested; + SalOnConvertPresenceToXMLRequested convert_presence_to_xml_requested; SalOnNotifyPresence notify_presence; SalOnPingReply ping_reply; SalOnAuthRequested auth_requested; @@ -532,11 +534,11 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to); -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message); +int sal_notify_presence(SalOp *op, SalPresenceModel *presence); int sal_notify_presence_close(SalOp *op); /*presence publish */ -int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status); +int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence); /*ping: main purpose is to obtain its own contact address behind firewalls*/ From c5de03334847f8974f0328b594237dac5cceb1a8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Jun 2013 10:39:39 +0200 Subject: [PATCH 463/909] Remove support of RFCxxxx and MSOLDPRES presence content. --- coreapi/presence.c | 148 ++------------------------------------------- 1 file changed, 4 insertions(+), 144 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index caab79581..167ed1396 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -641,116 +641,6 @@ static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); } -static int process_rfcxxxx_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { - LinphonePresenceBasicStatus basic_status; - struct _LinphonePresenceService *service; - struct _LinphonePresencePerson *person; - struct _LinphonePresenceActivity *activity = NULL; - char *status_text = NULL; - char *substatus_text = NULL; - - if (create_xml_xpath_context(xml_ctx) < 0) - return -1; - status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status"); - if (status_text == NULL) - return -1; - substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus"); - if (substatus_text == NULL) { - free_xml_text_content(status_text); - return -1; - } - - if (strcmp(status_text, "open") == 0) { - basic_status = LinphonePresenceBasicStatusOpen; - if (strcmp(substatus_text, "berightback") == 0) { - activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL); - } else if (strcmp(substatus_text, "away") == 0) { - activity = presence_activity_new(LinphonePresenceActivityAway, NULL); - } else if (strcmp(substatus_text, "outtolunch") == 0) { - activity = presence_activity_new(LinphonePresenceActivityMeal, NULL); - } - } else if (strcmp(status_text, "inuse") == 0) { - basic_status = LinphonePresenceBasicStatusOpen; - if (strcmp(substatus_text, "busy") == 0) { - activity = presence_activity_new(LinphonePresenceActivityBusy, NULL); - } else if (strcmp(substatus_text, "onthephone") == 0) { - activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL); - } - } else if (strcmp(status_text, "closed") == 0) { - basic_status = LinphonePresenceBasicStatusClosed; - } - service = presence_service_new(NULL, basic_status); - if (service != NULL) { - presence_model_add_service(model, service); - } - if (activity != NULL) { - person = presence_person_new(NULL, time(NULL)); - if (person != NULL) { - presence_person_add_activity(person, activity); - presence_model_add_person(model, person); - } - } - free_xml_text_content(status_text); - free_xml_text_content(substatus_text); - - return 0; -} - -static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { - LinphonePresenceBasicStatus basic_status; - struct _LinphonePresenceService *service; - struct _LinphonePresencePerson *person; - struct _LinphonePresenceActivity *activity = NULL; - char *status_text = NULL; - char *substatus_text = NULL; - - if (create_xml_xpath_context(xml_ctx) < 0) - return -1; - status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status"); - if (status_text == NULL) - return -1; - substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus"); - if (substatus_text == NULL) { - free_xml_text_content(status_text); - return -1; - } - - if (strcmp(status_text, "open") == 0) { - basic_status = LinphonePresenceBasicStatusOpen; - } else if (strcmp(status_text, "inuse") == 0) { - basic_status = LinphonePresenceBasicStatusOpen; - if (strcmp(substatus_text, "busy") == 0) { - activity = presence_activity_new(LinphonePresenceActivityBusy, NULL); - } else if (strcmp(substatus_text, "onthephone") == 0) { - activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL); - } - } else if (strcmp(status_text, "inactive") == 0) { - basic_status = LinphonePresenceBasicStatusOpen; - if (strcmp(substatus_text, "berightback") == 0) { - activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL); - } else if (strcmp(substatus_text, "idle") == 0) { - activity = presence_activity_new(LinphonePresenceActivityAway, NULL); - } else if (strcmp(substatus_text, "outtolunch") == 0) { - activity = presence_activity_new(LinphonePresenceActivityMeal, NULL); - } - } else if (strcmp(status_text, "closed") == 0) { - basic_status = LinphonePresenceBasicStatusClosed; - } - service = presence_service_new(NULL, basic_status); - if (service != NULL) { - presence_model_add_service(model, service); - } - if (activity != NULL) { - person = presence_person_new(NULL, time(NULL)); - if (person != NULL) { - presence_person_add_activity(person, activity); - presence_model_add_person(model, person); - } - } - - return 0; -} - static const char *service_prefix = "/pidf:presence/pidf:tuple"; static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresenceService *service, unsigned int service_idx) { @@ -1093,31 +983,6 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing return model; } -static LinphonePresenceModel * process_xpidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) { - LinphonePresenceModel *model = NULL; - int err = -1; - xmlDtdPtr dtd = xmlGetIntSubset(xml_ctx->doc); - - if (dtd != NULL) { - if (strcmp((const char *)dtd->name, "presence") == 0) { - model = linphone_presence_model_new(); - if ((strcmp((const char *)dtd->SystemID, "xpidf.dtd") == 0) - && (strcmp((const char *)dtd->ExternalID, "-//IETF//DTD RFCxxxx XPIDF 1.0//EN") == 0)) { - err = process_rfcxxxx_presence_notification(xml_ctx, model); - } else if (strcmp((const char *)dtd->SystemID, "http://schemas.microsoft.com/2002/09/sip/presence") == 0) { - err = process_msoldpres_presence_notification(xml_ctx, model); - } - } - } - - if ((err < 0) && (model != NULL)) { - linphone_presence_model_delete(model); - model = NULL; - } - - return model; -} - @@ -1199,8 +1064,6 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ 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; - bool_t pidf_xml = FALSE; - bool_t xpidf_xml = FALSE; LinphonePresenceModel *model = NULL; if (strcmp(content_type, "application") != 0) { @@ -1208,21 +1071,18 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c return; } - pidf_xml = (strcmp(content_subtype, "pidf+xml") == 0); - xpidf_xml = (strcmp(content_subtype, "xpidf+xml") == 0); - if (pidf_xml || xpidf_xml) { + if (strcmp(content_subtype, "pidf+xml") == 0) { xml_ctx = xmlparsing_context_new(); xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error); xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0); if (xml_ctx->doc != NULL) { - if (pidf_xml) - model = process_pidf_xml_presence_notification(xml_ctx); - if (xpidf_xml) - model = process_xpidf_xml_presence_notification(xml_ctx); + model = process_pidf_xml_presence_notification(xml_ctx); } else { ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); } xmlparsing_context_destroy(xml_ctx); + } else { + ms_error("Unknown content type '%s/%s' for presence", content_type, content_subtype); } *result = (SalPresenceModel *)model; From b069a3873ebe5f1f56b1d4ed4ceec0c4a6e911e2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Jun 2013 14:46:17 +0200 Subject: [PATCH 464/909] Handle setting and getting notes from the presence model. --- coreapi/linphonepresence.h | 3 +- coreapi/presence.c | 168 +++++++++++++++++++++++++++++++++++-- 2 files changed, 164 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 9244c4ea7..869d39baf 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -79,7 +79,8 @@ LINPHONE_PUBLIC int linphone_presence_model_get_nth_activity(const LinphonePrese LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description); LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description); LINPHONE_PUBLIC const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); -LINPHONE_PUBLIC int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang); +LINPHONE_PUBLIC int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang); +LINPHONE_PUBLIC int linphone_presence_model_clear_notes(LinphonePresenceModel *model); #ifdef __cplusplus diff --git a/coreapi/presence.c b/coreapi/presence.c index 167ed1396..192dabb94 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -152,6 +152,13 @@ static void presence_note_delete(struct _LinphonePresenceNote *note) { ms_free(note); } +static void presence_note_set_content(struct _LinphonePresenceNote *note, const char *content) { + if (note->content != NULL) { + ms_free(note->content); + } + note->content = ms_strdup(content); +} + static struct _LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) { struct _LinphonePresenceService *service = ms_new0(struct _LinphonePresenceService, 1); if (id != NULL) { @@ -425,7 +432,7 @@ LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(Linph LinphonePresenceModel *model = linphone_presence_model_new(); if (model != NULL) { linphone_presence_model_set_activity(model, activity, description); - linphone_presence_model_set_note(model, note, lang); + linphone_presence_model_add_note(model, note, lang); } return model; } @@ -592,14 +599,163 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP return 0; } -const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { - // TODO +struct _find_note_st { + const char *lang; + struct _LinphonePresenceNote *note; +}; + +static struct _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++) { + struct _LinphonePresenceNote *note = (struct _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; } -int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang) { - // TODO - return -1; +static void find_presence_person_note(struct _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(struct _LinphonePresenceService *service, struct _find_note_st *st) { + st->note = find_presence_note_in_list(service->notes, st->lang); +} + +static struct _LinphonePresenceNote * get_first_presence_note_in_list(MSList *list) { + return (struct _LinphonePresenceNote *)ms_list_nth_data(list, 0); +} + +static void get_first_presence_person_note(struct _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(struct _LinphonePresenceService *service, struct _find_note_st *st) { + st->note = get_first_presence_note_in_list(service->notes); +} + +const char * 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); + } + } + + if (st.note == NULL) + return NULL; + + return ms_strdup(st.note->content); +} + +int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) { + struct _LinphonePresenceService *service; + struct _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 = presence_note_new(note_content, lang); + } else { + 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(struct _LinphonePresencePerson *person) { + ms_list_for_each(person->activities_notes, (MSIterateFunc)presence_note_delete); + ms_list_free(person->activities_notes); + person->activities_notes = NULL; + ms_list_for_each(person->notes, (MSIterateFunc)presence_note_delete); + ms_list_free(person->notes); + person->notes = NULL; +} + +static void clear_presence_service_notes(struct _LinphonePresenceService *service) { + ms_list_for_each(service->notes, (MSIterateFunc)presence_note_delete); + 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)presence_note_delete); + ms_list_free(model->notes); + model->notes = NULL; + + return 0; } static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { From a4340fc442a8cdf9680cb38997da8a8facd4d98d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Jun 2013 16:20:19 +0200 Subject: [PATCH 465/909] Update documentation about presence. --- coreapi/friend.c | 4 +- coreapi/help/buddy_status.c | 16 ++- coreapi/help/doxygen.dox | 2 +- coreapi/linphonefriend.h | 55 ++++++---- coreapi/linphonepresence.h | 202 ++++++++++++++++++++++++++++++++++++ coreapi/presence.c | 29 +++++- 6 files changed, 279 insertions(+), 29 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index fe33125d4..e02078319 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -359,11 +359,11 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ return online_status; } -LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf) { +LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf) { return lf->presence; } -void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *model) { +void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *model) { if (lf->presence != NULL) { linphone_presence_model_delete(lf->presence); } diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 6fdb47f40..4f9db8ea7 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -51,9 +51,15 @@ static void stop(int signum){ * presence state change notification callback */ static void notify_presence_recv_updated (LinphoneCore *lc, LinphoneFriend *friend) { + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + const LinphonePresenceModel* model = linphone_friend_get_presence_model(friend); const LinphoneAddress* friend_address = linphone_friend_get_address(friend); - printf("New state state [%s] for user id [%s] \n" - ,linphone_online_status_to_string(linphone_friend_get_status(friend)) + char *description = NULL; + linphone_presence_model_get_activity(model, &activity, &description); + printf("New state state [%s%s%s] for user id [%s] \n" + ,linphone_presence_activity_to_string(activity) + ,(description == NULL) ? "" : ": " + ,(description == NULL) ? "" : description ,linphone_address_as_string (friend_address)); } static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *friend, const char* url) { @@ -164,7 +170,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, 0, NULL, linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL)); /* main loop for receiving notifications and doing background linphone core work: */ while(running){ @@ -172,7 +179,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, 0, NULL, linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL)); linphone_core_iterate(lc); /* just to make sure new status is initiate message is issued */ linphone_friend_edit(my_friend); /* start editing friend */ diff --git a/coreapi/help/doxygen.dox b/coreapi/help/doxygen.dox index 8b2e6b7b9..656f25e09 100644 --- a/coreapi/help/doxygen.dox +++ b/coreapi/help/doxygen.dox @@ -152,7 +152,7 @@ linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE mess Publishing presence status -
Local presence status can be changed using function linphone_core_set_presence_info() .New status is propagated to all friends \link linphone_core_add_friend() previously added \endlink to #LinphoneCore. +
Local presence status can be changed using function linphone_core_set_presence_model() .New status is propagated to all friends \link linphone_core_add_friend() previously added \endlink to #LinphoneCore. Handling incoming subscription request
New incoming subscription requests are process according to \link linphone_friend_set_inc_subscribe_policy() the incoming subscription policy state \endlink for subscription initiated by \link linphone_core_add_friend() members of the buddy list. \endlink diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 8ea05e7b1..b4ee2e801 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -54,6 +54,7 @@ typedef enum { /** * Enum describing remote friend status + * @deprecated Use #LinphonePresenceModel and #LinphonePresenceActivity instead */ typedef enum _LinphoneOnlineStatus{ /** @@ -206,13 +207,26 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); /** - * get friend status + * @brief 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); -LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf); -void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *presence); +/** + * @brief Get the presence information of a friend + * @param[in] lf A #LinphoneFriend object + * @return A #LinphonePresenceModel object, or NULL if the friend to not have presence information (in which he is considered offline) + */ +LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); + +/** + * @brief Set the presence information of a friend + * @param[in] lf A #LinphoneFriend object + * @param[in] presence A #LinphonePresenceModel object. It can be NULL to remove the presence information of the friend. + */ +void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence); BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); @@ -222,41 +236,44 @@ bool_t linphone_friend_in_list(const LinphoneFriend *lf); #define linphone_friend_url(lf) ((lf)->url) /** - * return humain readable presence status + * Return humain readable presence status * @param ss + * @deprecated Use #LinphonePresenceModel, #LinphonePresenceActivity and linphone_presence_activity_to_string() instead. */ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); /** - * 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 + * @brief Set my presence status + * @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 */ LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); /** - * 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 presence #LinphonePresenceModel + * @brief Set my presence status + * @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] presence #LinphonePresenceModel */ LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *alternative_contact, LinphonePresenceModel *presence); /** - * Get my presence status - * @param lc #LinphoneCore object + * @brief Get my presence status + * @param[in] lc #LinphoneCore object * @return #LinphoneOnlineStatus + * @deprecated Use linphone_core_get_presence_model() instead */ LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); /** - * Get my presence status - * @param lc #LinphoneCore object - * @return #LinphonePresenceModel + * @brief Get my presence status + * @param[in] lc #LinphoneCore object + * @return A #LinphonePresenceModel object, or NULL if no presence model has been set. */ LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 869d39baf..95281bafc 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -20,68 +20,270 @@ 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 LinphonePresenceActivity { + /** 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 } LinphonePresenceActivity; +/** + * 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; + +/** + * @brief Creates a default presence model. + * @returns The created presence model, NULL on error. + * @see linphone_presence_model_new_with_activity + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model is considered 'offline'. + */ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); + +/** + * @brief Creates a presence model specifying an activity. + * @param[in] activity The activity to set for the created presence model. + * @param[in] description An additional description of the activity (mainly useful for the 'other' activity). Set it to NULL to not add a description. + * @returns The created presence model, or NULL if an error occured. + * @see linphone_presence_model_new + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model has the activity specified in the parameters. + */ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description); + +/** + * @brief Creates a presence model specifying an activity and adding a note. + * @param[in] activity The activity to set for the created presence model. + * @param[in] description An additional description of the activity (mainly useful for the 'other' activity). Set it to NULL to not add a description. + * @param[in] note An additional note giving additional information about the contact presence. + * @param[in] lang The language the note is written in. It can be set to NULL in order to not specify the language of the note. + * @returns The created presence model, or NULL if an error occured. + * @see linphone_presence_model_new_with_activity + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model has the activity and the note specified in the parameters. + */ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang); + +/** + * @brief Deletes a presence model. + * @param[in] model The #LinphonePresenceModel object to delete. + */ LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model); + +/** + * @brief Compares two presence models. + * @param[in] m1 The first #LinphonePresenceModel object. + * @param[in] m2 The second #LinphonePresenceModel object. + * @return TRUE if the #LinphonePresenceModel objects are equals, FALSE otherwise. + */ LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2); + +/** + * @brief 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); + +/** + * @brief 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_nb_activities(const LinphonePresenceModel *model); + +/** + * @brief 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). + * @param[out] activity The returned #LinphonePresenceActivity (may not be changed in case of error). + * @param[out] description The description of the returned #LinphonePresenceActivity (may not be changed in case of error). + * @return 0 if successful, a value < 0 in case of error. + */ LINPHONE_PUBLIC int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description); + +/** + * @brief Gets the first activity of a presence model (there is usually only one). + * @param[in] model The #LinphonePresenceModel object to get the activity from. + * @param[out] activity The returned #LinphonePresenceActivity (may not be changed in case of error). + * @param[out] description The description of the returned #LinphonePresenceActivity (may not be changed in case of error). + * @return 0 if successful, a value < 0 in case of error. + */ LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description); + +/** + * @brief 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 #LinphonePresenceActivity 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. + */ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description); + +/** + * @brief 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 a note that has no language specified or to get the first note whatever language it is written into. + * @return A pointer to dynamically allocated string in case of success, NULL otherwise. + * + * The string that is returned MUST be freed using ms_free(). + */ LINPHONE_PUBLIC const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); + +/** + * @brief 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); + +/** + * @brief 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); +/** + * @brief Gets the string representation of a presence activity. + * @param[in] activity The #LinphonePresenceActivity for which to get a string representation. + * @return A pointer to the string representing the given activity. + */ +LINPHONE_PUBLIC const char * linphone_presence_activity_to_string(LinphonePresenceActivity activity); + + +/** + * @} + */ + #ifdef __cplusplus } diff --git a/coreapi/presence.c b/coreapi/presence.c index 192dabb94..85fb2100f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -945,6 +945,14 @@ static const char * presence_activity_to_string(LinphonePresenceActivity activit return NULL; } +const char * linphone_presence_activity_to_string(LinphonePresenceActivity activity) { + if (activity == LinphonePresenceActivityOffline) + return "offline"; + if (activity == LinphonePresenceActivityOnline) + return "online"; + return presence_activity_to_string(activity); +} + static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr activities_nodes_object; @@ -1162,7 +1170,13 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){ MSList *elem; - ms_message("Notifying all friends"); + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + char *description = NULL; + linphone_presence_model_get_activity(presence, &activity, &description); + ms_message("Notifying all friends that we are [%s%s%s]", + linphone_presence_activity_to_string(activity), + (description == NULL) ? "" : ": ", + (description == NULL) ? "" : description); for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend *)elem->data; if (lf->insub){ @@ -1501,19 +1515,28 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; + LinphonePresenceModel *presence = (LinphonePresenceModel *)model; lf=linphone_find_friend_by_out_subscribe(lc->friends,op); if (lf!=NULL){ + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + char *description = NULL; friend=lf->uri; tmp=linphone_address_as_string(friend); - linphone_friend_set_presence(lf, (LinphonePresenceModel *)model); + linphone_presence_model_get_activity(presence, &activity, &description); + ms_message("We are notified that [%s] has presence [%s%s%s]", + tmp, + linphone_presence_activity_to_string(activity), + (description == NULL) ? "" : ": ", + (description == NULL) ? "" : description); + linphone_friend_set_presence_model(lf, presence); lf->subscribe_active=TRUE; if (lc->vtable.notify_presence_recv) lc->vtable.notify_presence_recv(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_delete((LinphonePresenceModel *)model); + linphone_presence_model_delete(presence); } if (ss==SalSubscribeTerminated){ sal_op_release(op); From 23ae9b1240d1107c437f6b7a73680f4c1a9cf19f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Jun 2013 17:28:53 +0200 Subject: [PATCH 466/909] fix potential invalid free due to record_file field of LinphoneCallParams not duplicated. --- coreapi/linphonecall.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e4d1bca6a..a51001b3f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -776,6 +776,7 @@ static void linphone_call_destroy(LinphoneCall *obj) ms_free(obj->auth_token); } linphone_call_params_uninit(&obj->params); + linphone_call_params_uninit(&obj->current_params); ms_free(obj); } @@ -811,8 +812,6 @@ void linphone_call_unref(LinphoneCall *obj){ * Returns current parameters associated to the call. **/ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ - if (call->params.record_file) - call->current_params.record_file=call->params.record_file; return &call->current_params; } @@ -1144,6 +1143,7 @@ const char *linphone_call_params_get_custom_header(const LinphoneCallParams *par } void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){ + if (ncp==cp) return; memcpy(ncp,cp,sizeof(LinphoneCallParams)); if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file); /* @@ -1608,8 +1608,10 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc); audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc)); - if (!call->params.in_conference && call->params.record_file) + if (!call->params.in_conference && call->params.record_file){ audio_stream_mixed_record_open(call->audiostream,call->params.record_file); + call->current_params.record_file=ms_strdup(call->params.record_file); + } audio_stream_start_full( call->audiostream, call->audio_profile, From 727a7229de6d774130193bb6a1b5cc8076f3f12f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Jun 2013 17:55:56 +0200 Subject: [PATCH 467/909] Use new API in presence tester. --- coreapi/presence.c | 1 + tester/liblinphone_tester.h | 41 +++++++++++----- tester/presence_tester.c | 95 ++++++++++++++++++++++++++++--------- 3 files changed, 103 insertions(+), 34 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 85fb2100f..a002d5c49 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -301,6 +301,7 @@ static int presence_model_set_basic_status(LinphonePresenceModel *model, Linphon if (ms_list_size(model->services) > 0) { ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); ms_list_free(model->services); + model->services = NULL; } id = generate_presence_id(); service = presence_service_new(id, basic_status); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 9e98850c7..391769030 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -122,18 +122,35 @@ typedef struct _stats { int number_of_NewSubscriptionRequest; int number_of_NotifyReceived; - int number_of_LinphoneStatusOffline; - int number_of_LinphoneStatusOnline; - int number_of_LinphoneStatusBusy; - int number_of_LinphoneStatusBeRightBack; - int number_of_LinphoneStatusAway; - int number_of_LinphoneStatusOnThePhone; - int number_of_LinphoneStatusOutToLunch; - int number_of_LinphoneStatusDoNotDisturb; - int number_of_LinphoneStatusMoved; - int number_of_LinphoneStatusAltService; - int number_of_LinphoneStatusPending; - int number_of_LinphoneStatusEnd; + 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; int number_of_inforeceived; int number_of_inforeceived_with_body; diff --git a/tester/presence_tester.c b/tester/presence_tester.c index c6919bbdf..bcef76879 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -43,33 +43,82 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { stats* counters; + LinphonePresenceModel* presence; + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; 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++; - switch(linphone_friend_get_status(lf)) { - case LinphoneStatusOffline: counters->number_of_LinphoneStatusOffline++; break; - case LinphoneStatusOnline: counters->number_of_LinphoneStatusOnline++; break; - case LinphoneStatusBusy: counters->number_of_LinphoneStatusBusy++; break; - case LinphoneStatusBeRightBack: counters->number_of_LinphoneStatusBeRightBack++; break; - case LinphoneStatusAway: counters->number_of_LinphoneStatusAway++; break; - case LinphoneStatusOnThePhone: counters->number_of_LinphoneStatusOnThePhone++; break; - case LinphoneStatusOutToLunch: counters->number_of_LinphoneStatusOutToLunch++; break; - case LinphoneStatusDoNotDisturb: counters->number_of_LinphoneStatusDoNotDisturb++; break; - case LinphoneStatusMoved: counters->number_of_LinphoneStatusMoved++; break; - case LinphoneStatusAltService: counters->number_of_LinphoneStatusMoved++; break; - case LinphoneStatusPending: counters->number_of_LinphoneStatusPending++; break; - case LinphoneStatusEnd: counters->number_of_LinphoneStatusEnd++; break; - default: - break; + presence = linphone_friend_get_presence_model(lf); + linphone_presence_model_get_activity(presence, &activity, NULL); + switch(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 simple_publish(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; int i=0; linphone_core_get_default_proxy(marie->lc,&proxy); linphone_proxy_config_edit(proxy); @@ -79,7 +128,9 @@ static void simple_publish(void) { linphone_core_iterate(marie->lc); ms_usleep(100000); } - linphone_core_set_presence_info(marie->lc,0,NULL,LinphoneStatusOffline); + presence = linphone_core_get_presence_model(marie->lc); + linphone_presence_model_set_activity(presence,LinphonePresenceActivityOffline,NULL); + linphone_core_set_presence_model(marie->lc,0,NULL,presence); for (i=0;i<10;i++) { linphone_core_iterate(marie->lc); ms_usleep(100000); @@ -101,8 +152,8 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph linphone_core_add_friend(caller_mgr->lc,friend); - result=wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneStatusOnline,initial_callee.number_of_LinphoneStatusOnline+1); - result&=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneStatusOnline,initial_caller.number_of_LinphoneStatusOnline+1); + result=wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_callee.number_of_LinphonePresenceActivityOnline+1); + result&=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_caller.number_of_LinphonePresenceActivityOnline+1); CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1); CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1); @@ -142,14 +193,14 @@ static void call_with_presence(void) { CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); CU_ASSERT_TRUE(call(marie,pauline)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneStatusOnThePhone,1); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneStatusOnThePhone,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphonePresenceActivityOnThePhone,1); reset_counters(&marie->stat); reset_counters(&pauline->stat); linphone_core_terminate_all_calls(marie->lc); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneStatusOnline,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneStatusOnline,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityOnline,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnline,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From 5acc4dd2ec1d46ebd6634519592c00a4856c6655 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Jun 2013 18:13:48 +0200 Subject: [PATCH 468/909] Fix some memory leaks. --- coreapi/bellesip_sal/sal_op_presence.c | 1 + coreapi/linphonecore.c | 2 ++ coreapi/presence.c | 1 + 3 files changed, 4 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 321f2e0ac..a818fd511 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -41,6 +41,7 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo ,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(contact_info); + ms_free(content); } static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 605521552..95d0e5d83 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5490,6 +5490,8 @@ static void linphone_core_uninit(LinphoneCore *lc) if (lc->friends) /* FIXME we should wait until subscription to complete*/ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); + if (lc->presence_model) + linphone_presence_model_delete(lc->presence_model); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED if (lc->previewstream!=NULL){ diff --git a/coreapi/presence.c b/coreapi/presence.c index a002d5c49..67bbe666f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -991,6 +991,7 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml } } } + if (activities_object != NULL) xmlXPathFreeObject(activities_object); if (err < 0) break; } } From e97420ed13186b01730f91f0dcfa1f6a3ae3fc3c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 20 Jun 2013 11:19:09 +0200 Subject: [PATCH 469/909] allow to reset the contact in reINVITE --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 95d0e5d83..42244b9c1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2887,7 +2887,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Modifying call parameters...")); sal_call_set_local_media_description (call->op,call->localdesc); - if (call->dest_proxy && call->dest_proxy->op && sal_op_get_contact(call->dest_proxy->op)){ + if (call->dest_proxy && call->dest_proxy->op){ /*give a chance to update the contact address if connectivity has changed*/ sal_op_set_contact(call->op,sal_op_get_contact(call->dest_proxy->op)); } From 3d1f4a1d8ca411bfbba3f0d733ec573e78344660 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 20 Jun 2013 11:36:58 +0200 Subject: [PATCH 470/909] allow contact address to be changed during call updates --- coreapi/linphonecore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 202519d76..34c849595 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2821,6 +2821,10 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Modifying call parameters...")); sal_call_set_local_media_description (call->op,call->localdesc); + if (call->dest_proxy && call->dest_proxy->op){ + /*give a chance to update the contact address if connectivity has changed*/ + sal_op_set_contact(call->op,sal_op_get_contact(call->dest_proxy->op)); + }else sal_op_set_contact(call->op,NULL); return sal_call_update(call->op,subject); } From f34aee7e4c87c6215f568fdbe32a74dad0529daa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Jun 2013 11:38:49 +0200 Subject: [PATCH 471/909] Add unit test for presence information. --- tester/liblinphone_tester.h | 1 + tester/presence_tester.c | 81 ++++++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 391769030..5d9b5b49c 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -151,6 +151,7 @@ typedef struct _stats { int number_of_LinphonePresenceActivityVacation; int number_of_LinphonePresenceActivityWorking; int number_of_LinphonePresenceActivityWorship; + LinphonePresenceModel *last_received_presence; int number_of_inforeceived; int number_of_inforeceived_with_body; diff --git a/tester/presence_tester.c b/tester/presence_tester.c index bcef76879..e7122659f 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -43,7 +43,6 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { stats* counters; - LinphonePresenceModel* presence; LinphonePresenceActivity activity = LinphonePresenceActivityOffline; char* from=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("New Notify request from [%s] ",from); @@ -51,8 +50,8 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { counters = get_stats(lc); counters->number_of_NotifyReceived++; - presence = linphone_friend_get_presence_model(lf); - linphone_presence_model_get_activity(presence, &activity, NULL); + counters->last_received_presence = linphone_friend_get_presence_model(lf); + linphone_presence_model_get_activity(counters->last_received_presence, &activity, NULL); switch(activity) { case LinphonePresenceActivityOffline: counters->number_of_LinphonePresenceActivityOffline++; break; @@ -115,26 +114,28 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { } } +static void wait_core(LinphoneCore *core) { + int i; + + for (i = 0; i < 10; i++) { + linphone_core_iterate(core); + ms_usleep(100000); + } +} + static void simple_publish(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneProxyConfig* proxy; LinphonePresenceModel* presence; - int i=0; + linphone_core_get_default_proxy(marie->lc,&proxy); linphone_proxy_config_edit(proxy); linphone_proxy_config_enable_publish(proxy,TRUE); linphone_proxy_config_done(proxy); - for (i=0;i<10;i++) { - linphone_core_iterate(marie->lc); - ms_usleep(100000); - } - presence = linphone_core_get_presence_model(marie->lc); - linphone_presence_model_set_activity(presence,LinphonePresenceActivityOffline,NULL); + wait_core(marie->lc); + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,NULL); linphone_core_set_presence_model(marie->lc,0,NULL,presence); - for (i=0;i<10;i++) { - linphone_core_iterate(marie->lc); - ms_usleep(100000); - } + wait_core(marie->lc); linphone_core_manager_destroy(marie); } @@ -205,11 +206,63 @@ static void call_with_presence(void) { linphone_core_manager_destroy(pauline); } +static void presence_information(void) { + const char *bike_description = "Riding my bike"; + const char *vacation_note = "I'm on vacation until July 4th"; + const char *vacation_lang = "en"; + LinphoneCoreManager *marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager *pauline = presence_linphone_core_manager_new("pauline"); + LinphonePresenceModel *presence; + LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + char *description = NULL; + char *note = NULL; + + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie, pauline)); + + /* Presence activity without description. */ + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityDinner, NULL); + linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); + wait_core(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1); + linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); + CU_ASSERT_EQUAL(activity, LinphonePresenceActivityDinner); + CU_ASSERT_PTR_NULL(description); + + /* Presence activity with description. */ + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivitySteering, bike_description); + linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); + wait_core(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1); + linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); + CU_ASSERT_EQUAL(activity, LinphonePresenceActivitySteering); + CU_ASSERT_PTR_NOT_NULL(description); + if (description != NULL) CU_ASSERT_EQUAL(strcmp(description, bike_description), 0); + + /* Presence activity with description and note. */ + presence = linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityVacation, NULL, vacation_note, vacation_lang); + linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); + wait_core(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1); + linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); + CU_ASSERT_EQUAL(activity, LinphonePresenceActivityVacation); + CU_ASSERT_PTR_NULL(description); + note = linphone_presence_model_get_note(marie->stat.last_received_presence, NULL); + CU_ASSERT_PTR_NOT_NULL(note); + if (note != NULL) { + CU_ASSERT_EQUAL(strcmp(note, vacation_note), 0); + ms_free(note); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t presence_tests[] = { { "Simple Subscribe", simple_subscribe }, { "Simple Publish", simple_publish }, { "Call with Presence", call_with_presence }, { "Unsubscribe while subscribing", unsubscribe_while_subscribing }, + { "Presence information", presence_information }, }; test_suite_t presence_test_suite = { From ad2e0b4753880ac8c77c7d0f5098eccd37a52f77 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Jun 2013 11:39:18 +0200 Subject: [PATCH 472/909] Fix some bugs revealed by unit tests in presence model. --- coreapi/linphonecore.c | 6 ++- coreapi/linphonepresence.h | 2 +- coreapi/presence.c | 83 +++++++++++++++++++++----------------- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 42244b9c1..c27090a73 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5457,6 +5457,10 @@ void ui_config_uninit(LinphoneCore* lc) ms_list_free(lc->friends); lc->friends=NULL; } + if (lc->presence_model) { + linphone_presence_model_delete(lc->presence_model); + lc->presence_model = NULL; + } } /** @@ -5490,8 +5494,6 @@ static void linphone_core_uninit(LinphoneCore *lc) if (lc->friends) /* FIXME we should wait until subscription to complete*/ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); - if (lc->presence_model) - linphone_presence_model_delete(lc->presence_model); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED if (lc->previewstream!=NULL){ diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 95281bafc..cae432afa 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -252,7 +252,7 @@ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel * * * The string that is returned MUST be freed using ms_free(). */ -LINPHONE_PUBLIC const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); +LINPHONE_PUBLIC char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); /** * @brief Adds a note to a presence model. diff --git a/coreapi/presence.c b/coreapi/presence.c index 67bbe666f..ddce8fc29 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -176,7 +176,7 @@ static void presence_service_delete(struct _LinphonePresenceService *service) { if (service->contact != NULL) { ms_free(service->contact); } - ms_list_for_each(service->notes, (MSIterateFunc)presence_service_delete); + ms_list_for_each(service->notes, (MSIterateFunc)presence_note_delete); ms_list_free(service->notes); ms_free(service); }; @@ -455,8 +455,8 @@ bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const Lin int nb; int i; - /* Two null activities are considered equal. */ - if ((m1 == NULL) && (m2 == NULL)) + /* If the two pointers are the same, the presence model are equals. */ + if (m1 == m2) return TRUE; /* A null activity is equal to an activity with no activity but a basic status of Closed. */ @@ -653,7 +653,7 @@ static void get_first_presence_service_note(struct _LinphonePresenceService *ser st->note = get_first_presence_note_in_list(service->notes); } -const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { +char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { struct _find_note_st st; if (model == NULL) return NULL; @@ -808,14 +808,14 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx const char *lang; int i; - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", service_prefix, service_idx); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx); note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]", service_prefix, service_idx, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i); note_str = get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]/@xml:lang", service_prefix, service_idx, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i); lang = get_xml_text_content(xml_ctx, xpath_str); note = presence_note_new(note_str, lang); @@ -1026,14 +1026,14 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, } if (note_object != NULL) xmlXPathFreeObject(note_object); - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", person_prefix, person_idx); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note", person_prefix, person_idx); note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]", person_prefix, person_idx, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]", person_prefix, person_idx, i); note_str = get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i); lang = get_xml_text_content(xml_ctx, xpath_str); note = presence_note_new(note_str, lang); @@ -1102,13 +1102,13 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho const char *lang; int i; - note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/rpid:note"); + note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { - snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/rpid:note[%i]", i); + snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]", i); note_str = get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; - snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/rpid:note[%i]/@xml:lang", i); + snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i); lang = get_xml_text_content(xml_ctx, xpath_str); note = presence_note_new(note_str, lang); @@ -1282,6 +1282,30 @@ struct _presence_note_obj_st { int *err; }; +static int write_xml_presence_note(xmlTextWriterPtr writer, struct _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(struct _LinphonePresenceNote *note, struct _presence_note_obj_st *st) { + int err = write_xml_presence_note(st->writer, note, st->ns); + if (err < 0) *st->err = err; +} + static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestamp) { int err; char *timestamp_str = timestamp_to_string(timestamp); @@ -1326,6 +1350,13 @@ static int write_xml_presence_service(xmlTextWriterPtr writer, struct _LinphoneP /* 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)); @@ -1356,30 +1387,6 @@ static void write_xml_presence_activity_obj(struct _LinphonePresenceActivity *ac if (err < 0) *st->err = err; } -static int write_xml_presence_note(xmlTextWriterPtr writer, struct _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(struct _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_person(xmlTextWriterPtr writer, struct _LinphonePresencePerson *person) { int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"dm", (const xmlChar *)"person", NULL); if (err >= 0) { @@ -1416,7 +1423,7 @@ static int write_xml_presence_person(xmlTextWriterPtr writer, struct _LinphonePr st.writer = writer; st.ns = "dm"; st.err = &err; - ms_list_for_each2(person->activities_notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + ms_list_for_each2(person->notes, (MSIterate2Func)write_xml_presence_note_obj, &st); } if (err >= 0) { write_xml_presence_timestamp(writer, person->timestamp); From a0f01705cedb4e38d3ec7887de8702b52842de28 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 20 Jun 2013 12:48:54 +0200 Subject: [PATCH 473/909] fix invalid test --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c27090a73..ebd674e41 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3834,7 +3834,7 @@ void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ ms_message("linphone_core_set_mic_gain_db(): no active call."); return; } - if (st->volrecv){ + if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply gain: gain control wasn't activated."); } From cc45df4858dec37c9c9c733bfedc83b825b85e5e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Jun 2013 17:12:01 +0200 Subject: [PATCH 474/909] Fix compilation for iOS. --- configure.ac | 10 +++++++++- share/Makefile.am | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5bbb5f645..b90833310 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,14 @@ AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) +case $host in + *-apple-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]) @@ -742,7 +750,7 @@ AC_SUBST(ORTP_LIBS) AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) -AC_ARG_ENABLE(tests_enabled, +AC_ARG_ENABLE(tests, [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], [case "${enableval}" in yes) tests_enabled=true ;; diff --git a/share/Makefile.am b/share/Makefile.am index 6f8fe9198..391bc7053 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -32,7 +32,7 @@ pkgconfig_DATA=linphone.pc linphonedir=$(datadir)/linphone linphone_DATA=rootca.pem rootca.pem: - $(top_srcdir)/scripts/mk-ca-bundle.pl rootca.pem + HTTPS_CA_DIR=$(HTTPS_CA_DIR) $(top_srcdir)/scripts/mk-ca-bundle.pl rootca.pem EXTRA_DIST = $(LINPHONE_SOUNDS) \ $(LINPHONE_RINGS) \ From 392b36c2429e268f291d22882ab195d46c70d5d5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 21 Jun 2013 11:28:43 +0200 Subject: [PATCH 475/909] libxml2 is now mandatory. --- build/android/common.mk | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index 67bcd336c..cffaa1e0c 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -92,7 +92,9 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../oRTP/include \ $(LOCAL_PATH)/../mediastreamer2/include \ $(LOCAL_PATH)/../../belle-sip/include \ - $(LOCAL_PATH)/../../../gen + $(LOCAL_PATH)/../../../gen \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 LOCAL_LDLIBS += -llog -ldl @@ -101,7 +103,8 @@ LOCAL_STATIC_LIBRARIES := \ libmediastreamer2 \ libortp \ libbellesip \ - libgsm + libgsm \ + liblpxml2 ifeq ($(BUILD_TUNNEL),1) @@ -209,12 +212,7 @@ LOCAL_SRC_FILES += ../tools/xml2lpc.c \ ../tools/xml2lpc_jni.cc \ ../tools/lpc2xml.c \ ../tools/lpc2xml_jni.cc -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 -LOCAL_STATIC_LIBRARIES += liblpxml2 - endif LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) From 301b7504f1f4f337725f568be5b9e04f0ddf884f Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 21 Jun 2013 11:31:49 +0200 Subject: [PATCH 476/909] Update ms2 (msdscap bug fix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 51d3c20b5..08e53b3ae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 51d3c20b5ac8c0c8ad4be8fc73d8fa4df195d017 +Subproject commit 08e53b3ae265c5927efc420ae68e16e500ac0500 From 1b7f68b4390ad1fec3026a7369f19dc3a68f4b86 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 21 Jun 2013 16:45:57 +0200 Subject: [PATCH 477/909] Change presence API a little bit to ease wrapping for other programming languages. --- coreapi/callbacks.c | 40 +++---- coreapi/friend.c | 110 +++++++++--------- coreapi/help/buddy_status.c | 11 +- coreapi/linphonecore.c | 40 +++---- coreapi/linphonepresence.h | 84 ++++++++++---- coreapi/presence.c | 223 +++++++++++++++++++++--------------- tester/presence_tester.c | 38 +++--- 7 files changed, 315 insertions(+), 231 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9820ae4de..bb0ae00ce 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -220,28 +220,26 @@ static void call_received(SalOp *h){ /* first check if we can answer successfully to this invite */ if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) { - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; - if (linphone_presence_model_get_activity(lc->presence_model, &activity, NULL)) { - switch (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: - if (lc->alt_contact != NULL) - sal_call_decline(h,SalReasonRedirect,lc->alt_contact); - break; - default: - break; - } - sal_op_release(h); - return; + 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: + if (lc->alt_contact != NULL) + sal_call_decline(h,SalReasonRedirect,lc->alt_contact); + break; + default: + break; } + sal_op_release(h); + return; } if (!linphone_core_can_we_add_call(lc)){/*busy*/ diff --git a/coreapi/friend.c b/coreapi/friend.c index e02078319..3e3181888 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -280,10 +280,8 @@ LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneF LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ LinphoneOnlineStatus online_status = LinphoneStatusOffline; LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed; - LinphonePresenceActivity activity = LinphonePresenceActivityUnknown; - char *activity_description = NULL; + LinphonePresenceActivity *activity = NULL; unsigned int nb_activities = 0; - int err = 0; if (lf->presence != NULL) { basic_status = linphone_presence_model_get_basic_status(lf->presence); @@ -298,60 +296,58 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ nb_activities = 1; } if (nb_activities == 1) { - err = linphone_presence_model_get_activity(lf->presence, &activity, &activity_description); - if (err == 0) { - switch (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: - case LinphonePresenceActivityOffline: - /* Should not happen! */ - ms_warning("LinphonePresenceActivityOnline or LinphonePresenceActivityOffline should not happen here!"); - break; - } + 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: + case LinphonePresenceActivityOffline: + /* Should not happen! */ + ms_warning("LinphonePresenceActivityOnline or LinphonePresenceActivityOffline should not happen here!"); + break; } } } diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 4f9db8ea7..4f1f64906 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -51,15 +51,12 @@ static void stop(int signum){ * presence state change notification callback */ static void notify_presence_recv_updated (LinphoneCore *lc, LinphoneFriend *friend) { - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; const LinphonePresenceModel* model = linphone_friend_get_presence_model(friend); const LinphoneAddress* friend_address = linphone_friend_get_address(friend); - char *description = NULL; - linphone_presence_model_get_activity(model, &activity, &description); - printf("New state state [%s%s%s] for user id [%s] \n" - ,linphone_presence_activity_to_string(activity) - ,(description == NULL) ? "" : ": " - ,(description == NULL) ? "" : description + 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" + ,activity_str ,linphone_address_as_string (friend_address)); } static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *friend, const char* url) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ebd674e41..3d391da99 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3645,52 +3645,52 @@ void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const char *contact, LinphoneOnlineStatus os) { LinphonePresenceModel *presence = NULL; char *description = NULL; - LinphonePresenceActivity activity = LinphonePresenceActivityUnknown; + LinphonePresenceActivityType acttype = LinphonePresenceActivityUnknown; switch (os) { case LinphoneStatusOffline: - activity = LinphonePresenceActivityOffline; + acttype = LinphonePresenceActivityOffline; break; case LinphoneStatusOnline: - activity = LinphonePresenceActivityOnline; + acttype = LinphonePresenceActivityOnline; break; case LinphoneStatusBusy: - activity = LinphonePresenceActivityBusy; + acttype = LinphonePresenceActivityBusy; break; case LinphoneStatusBeRightBack: - activity = LinphonePresenceActivityInTransit; + acttype = LinphonePresenceActivityInTransit; break; case LinphoneStatusAway: - activity = LinphonePresenceActivityAway; + acttype = LinphonePresenceActivityAway; break; case LinphoneStatusOnThePhone: - activity = LinphonePresenceActivityOnThePhone; + acttype = LinphonePresenceActivityOnThePhone; break; case LinphoneStatusOutToLunch: - activity = LinphonePresenceActivityLunch; + acttype = LinphonePresenceActivityLunch; break; case LinphoneStatusDoNotDisturb: - activity = LinphonePresenceActivityBusy; + acttype = LinphonePresenceActivityBusy; description = "Do not disturb"; break; case LinphoneStatusMoved: - activity = LinphonePresenceActivityPermanentAbsence; + acttype = LinphonePresenceActivityPermanentAbsence; break; case LinphoneStatusAltService: - activity = LinphonePresenceActivityBusy; + acttype = LinphonePresenceActivityBusy; description = "Using another messaging service"; break; case LinphoneStatusPending: - activity = LinphonePresenceActivityOther; + acttype = LinphonePresenceActivityOther; description = "Waiting for user acceptance"; break; case LinphoneStatusVacation: - activity = LinphonePresenceActivityVacation; + acttype = LinphonePresenceActivityVacation; break; case LinphoneStatusEnd: ms_warning("Invalid status LinphoneStatusEnd"); return; } - presence = linphone_presence_model_new_with_activity(activity, description); + presence = linphone_presence_model_new_with_activity(acttype, description); linphone_core_set_presence_model(lc, minutes_away, contact, presence); } @@ -3718,14 +3718,12 @@ void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const } LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){ - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; - char *description = NULL; + LinphonePresenceActivity *activity = NULL; + const char *description = NULL; - if ((lc->presence_model == NULL) - || (linphone_presence_model_get_activity(lc->presence_model, &activity, &description) < 0)) - return LinphoneStatusOffline; - - switch (activity) { + 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: diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index cae432afa..c743454d0 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -138,7 +138,7 @@ typedef enum LinphonePresenceActivity { /** The person is participating in religious rites. */ LinphonePresenceActivityWorship -} LinphonePresenceActivity; +} LinphonePresenceActivityType; /** * Structure holding the information about the presence of a person. @@ -150,6 +150,26 @@ struct _LinphonePresenceModel; */ typedef struct _LinphonePresenceModel LinphonePresenceModel; +/** + * 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; + /** @@ -172,7 +192,7 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); * * The created presence model has the activity specified in the parameters. */ -LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivityType activity, const char *description); /** * @brief Creates a presence model specifying an activity and adding a note. @@ -186,7 +206,7 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activit * * 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(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType activity, const char *description, const char *note, const char *lang); /** * @brief Deletes a presence model. @@ -220,39 +240,33 @@ LINPHONE_PUBLIC unsigned int linphone_presence_model_nb_activities(const Linphon * @brief 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). - * @param[out] activity The returned #LinphonePresenceActivity (may not be changed in case of error). - * @param[out] description The description of the returned #LinphonePresenceActivity (may not be changed in case of error). - * @return 0 if successful, a value < 0 in case of error. + * @return A pointer to a #LinphonePresenceActivity object if successful, NULL otherwise. */ -LINPHONE_PUBLIC int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description); +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx); /** * @brief Gets the first activity of a presence model (there is usually only one). * @param[in] model The #LinphonePresenceModel object to get the activity from. - * @param[out] activity The returned #LinphonePresenceActivity (may not be changed in case of error). - * @param[out] description The description of the returned #LinphonePresenceActivity (may not be changed in case of error). - * @return 0 if successful, a value < 0 in case of error. + * @return A #LinphonePresenceActivity object if successful, NULL otherwise. */ -LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description); +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model); /** * @brief 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 #LinphonePresenceActivity to set for the model. + * @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. */ -LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description); +LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); /** * @brief 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 a note that has no language specified or to get the first note whatever language it is written into. - * @return A pointer to dynamically allocated string in case of success, NULL otherwise. - * - * The string that is returned MUST be freed using ms_free(). + * @return A pointer to a #LinphonePresenceNote object if successful, NULL otherwise. */ -LINPHONE_PUBLIC char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); /** * @brief Adds a note to a presence model. @@ -274,10 +288,40 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_notes(LinphonePresenceModel *m /** * @brief Gets the string representation of a presence activity. - * @param[in] activity The #LinphonePresenceActivity for which to get a string representation. - * @return A pointer to the string representing the given 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 const char * linphone_presence_activity_to_string(LinphonePresenceActivity activity); +LINPHONE_PUBLIC char * linphone_presence_activity_to_string(const LinphonePresenceActivity * activity); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); /** diff --git a/coreapi/presence.c b/coreapi/presence.c index ddce8fc29..7758ba91d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -48,7 +48,7 @@ struct _LinphonePresenceService { }; struct _LinphonePresenceActivity { - LinphonePresenceActivity activity; + LinphonePresenceActivityType type; char *description; }; @@ -193,9 +193,9 @@ static void presence_service_add_note(struct _LinphonePresenceService *service, service->notes = ms_list_append(service->notes, note); } -static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivity activity, const char *description) { +static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1); - act->activity = activity; + act->type = acttype; if (description != NULL) { act->description = ms_strdup(description); } @@ -315,15 +315,11 @@ static void presence_model_clear_activities(LinphonePresenceModel *model) { ms_list_for_each(model->persons, (MSIterateFunc)presence_person_clear_activities); } -static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description) { +static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { char *id = NULL; struct _LinphonePresencePerson *person = NULL; struct _LinphonePresenceActivity *act = NULL; - /* Do not add activity for special cases Offline and Online. */ - if ((activity == LinphonePresenceActivityOffline) || (activity == LinphonePresenceActivityOnline)) - return 0; - if (ms_list_size(model->persons) == 0) { /* There is no person in the presence model, add one. */ id = generate_presence_id(); @@ -336,7 +332,7 @@ static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePre /* Add the activity to the first person in the model. */ person = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); } - act = presence_activity_new(activity, description); + act = presence_activity_new(acttype, description); if (act == NULL) return -1; presence_person_add_activity(person, act); @@ -376,7 +372,7 @@ static bool_t presence_activity_equals(const struct _LinphonePresenceActivity *a || ((a1->description != NULL) && (a2->description == NULL))) return FALSE; - if (a1->activity != a2->activity) + if (a1->type != a2->type) return FALSE; if ((a1->description != NULL) && (a2->description != NULL)) { @@ -421,18 +417,18 @@ LinphonePresenceModel * linphone_presence_model_new(void) { return ms_new0(LinphonePresenceModel, 1); } -LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description) { +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, activity, description); + linphone_presence_model_set_activity(model, acttype, description); } return model; } -LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang) { +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, activity, description); + linphone_presence_model_set_activity(model, acttype, description); linphone_presence_model_add_note(model, note, lang); } return model; @@ -451,7 +447,7 @@ void linphone_presence_model_delete(LinphonePresenceModel *model) { } bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2) { - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + LinphonePresenceActivity *activity = NULL; int nb; int i; @@ -461,14 +457,14 @@ bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const Lin /* A null activity is equal to an activity with no activity but a basic status of Closed. */ if (m1 == NULL) { - if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0) - || (activity != LinphonePresenceActivityOffline)) + activity = linphone_presence_model_get_activity(m2); + if (linphone_presence_activity_get_type(activity) != LinphonePresenceActivityOffline) return FALSE; return TRUE; } if (m2 == NULL) { - if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0) - || (activity != LinphonePresenceActivityOffline)) + activity = linphone_presence_model_get_activity(m2); + if (linphone_presence_activity_get_type(activity) != LinphonePresenceActivityOffline) return FALSE; return TRUE; } @@ -521,64 +517,41 @@ unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel * struct _get_activity_st { unsigned int requested_idx; unsigned int current_idx; - LinphonePresenceActivity *activity; - char **description; + struct _LinphonePresenceActivity *activity; }; static void presence_model_get_activity(const struct _LinphonePresencePerson *person, struct _get_activity_st *st) { - struct _LinphonePresenceActivity *activity; unsigned int size = ms_list_size(person->activities); if (st->requested_idx < (st->current_idx + size)) { - activity = (struct _LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); - *st->activity = activity->activity; - if (st->description != NULL) { - *st->description = activity->description; - } + st->activity = (struct _LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); } else { st->current_idx += size; } } -int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) { +LinphonePresenceActivity * linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx) { struct _get_activity_st st; - if ((model == NULL) || (activity == NULL) || (idx >= linphone_presence_model_nb_activities(model))) - return -1; + if ((model == NULL) || (idx >= linphone_presence_model_nb_activities(model))) + return NULL; memset(&st, 0, sizeof(st)); st.requested_idx = idx; - st.activity = activity; - *st.activity = LinphonePresenceActivityUnknown; - if (description != NULL) { - st.description = description; - } ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st); - return 0; + return st.activity; } -int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description) { - if ((model == NULL) || (activity == NULL)) - return -1; - - if (linphone_presence_model_get_nth_activity(model, 0, activity, description) < 0) { - /* There is no activities, base the result on the basic status. */ - LinphonePresenceBasicStatus basic_status = linphone_presence_model_get_basic_status(model); - if (basic_status == LinphonePresenceBasicStatusOpen) - *activity = LinphonePresenceActivityOnline; - else - *activity = LinphonePresenceActivityOffline; - } - - return 0; +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, LinphonePresenceActivity activity, const char *description) { +int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen; if (model == NULL) return -1; - switch (activity) { + switch (acttype) { case LinphonePresenceActivityAppointment: case LinphonePresenceActivityBusy: case LinphonePresenceActivityMeeting: @@ -594,7 +567,7 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP if (presence_model_set_basic_status(model, basic_status) < 0) return -1; presence_model_clear_activities(model); - if (presence_model_add_activity(model, activity, description) < 0) + if (presence_model_add_activity(model, acttype, description) < 0) return -1; return 0; @@ -653,7 +626,7 @@ static void get_first_presence_service_note(struct _LinphonePresenceService *ser st->note = get_first_presence_note_in_list(service->notes); } -char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { +LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { struct _find_note_st st; if (model == NULL) return NULL; @@ -694,10 +667,7 @@ char * linphone_presence_model_get_note(const LinphonePresenceModel *model, cons } } - if (st.note == NULL) - return NULL; - - return ms_strdup(st.note->content); + return st.note; } int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) { @@ -892,7 +862,7 @@ static const char *person_prefix = "/pidf:presence/dm:person"; struct _presence_activity_name_map { const char *name; - LinphonePresenceActivity activity; + LinphonePresenceActivityType type; }; static struct _presence_activity_name_map activity_map[] = { @@ -925,35 +895,67 @@ static struct _presence_activity_name_map activity_map[] = { { "worship", LinphonePresenceActivityWorship } }; -static int activity_name_to_linphone_presence_activity(const char *name, LinphonePresenceActivity *activity) { +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) { - *activity = activity_map[i].activity; + *acttype = activity_map[i].type; return 0; } } return -1; } -static const char * presence_activity_to_string(LinphonePresenceActivity activity) { +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 (activity == activity_map[i].activity) { + if (acttype == activity_map[i].type) { return activity_map[i].name; } } return NULL; } -const char * linphone_presence_activity_to_string(LinphonePresenceActivity activity) { - if (activity == LinphonePresenceActivityOffline) - return "offline"; - if (activity == LinphonePresenceActivityOnline) - return "online"; - return presence_activity_to_string(activity); +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", acttype_str, (description == NULL) ? "" : description); } +LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity) { + if (activity == NULL) + return LinphonePresenceActivityOffline; + return activity->type; +} + +const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity) { + if (activity == NULL) + return NULL; + return activity->description; +} + +const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->content; +} + +const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->lang; +} + + static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr activities_nodes_object; @@ -977,15 +979,15 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml && (activity_node->ns != NULL) && (activity_node->ns->prefix != NULL) && (strcmp((const char *)activity_node->ns->prefix, "rpid") == 0)) { - LinphonePresenceActivity linphone_activity; + LinphonePresenceActivityType acttype; description = (const char *)xmlNodeGetContent(activity_node); if ((description != NULL) && (description[0] == '\0')) { free_xml_text_content(description); description = NULL; } - err = activity_name_to_linphone_presence_activity((const char *)activity_node->name, &linphone_activity); + err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); if (err < 0) break; - activity = presence_activity_new(linphone_activity, description); + activity = presence_activity_new(acttype, description); presence_person_add_activity(person, activity); if (description != NULL) free_xml_text_content(description); } @@ -1172,13 +1174,10 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){ MSList *elem; - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; - char *description = NULL; - linphone_presence_model_get_activity(presence, &activity, &description); - ms_message("Notifying all friends that we are [%s%s%s]", - linphone_presence_activity_to_string(activity), - (description == NULL) ? "" : ": ", - (description == NULL) ? "" : description); + 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){ @@ -1257,6 +1256,26 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c 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; + } + presence_model_add_activity(model, acttype, NULL); + } + } + *result = (SalPresenceModel *)model; } @@ -1370,9 +1389,19 @@ static int write_xml_presence_service(xmlTextWriterPtr writer, struct _LinphoneP return err; } +static bool_t is_valid_activity(struct _LinphonePresenceActivity *activity) { + if ((activity->type == LinphonePresenceActivityOffline) || (activity->type == LinphonePresenceActivityOnline)) + return FALSE; + return TRUE; +} + static int write_xml_presence_activity(xmlTextWriterPtr writer, struct _LinphonePresenceActivity *activity) { - int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid", - (const xmlChar *)presence_activity_to_string(activity->activity), NULL); + 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); } @@ -1387,8 +1416,22 @@ static void write_xml_presence_activity_obj(struct _LinphonePresenceActivity *ac if (err < 0) *st->err = err; } +static void person_has_valid_activity(struct _LinphonePresenceActivity *activity, bool_t *has_valid_activities) { + if (is_valid_activity(activity) == TRUE) *has_valid_activities = TRUE; +} + +static bool_t person_has_valid_activities(struct _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, struct _LinphonePresencePerson *person) { - int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"dm", (const xmlChar *)"person", NULL); + 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(); @@ -1398,7 +1441,7 @@ static int write_xml_presence_person(xmlTextWriterPtr writer, struct _LinphonePr err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)person->id); } } - if ((err >= 0) && ((person->activities_notes != NULL) || (person->activities != NULL))) { + 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; @@ -1528,16 +1571,14 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa lf=linphone_find_friend_by_out_subscribe(lc->friends,op); if (lf!=NULL){ - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; - char *description = NULL; + LinphonePresenceActivity *activity = NULL; + char *activity_str; friend=lf->uri; tmp=linphone_address_as_string(friend); - linphone_presence_model_get_activity(presence, &activity, &description); - ms_message("We are notified that [%s] has presence [%s%s%s]", - tmp, - linphone_presence_activity_to_string(activity), - (description == NULL) ? "" : ": ", - (description == NULL) ? "" : description); + 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); linphone_friend_set_presence_model(lf, presence); lf->subscribe_active=TRUE; if (lc->vtable.notify_presence_recv) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index e7122659f..1363c4045 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -43,7 +43,7 @@ void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char * void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { stats* counters; - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; + 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); @@ -51,8 +51,8 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { counters->number_of_NotifyReceived++; counters->last_received_presence = linphone_friend_get_presence_model(lf); - linphone_presence_model_get_activity(counters->last_received_presence, &activity, NULL); - switch(activity) { + 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: @@ -213,9 +213,10 @@ static void presence_information(void) { LinphoneCoreManager *marie = presence_linphone_core_manager_new("marie"); LinphoneCoreManager *pauline = presence_linphone_core_manager_new("pauline"); LinphonePresenceModel *presence; - LinphonePresenceActivity activity = LinphonePresenceActivityOffline; - char *description = NULL; - char *note = NULL; + LinphonePresenceActivity *activity = NULL; + LinphonePresenceNote *note = NULL; + const char *description = NULL; + const char *note_content = NULL; CU_ASSERT_TRUE(subscribe_to_callee_presence(marie, pauline)); @@ -224,8 +225,10 @@ static void presence_information(void) { linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1); - linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); - CU_ASSERT_EQUAL(activity, LinphonePresenceActivityDinner); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityDinner); + description = linphone_presence_activity_get_description(activity); CU_ASSERT_PTR_NULL(description); /* Presence activity with description. */ @@ -233,8 +236,10 @@ static void presence_information(void) { linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1); - linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); - CU_ASSERT_EQUAL(activity, LinphonePresenceActivitySteering); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivitySteering); + description = linphone_presence_activity_get_description(activity); CU_ASSERT_PTR_NOT_NULL(description); if (description != NULL) CU_ASSERT_EQUAL(strcmp(description, bike_description), 0); @@ -243,14 +248,19 @@ static void presence_information(void) { linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1); - linphone_presence_model_get_activity(marie->stat.last_received_presence, &activity, &description); - CU_ASSERT_EQUAL(activity, LinphonePresenceActivityVacation); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityVacation); + description = linphone_presence_activity_get_description(activity); CU_ASSERT_PTR_NULL(description); note = linphone_presence_model_get_note(marie->stat.last_received_presence, NULL); CU_ASSERT_PTR_NOT_NULL(note); if (note != NULL) { - CU_ASSERT_EQUAL(strcmp(note, vacation_note), 0); - ms_free(note); + note_content = linphone_presence_note_get_content(note); + CU_ASSERT_PTR_NOT_NULL(note_content); + if (note_content != NULL) { + CU_ASSERT_EQUAL(strcmp(note_content, vacation_note), 0); + } } linphone_core_manager_destroy(marie); From 77681fa4bb5d1ff4574e7e9dc6e12ede46802e92 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 11:52:12 +0200 Subject: [PATCH 478/909] Remove explicit reference to rpid namespace that may be named differently. --- coreapi/presence.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 7758ba91d..5ab52b44f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -955,6 +955,15 @@ const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) { return note->lang; } +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, struct _LinphonePresencePerson *person, unsigned int person_idx) { char xpath_str[MAX_XPATH_LENGTH]; @@ -970,15 +979,12 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) { for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) { - snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/*", person_prefix, person_idx, i); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/rpid:*", person_prefix, person_idx, i); activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { activity_node = activities_object->nodesetval->nodeTab[j]; - if ((activity_node->name != NULL) - && (activity_node->ns != NULL) - && (activity_node->ns->prefix != NULL) - && (strcmp((const char *)activity_node->ns->prefix, "rpid") == 0)) { + 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')) { From ec1875a094ca8699ac4f29bca0c3009de83fa34c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 24 Jun 2013 11:53:32 +0200 Subject: [PATCH 479/909] update MS2 for 32bits video on macosx --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 08e53b3ae..94b4434c3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 08e53b3ae265c5927efc420ae68e16e500ac0500 +Subproject commit 94b4434c34d1ae9de5438b9cfa614ee1821eb709 From 96ea72f762f093e76ae30eb8b9843b8b6b6586ba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 11:57:25 +0200 Subject: [PATCH 480/909] Improve status log. --- coreapi/presence.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 5ab52b44f..0d244b28d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -928,7 +928,9 @@ char * linphone_presence_activity_to_string(const LinphonePresenceActivity *acti else acttype_str = presence_activity_type_to_string(acttype); - return ms_strdup_printf("%s: %s", acttype_str, (description == NULL) ? "" : description); + return ms_strdup_printf("%s%s%s", acttype_str, + (description == NULL) ? "" : ": ", + (description == NULL) ? "" : description); } LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity) { From 866af779abc0b74a53f3237d42d6db07e4426cc0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 24 Jun 2013 12:14:54 +0200 Subject: [PATCH 481/909] handle out of dialogs incoming NOTIFY. Use in [sip]: allow_out_of_subscribe_presence=1 to allow them for presence (unsecure) --- coreapi/bellesip_sal/sal_impl.c | 11 ++- coreapi/bellesip_sal/sal_op_events.c | 49 ++++++---- coreapi/bellesip_sal/sal_op_presence.c | 125 ++++++++++++++----------- coreapi/friend.c | 9 +- coreapi/presence.c | 11 ++- coreapi/private.h | 3 +- 6 files changed, 124 insertions(+), 84 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index cf46d4f74..2ff7041e6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -175,31 +175,32 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_header_to_t* to; belle_sip_response_t* resp; belle_sip_header_t *evh; + const char *method=belle_sip_request_get_method(req); from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); - } else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { + }else if (strcmp("INVITE",method)==0) { op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); - } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0 && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { + }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*)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",belle_sip_request_get_method(req))==0) { + }else if (strcmp("MESSAGE",method)==0) { op=sal_op_new((Sal*)sal); op->dir=SalOpDirIncoming; sal_op_message_fill_cbs(op); - } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { + }else if (strcmp("OPTIONS",method)==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; - }else if (strcmp("INFO",belle_sip_request_get_method(req))==0) { + }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*)sal)->prov,resp); return; diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 952c58a6a..a1a88fec8 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -64,7 +64,7 @@ static void subscribe_response_event(void *op_base, const belle_sip_response_eve } set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); if (!op->dialog) { - ms_message("subscribe op [%p] receive out of dialog answer [%i]",op,code); + ms_message("subscribe op [%p] received out of dialog answer [%i]",op,code); return; } dialog_state=belle_sip_dialog_get_state(op->dialog); @@ -112,18 +112,34 @@ static void subscribe_process_transaction_terminated(void *user_ctx, const belle ms_message("subscribe_process_transaction_terminated not implemented yet"); } +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; + + 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); +} + 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_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); 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; - SalSubscribeStatus sub_state; 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); @@ -141,10 +157,15 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque } if (!op->dialog) { - 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)); + 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) { @@ -158,17 +179,9 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque break; case BELLE_SIP_DIALOG_CONFIRMED: - if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { - 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; - - 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); - } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { + 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) { diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index a818fd511..62acc81aa 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -142,77 +142,94 @@ static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_req return result; } +static void handle_notify(SalOp *op, belle_sip_request_t *req){ + belle_sip_response_t* resp; + belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + SalSubscribeStatus sub_state; + + if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + SalPresenceModel *presence_model = NULL; + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + if (body==NULL){ + ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); + resp = sal_op_create_response_from_request(op, req, 415); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; + } + presence_model = process_presence_notification(op, req); + if (presence_model != NULL) { + /* Presence notification body parsed successfully. */ + if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { + sub_state=SalSubscribeTerminated; + ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + } else { + sub_state=SalSubscribeActive; + } + op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); + resp = sal_op_create_response_from_request(op, req, 200); + } else { + /* Formatting error in presence notification body. */ + ms_error("Wrongly formatted presence notification received"); + resp = sal_op_create_response_from_request(op, req, 400); + } + belle_sip_server_transaction_send_response(server_transaction,resp); + } +} + static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; - belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); - const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - SalPresenceModel *presence_model = NULL; - SalSubscribeStatus sub_state; 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) { - 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)); + 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 ",belle_sip_request_get_method(req),op->dialog); - break; - - case BELLE_SIP_DIALOG_CONFIRMED: - if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { - if (body==NULL){ - ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); - return; - } - presence_model = process_presence_notification(op, req); - if (presence_model != NULL) { - /* Presence notification body parsed successfully. */ - if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { - sub_state=SalSubscribeTerminated; - ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); - } else { - sub_state=SalSubscribeActive; - } - op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); - resp = sal_op_create_response_from_request(op, req, 200); - } else { - /* Formatting error in presence notification body. */ - ms_error("Wrongly formatted presence notification received"); - resp = sal_op_create_response_from_request(op, req, 400); - } - belle_sip_server_transaction_send_response(server_transaction,resp); - } else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) { - /*either a refresh of 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); - } + case BELLE_SIP_DIALOG_NULL: { + op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); + break; } - break; - default: { - ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - } - /* no 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; } } diff --git a/coreapi/friend.c b/coreapi/friend.c index 3e3181888..38800f05d 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -73,16 +73,16 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ static int friend_compare(const void * a, const void * b){ LinphoneAddress *fa=((LinphoneFriend*)a)->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_addr(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; @@ -99,8 +99,9 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){ MSList *elem; + LinphoneFriend *lf; for (elem=l;elem!=NULL;elem=elem->next){ - LinphoneFriend *lf=(LinphoneFriend*)elem->data; + lf=(LinphoneFriend*)elem->data; if (lf->outsub==op) return lf; } return NULL; diff --git a/coreapi/presence.c b/coreapi/presence.c index 0d244b28d..6148e3929 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +#include "lpconfig.h" + #include #include #include @@ -1216,14 +1218,14 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ } /* check if we answer to this subscription */ - if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ + if (linphone_find_friend_by_addr(lc->friends,uri,&lf)!=NULL){ lf->insub=op; lf->inc_subscribe_pending=TRUE; sal_subscribe_accept(op); linphone_friend_done(lf); /*this will do all necessary actions */ }else{ /* check if this subscriber is in our black list */ - if (linphone_find_friend(lc->subscribers,uri,&lf)){ + if (linphone_find_friend_by_addr(lc->subscribers,uri,&lf)){ if (lf->pol==LinphoneSPDeny){ ms_message("Rejecting %s because we already rejected it once.",from); sal_subscribe_decline(op,SalReasonDeclined); @@ -1578,6 +1580,11 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa LinphonePresenceModel *presence = (LinphonePresenceModel *)model; 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_addr(lc->friends,(LinphoneAddress*)addr,&lf); + } if (lf!=NULL){ LinphonePresenceActivity *activity = NULL; char *activity_str; diff --git a/coreapi/private.h b/coreapi/private.h index e85c169fc..d83ab161a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -248,6 +248,7 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf); void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); +MSList *linphone_find_friend_by_addr(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen); int set_lock_file(); @@ -297,7 +298,7 @@ void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalO 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); +MSList *linphone_find_friend_by_addr(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); From 6e8e0094c4759c6b8e6008d0645f46c12d7bea1c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 24 Jun 2013 12:35:06 +0200 Subject: [PATCH 482/909] fix Adroid compilation issue --- coreapi/linphonecore_jni.cc | 8 -------- java/impl/org/linphone/core/LinphoneAddressImpl.java | 1 - 2 files changed, 9 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 44f0e7acb..2a8d4d1cd 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1539,14 +1539,6 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* return NULL; } } -extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* env - ,jobject thiz - ,jlong ptr - ,jstring jdomain) { - const char* domain = env->GetStringUTFChars(jdomain, NULL); - linphone_address_set_domain((LinphoneAddress*)ptr, domain); - env->ReleaseStringUTFChars(jdomain, domain); -} extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index bbaa60be0..54e7a408e 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -33,7 +33,6 @@ public class LinphoneAddressImpl implements LinphoneAddress { private native void setDomain(long ptr,String domain); private native void setUserName(long ptr,String username); private native String toString(long ptr); - private native void setDomain(long ptr, String domain); protected LinphoneAddressImpl(String identity) throws LinphoneCoreException{ nativePtr = newLinphoneAddressImpl(identity, null); From 14373bcb041acb04f8428acbcc397e0c0b15973b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 12:50:25 +0200 Subject: [PATCH 483/909] Prevent crash when adding a friend without entering a SIP URI. --- coreapi/friend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 38800f05d..32da85edb 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -179,7 +179,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); From 04f3c8af733d964c38b4a79aba6252e734aa1386 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 12:55:49 +0200 Subject: [PATCH 484/909] Fix typos. --- coreapi/linphonefriend.h | 2 +- coreapi/linphonepresence.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index b4ee2e801..3f1680c63 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -217,7 +217,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); /** * @brief Get the presence information of a friend * @param[in] lf A #LinphoneFriend object - * @return A #LinphonePresenceModel object, or NULL if the friend to not have presence information (in which he is considered offline) + * @return A #LinphonePresenceModel object, or NULL if the friend do not have presence information (in which case he is considered offline) */ LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index c743454d0..924df2008 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -42,7 +42,7 @@ typedef enum LinphonePresenceBasicStatus { } LinphonePresenceBasicStatus; /** Activities as defined in section 3.2 of RFC 4480 */ -typedef enum LinphonePresenceActivity { +typedef enum LinphonePresenceActivityType { /** This value is not defined in the RFC, it corresponds to no activity with a basic status of "closed". */ LinphonePresenceActivityOffline, @@ -263,7 +263,7 @@ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel * /** * @brief 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 a note that has no language specified or to get the first note whatever language it is written into. + * @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); From 48140cefd017024a0f78bb16061c28e8974d9ecb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 24 Jun 2013 16:27:25 +0200 Subject: [PATCH 485/909] remove unwanted quotes from LinphoenMessage external body url --- coreapi/bellesip_sal/sal_op_message.c | 9 ++++++++- tester/message_tester.c | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 140dbe85f..17a038080 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -108,12 +108,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; - salmsg.url=external_body?belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"):NULL; + salmsg.url=NULL; + if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { + size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); + char* url = ms_malloc(url_length); + if (sscanf(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"),"\"%s\"",url) ==1) + salmsg.url=url; + } salmsg.message_id=message_id; salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); op->base.root->callbacks.text_received(op,&salmsg); belle_sip_object_unref(address); belle_sip_free(from); + if (salmsg.url) ms_free((char*)salmsg.url); response_code=200; } else { ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) diff --git a/tester/message_tester.c b/tester/message_tester.c index 33536ff7f..8e543de38 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -164,9 +164,10 @@ static void text_message_with_external_body(void) { linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); - + /*fixme use history to check message content*/ linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From 5f1e8dd03ddce0bfe437016f86342b038ab9f5fe Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 14:53:49 +0200 Subject: [PATCH 486/909] Add JNI for presence. --- coreapi/linphonecore_jni.cc | 258 +++++++++++++++++- coreapi/linphonepresence.h | 84 ++++++ coreapi/presence.c | 73 +++++ .../org/linphone/core/LinphoneCore.java | 26 +- .../org/linphone/core/LinphoneFriend.java | 15 +- .../org/linphone/core/OnlineStatus.java | 2 +- .../org/linphone/core/PresenceActivity.java | 42 +++ .../linphone/core/PresenceActivityType.java | 137 ++++++++++ .../org/linphone/core/PresenceModel.java | 109 ++++++++ .../org/linphone/core/PresenceNote.java | 36 +++ .../org/linphone/core/LinphoneCoreImpl.java | 19 +- .../org/linphone/core/LinphoneFriendImpl.java | 8 + .../linphone/core/PresenceActivityImpl.java | 51 ++++ .../org/linphone/core/PresenceModelImpl.java | 85 ++++++ .../org/linphone/core/PresenceNoteImpl.java | 45 +++ 15 files changed, 978 insertions(+), 12 deletions(-) create mode 100644 java/common/org/linphone/core/PresenceActivity.java create mode 100644 java/common/org/linphone/core/PresenceActivityType.java create mode 100644 java/common/org/linphone/core/PresenceModel.java create mode 100644 java/common/org/linphone/core/PresenceNote.java create mode 100644 java/impl/org/linphone/core/PresenceActivityImpl.java create mode 100644 java/impl/org/linphone/core/PresenceModelImpl.java create mode 100644 java/impl/org/linphone/core/PresenceNoteImpl.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 2a8d4d1cd..bf3045de8 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -50,6 +50,27 @@ extern "C" void libmsbcg729_init(); #endif #endif /*ANDROID*/ + + +#define RETURN_USER_DATA_OBJECT(javaclass, funcprefix, cobj) \ + { \ + jclass jUserDataObjectClass; \ + jmethodID jUserDataObjectCtor; \ + jobject jUserDataObj; \ + jUserDataObj = (jobject)funcprefix ## _get_user_data(cobj); \ + if (jUserDataObj == NULL) { \ + jUserDataObjectClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/" javaclass)); \ + jUserDataObjectCtor = env->GetMethodID(jUserDataObjectClass,"", "(J)V"); \ + jUserDataObj = env->NewObject(jUserDataObjectClass, jUserDataObjectCtor, (jlong)funcprefix ## _ref(cobj)); \ + jUserDataObj = env->NewGlobalRef(jUserDataObj); \ + funcprefix ## _set_user_data(cobj, jUserDataObj); \ + env->DeleteGlobalRef(jUserDataObjectClass); \ + } \ + return jUserDataObj; \ + } + + + static JavaVM *jvm=0; static const char* LogDomain = "Linphone"; static jclass handler_class; @@ -1062,13 +1083,41 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv* env ,jobject thiz ,jlong lc - ,jint minute_away + ,jint minutes_away ,jstring jalternative_contact ,jint status) { const char* alternative_contact = jalternative_contact?env->GetStringUTFChars(jalternative_contact, NULL):NULL; - linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,(LinphoneOnlineStatus)status); + linphone_core_set_presence_info((LinphoneCore*)lc,minutes_away,alternative_contact,(LinphoneOnlineStatus)status); if (alternative_contact) env->ReleaseStringUTFChars(jalternative_contact, alternative_contact); } +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPresenceInfo(JNIEnv *env, jobject thiz, jlong lc) { + return (jint)linphone_core_get_presence_info((LinphoneCore *)lc); +} + +/* + * 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, jint minutes_away, jstring jalternative_contact, jlong modelPtr) { + LinphoneCore *lc = (LinphoneCore *)ptr; + const char *calternative_contact = jalternative_contact ? env->GetStringUTFChars(jalternative_contact, NULL) : NULL; + LinphonePresenceModel *model = (LinphonePresenceModel *)modelPtr; + linphone_core_set_presence_model(lc, minutes_away, calternative_contact, model); + if (calternative_contact) env->ReleaseStringUTFChars(jalternative_contact, calternative_contact); +} + +/* + * 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_createChatRoom(JNIEnv* env ,jobject thiz @@ -1952,6 +2001,30 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env ,jlong ptr) { return (jint)linphone_friend_get_status((LinphoneFriend*)ptr); } + +/* + * Class: org_linphone_core_LinphoneFriendImpl + * Method: getPresenceModel + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneFriendImpl_getPresenceModel(JNIEnv *env, jobject jobj, jlong ptr) { + LinphoneFriend *lf = (LinphoneFriend *)ptr; + LinphonePresenceModel *model = linphone_friend_get_presence_model(lf); + if (model == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model); +} + +/* + * Class: org_linphone_core_LinphoneFriendImpl + * Method: setPresenceModel + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneFriendImpl_setPresenceModel(JNIEnv *env, jobject jobj, jlong ptr, jlong presencePtr) { + LinphoneFriend *lf = (LinphoneFriend *)ptr; + LinphonePresenceModel *model = (LinphonePresenceModel *)presencePtr; + linphone_friend_set_presence_model(lf, model); +} + extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -3040,3 +3113,184 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *en linphone_event_unref(ev); } +/* + * 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: nbActivities + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_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: 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: 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_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: 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_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: 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; +} diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 924df2008..7b7c66f4f 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -214,6 +214,34 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activit */ LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model); +/** + * Increase the reference count of the #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased. + * @return The #LinphonePresenceModel object with the increased reference count. + */ +LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); + +/** + * Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0. + * @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased. + * @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); + +/** + * Sets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); + /** * @brief Compares two presence models. * @param[in] m1 The first #LinphonePresenceModel object. @@ -286,6 +314,34 @@ LINPHONE_PUBLIC int linphone_presence_model_add_note(LinphonePresenceModel *mode */ LINPHONE_PUBLIC int linphone_presence_model_clear_notes(LinphonePresenceModel *model); +/** + * Increase the reference count of the #LinphonePresenceActivity object. + * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be increased. + * @return The #LinphonePresenceActivity object with the increased reference count. + */ +LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity); + +/** + * Decrease the reference count of the #LinphonePresenceActivity object and destroy it if it reaches 0. + * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be decreased. + * @return The #LinphonePresenceActivity object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity); + +/** + * Sets the user data of a #LinphonePresenceActivity object. + * @param[in] activity The #LinphonePresenceActivity object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceActivity object. + * @param[in] activity The #LinphonePresenceActivity object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity); + /** * @brief Gets the string representation of a presence activity. * @param[in] activity A pointer to the #LinphonePresenceActivity object for which to get a string representation. @@ -309,6 +365,34 @@ LINPHONE_PUBLIC LinphonePresenceActivityType linphone_presence_activity_get_type */ LINPHONE_PUBLIC const char * linphone_presence_activity_get_description(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. + */ +LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note); + +/** + * Decrease the reference count of the #LinphonePresenceNote object and destroy it if it reaches 0. + * @param[in] note The #LinphonePresenceNote object for which the reference count is to be decreased. + * @return The #LinphonePresenceNote object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note); + +/** + * Sets the user data of a #LinphonePresenceNote object. + * @param[in] note The #LinphonePresenceNote object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceNote object. + * @param[in] note The #LinphonePresenceNote object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_note_get_user_data(LinphonePresenceNote *note); + /** * @brief Gets the content of a presence note. * @param[in] note A pointer to the #LinphonePresenceNote for which to get the content. diff --git a/coreapi/presence.c b/coreapi/presence.c index 6148e3929..9f6ee9bf6 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -37,6 +37,8 @@ extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); struct _LinphonePresenceNote { + void *user_data; + int refcnt; char *lang; char *content; }; @@ -50,6 +52,8 @@ struct _LinphonePresenceService { }; struct _LinphonePresenceActivity { + void *user_data; + int refcnt; LinphonePresenceActivityType type; char *description; }; @@ -67,6 +71,8 @@ struct _LinphonePresencePerson { * 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. */ @@ -139,6 +145,7 @@ static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus static struct _LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { struct _LinphonePresenceNote * note = ms_new0(struct _LinphonePresenceNote, 1); + note->refcnt = 1; note->content = ms_strdup(content); if (lang != NULL) { note->lang = ms_strdup(lang); @@ -448,6 +455,28 @@ void linphone_presence_model_delete(LinphonePresenceModel *model) { ms_free(model); } +LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) { + model->refcnt++; + return model; +} + +LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) { + model->refcnt--; + if (model->refcnt == 0) { + linphone_presence_model_delete(model); + return NULL; + } + return model; +} + +void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data) { + model->user_data = user_data; +} + +void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) { + return model->user_data; +} + bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2) { LinphonePresenceActivity *activity = NULL; int nb; @@ -918,6 +947,28 @@ static const char * presence_activity_type_to_string(LinphonePresenceActivityTyp return NULL; } +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_note_delete(activity); + return NULL; + } + return activity; +} + +void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data) { + activity->user_data = user_data; +} + +void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity) { + return activity->user_data; +} + 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); @@ -947,6 +998,28 @@ const char * linphone_presence_activity_get_description(const LinphonePresenceAc return activity->description; } +LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) { + note->refcnt++; + return note; +} + +LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) { + note->refcnt--; + if (note->refcnt == 0) { + presence_note_delete(note); + return NULL; + } + return note; +} + +void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data) { + note->user_data = user_data; +} + +void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { + return note->user_data; +} + const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) { if (note == NULL) return NULL; diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index c8a6d7b6f..66db71526 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -669,11 +669,31 @@ public interface LinphoneCore { void addFriend(LinphoneFriend lf) throws LinphoneCoreException; /** - * Set my presence status - * @param minute_away how long in away + * @brief Set my presence status + * @param minutes_away how long in away * @param status sip uri used to redirect call in state LinphoneStatusMoved + * @param status OnlineStatus + * @deprecated Use setPresenceModel() instead */ - void setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status); + void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status); + /** + * @brief Get my presence status + * @return OnlineStatus + * @deprecated Use getPresenceModel() instead + */ + OnlineStatus getPresenceInfo(); + /** + * @brief Set my presence status + * @param minutess_away how long in away + * @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved + * @param presence #LinphonePresenceModel + */ + void setPresenceModel(int minutes_away, String alternative_contact, 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 diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java index 417c582d9..d4a33fe45 100644 --- a/java/common/org/linphone/core/LinphoneFriend.java +++ b/java/common/org/linphone/core/LinphoneFriend.java @@ -103,10 +103,21 @@ 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(); + /** + * @brief Set the presence information of a friend + * @param presence A #PresenceModel object. It can be null to remove the presence information of the friend. + */ + void setPresenceModel(PresenceModel presence); /** * Starts editing a friend configuration. *
Because friend configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify friend configuration (such as address or subscription policy and so on). diff --git a/java/common/org/linphone/core/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/PresenceActivity.java b/java/common/org/linphone/core/PresenceActivity.java new file mode 100644 index 000000000..4f116c43c --- /dev/null +++ b/java/common/org/linphone/core/PresenceActivity.java @@ -0,0 +1,42 @@ +/* +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 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(); + +} 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/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java new file mode 100644 index 000000000..9644e04cb --- /dev/null +++ b/java/common/org/linphone/core/PresenceModel.java @@ -0,0 +1,109 @@ +/* +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 { + + /** Basic status as defined in section 4.1.4 of RFC 3863 */ + public enum BasicStatus { + /** 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 BasicStatus(int value) { + mValue = value; + } + + public int toInt() { + return mValue; + } + + static protected BasicStatus fromInt(int value) { + switch (value) { + case 0: return Open; + case 1: return Closed; + default: return Invalid; + } + } + } + + + + /** + * @brief Gets the basic status of a presence model. + * @return The #BasicStatus of the #PresenceModel object. + */ + BasicStatus getBasicStatus(); + + /** + * @brief Gets the number of activities included in the presence model. + * @return The number of activities included in the #PresenceModel object. + */ + long nbActivities(); + + /** + * @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 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. + */ + int setActivity(PresenceActivityType activity, String description); + + /** + * @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(); + +} diff --git a/java/common/org/linphone/core/PresenceNote.java b/java/common/org/linphone/core/PresenceNote.java new file mode 100644 index 000000000..a89cde1df --- /dev/null +++ b/java/common/org/linphone/core/PresenceNote.java @@ -0,0 +1,36 @@ +/* +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 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(); + +} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index ae9b26fe8..7884fb011 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -80,7 +80,10 @@ 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 void setPresenceInfo(long nativePtr, int minutes_away, String alternative_contact, int status); + private native int getPresenceInfo(long nativePtr); + private native void setPresenceModel(long nativePtr, int minutes_away, String alternative_contact, long presencePtr); + private native Object getPresenceModel(long nativePtr); private native long createChatRoom(long nativePtr,String to); private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled); private native boolean isVideoEnabled(long nativePtr); @@ -368,11 +371,19 @@ class LinphoneCoreImpl implements LinphoneCore { addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr); } - public synchronized void setPresenceInfo(int minute_away, String alternative_contact, - OnlineStatus status) { - setPresenceInfo(nativePtr,minute_away,alternative_contact,status.mValue); + public synchronized void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status) { + setPresenceInfo(nativePtr,minutes_away,alternative_contact,status.mValue); } + public synchronized OnlineStatus getPresenceInfo() { + return OnlineStatus.fromInt(getPresenceInfo(nativePtr)); + } + public synchronized void setPresenceModel(int minutes_away, String alternative_contact, PresenceModel presence) { + setPresenceModel(nativePtr, minutes_away, alternative_contact, ((PresenceModelImpl)presence).getNativePtr()); + } + public synchronized PresenceModel getPresenceModel() { + return (PresenceModel)getPresenceModel(nativePtr); + } public synchronized LinphoneChatRoom createChatRoom(String to) { return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to)); } diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index 6e7aa2db1..da37b15ac 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -30,6 +30,8 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { private native void enableSubscribes(long nativePtr,boolean value); private native boolean isSubscribesEnabled(long nativePtr); private native int getStatus(long nativePtr); + private native Object getPresenceModel(long nativePtr); + private native void setPresenceModel(long nativePtr, long presencePtr); private native void edit(long nativePtr); private native void done(long nativePtr); @@ -69,6 +71,12 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { public OnlineStatus getStatus() { return OnlineStatus.fromInt(getStatus(nativePtr)); } + public PresenceModel getPresenceModel() { + return (PresenceModel)getPresenceModel(nativePtr); + } + public void setPresenceModel(PresenceModel presence) { + setPresenceModel(nativePtr, ((PresenceModelImpl)presence).getNativePtr()); + } public void edit() { edit(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..fc63c4114 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceActivityImpl.java @@ -0,0 +1,51 @@ +/* +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 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 String getDescription(long nativePtr); + @Override + public String getDescription() { + return getDescription(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..c7720fa2e --- /dev/null +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -0,0 +1,85 @@ +/* +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 void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + public long getNativePtr() { + return mNativePtr; + } + + private native int getBasicStatus(long nativePtr); + @Override + public BasicStatus getBasicStatus() { + return BasicStatus.fromInt(getBasicStatus(mNativePtr)); + } + + private native long nbActivities(long nativePtr); + @Override + public long nbActivities() { + return nbActivities(mNativePtr); + } + + private native Object getNthActivity(long nativePtr, long idx); + @Override + public PresenceActivity getNthActivity(long idx) { + return (PresenceActivity)getNthActivity(mNativePtr, idx); + } + + 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 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); + } +} diff --git a/java/impl/org/linphone/core/PresenceNoteImpl.java b/java/impl/org/linphone/core/PresenceNoteImpl.java new file mode 100644 index 000000000..38c541cf2 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceNoteImpl.java @@ -0,0 +1,45 @@ +/* +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 void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native String getContent(long nativePtr); + @Override + public String getContent() { + return getContent(mNativePtr); + } + + private native String getLang(long nativePtr); + @Override + public String getLang() { + return getLang(mNativePtr); + } +} From db9d58cf45eb7609b1f17e0524b3b89b7ddc2ded Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 17:57:52 +0200 Subject: [PATCH 487/909] Fix bug with activities clearing. --- coreapi/presence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/presence.c b/coreapi/presence.c index 9f6ee9bf6..4f1af4dcb 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -290,6 +290,7 @@ static void presence_person_add_note(struct _LinphonePresencePerson *person, str static void presence_person_clear_activities(struct _LinphonePresencePerson *person) { ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete); ms_list_free(person->activities); + person->activities = NULL; } static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) { From e53bd7f811fac785d14b27dfe16b3ddb2dec1d25 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Jun 2013 18:01:39 +0200 Subject: [PATCH 488/909] Do not check equality of presence statuses because it does not work if the presence model of linphone core has been changed instead of a new one created. --- coreapi/linphonecore.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 87a57c7a6..9d1121c60 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3702,15 +3702,16 @@ void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const lc->alt_contact=NULL; } if (contact) lc->alt_contact=ms_strdup(contact); - if (!linphone_presence_model_equals(lc->presence_model,presence)){ - linphone_core_notify_all_friends(lc,presence); - /* - 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); - } + + // TODO: Check that the presence timestamp is newer than the last sent presence. + linphone_core_notify_all_friends(lc,presence); + /* + 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); + if ((lc->presence_model != NULL) && (lc->presence_model != presence)) { linphone_presence_model_delete(lc->presence_model); lc->presence_model = presence; From 3c1f7ace3366ee664e1155c3d4d3c5c1014117a0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 09:49:31 +0200 Subject: [PATCH 489/909] Fix wrong function call. --- coreapi/presence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 4f1af4dcb..889190d4c 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -956,7 +956,7 @@ LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivi LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) { activity->refcnt--; if (activity->refcnt == 0) { - presence_note_delete(activity); + presence_activity_delete(activity); return NULL; } return activity; From ee35e8e4131e66b098f9ba2eb7c0fb634d081cbd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 09:58:20 +0200 Subject: [PATCH 490/909] Remove linphone_friend_set_presence_model() and make linphone_friend_get_presence_model() return a const pointer because the user should not be able to change his friends' presence. --- coreapi/friend.c | 9 +-------- coreapi/linphonecore_jni.cc | 13 +------------ coreapi/linphonefriend.h | 9 +-------- coreapi/presence.c | 5 ++++- java/common/org/linphone/core/LinphoneFriend.java | 5 ----- java/impl/org/linphone/core/LinphoneFriendImpl.java | 3 --- tester/liblinphone_tester.h | 2 +- 7 files changed, 8 insertions(+), 38 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 32da85edb..9e535152c 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -356,17 +356,10 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ return online_status; } -LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf) { +const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf) { return lf->presence; } -void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *model) { - if (lf->presence != NULL) { - linphone_presence_model_delete(lf->presence); - } - lf->presence = model; -} - BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){ return lf->info; } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index bf3045de8..4278ca466 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2009,22 +2009,11 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env */ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneFriendImpl_getPresenceModel(JNIEnv *env, jobject jobj, jlong ptr) { LinphoneFriend *lf = (LinphoneFriend *)ptr; - LinphonePresenceModel *model = linphone_friend_get_presence_model(lf); + const LinphonePresenceModel *model = linphone_friend_get_presence_model(lf); if (model == NULL) return NULL; RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model); } -/* - * Class: org_linphone_core_LinphoneFriendImpl - * Method: setPresenceModel - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneFriendImpl_setPresenceModel(JNIEnv *env, jobject jobj, jlong ptr, jlong presencePtr) { - LinphoneFriend *lf = (LinphoneFriend *)ptr; - LinphonePresenceModel *model = (LinphonePresenceModel *)presencePtr; - linphone_friend_set_presence_model(lf, model); -} - extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 3f1680c63..d7c7cd8d8 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -219,14 +219,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); * @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) */ -LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); - -/** - * @brief Set the presence information of a friend - * @param[in] lf A #LinphoneFriend object - * @param[in] presence A #LinphonePresenceModel object. It can be NULL to remove the presence information of the friend. - */ -void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence); +const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); diff --git a/coreapi/presence.c b/coreapi/presence.c index 889190d4c..ddd65b515 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1668,7 +1668,10 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa 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); - linphone_friend_set_presence_model(lf, presence); + if (lf->presence != NULL) { + linphone_presence_model_delete(lf->presence); + } + lf->presence = presence; lf->subscribe_active=TRUE; if (lc->vtable.notify_presence_recv) lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java index d4a33fe45..1a84498ce 100644 --- a/java/common/org/linphone/core/LinphoneFriend.java +++ b/java/common/org/linphone/core/LinphoneFriend.java @@ -113,11 +113,6 @@ public interface LinphoneFriend { * @return A #PresenceModel object, or null if the friend do not have presence information (in which case he is considered offline) */ PresenceModel getPresenceModel(); - /** - * @brief Set the presence information of a friend - * @param presence A #PresenceModel object. It can be null to remove the presence information of the friend. - */ - void setPresenceModel(PresenceModel presence); /** * Starts editing a friend configuration. *
Because friend configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify friend configuration (such as address or subscription policy and so on). diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index da37b15ac..3b116f8ae 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -74,9 +74,6 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { public PresenceModel getPresenceModel() { return (PresenceModel)getPresenceModel(nativePtr); } - public void setPresenceModel(PresenceModel presence) { - setPresenceModel(nativePtr, ((PresenceModelImpl)presence).getNativePtr()); - } public void edit() { edit(nativePtr); } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 5d9b5b49c..36dc323af 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -151,7 +151,7 @@ typedef struct _stats { int number_of_LinphonePresenceActivityVacation; int number_of_LinphonePresenceActivityWorking; int number_of_LinphonePresenceActivityWorship; - LinphonePresenceModel *last_received_presence; + const LinphonePresenceModel *last_received_presence; int number_of_inforeceived; int number_of_inforeceived_with_body; From 15952e46fbe30378ea7c10672b719325e0d44a07 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 10:36:22 +0200 Subject: [PATCH 491/909] Use unref instead of explicit delete for presence objects. --- coreapi/friend.c | 4 ++-- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 4 ++-- coreapi/linphonepresence.h | 6 ------ coreapi/presence.c | 35 +++++++++++++++++++---------------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 9e535152c..80549e4f2 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -260,7 +260,7 @@ void linphone_friend_destroy(LinphoneFriend *lf){ sal_op_release(lf->outsub); lf->outsub=NULL; } - if (lf->presence != NULL) linphone_presence_model_delete(lf->presence); + 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); @@ -379,7 +379,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ case LinphoneSPWait: model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOther, "Waiting for user acceptance"); linphone_friend_notify(fr,model); - linphone_presence_model_delete(model); + linphone_presence_model_unref(model); break; case LinphoneSPAccept: if (fr->lc!=NULL) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a51001b3f..dd63fdb0a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -426,7 +426,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->owns_call_log=TRUE; model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); linphone_core_notify_all_friends(call->core,model); - linphone_presence_model_delete(model); + linphone_presence_model_unref(model); linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9d1121c60..8c79e75d4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3713,7 +3713,7 @@ void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const linphone_core_send_publish(lc,presence); if ((lc->presence_model != NULL) && (lc->presence_model != presence)) { - linphone_presence_model_delete(lc->presence_model); + linphone_presence_model_unref(lc->presence_model); lc->presence_model = presence; } } @@ -5457,7 +5457,7 @@ void ui_config_uninit(LinphoneCore* lc) lc->friends=NULL; } if (lc->presence_model) { - linphone_presence_model_delete(lc->presence_model); + linphone_presence_model_unref(lc->presence_model); lc->presence_model = NULL; } } diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 7b7c66f4f..c9624bcd9 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -208,12 +208,6 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activit */ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType activity, const char *description, const char *note, const char *lang); -/** - * @brief Deletes a presence model. - * @param[in] model The #LinphonePresenceModel object to delete. - */ -LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model); - /** * Increase the reference count of the #LinphonePresenceModel object. * @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased. diff --git a/coreapi/presence.c b/coreapi/presence.c index ddd65b515..52289d85b 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -185,7 +185,7 @@ static void presence_service_delete(struct _LinphonePresenceService *service) { if (service->contact != NULL) { ms_free(service->contact); } - ms_list_for_each(service->notes, (MSIterateFunc)presence_note_delete); + ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref); ms_list_free(service->notes); ms_free(service); }; @@ -204,6 +204,7 @@ static void presence_service_add_note(struct _LinphonePresenceService *service, static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1); + act->refcnt = 1; act->type = acttype; if (description != NULL) { act->description = ms_strdup(description); @@ -266,11 +267,11 @@ static void presence_person_delete(struct _LinphonePresencePerson *person) { if (person->id != NULL) { ms_free(person->id); } - ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete); + ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); ms_list_free(person->activities); - ms_list_for_each(person->activities_notes, (MSIterateFunc)presence_note_delete); + 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)presence_note_delete); + ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref); ms_list_free(person->notes); ms_free(person); } @@ -288,7 +289,7 @@ static void presence_person_add_note(struct _LinphonePresencePerson *person, str } static void presence_person_clear_activities(struct _LinphonePresencePerson *person) { - ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete); + ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); ms_list_free(person->activities); person->activities = NULL; } @@ -424,7 +425,9 @@ static bool_t presence_person_equals(const struct _LinphonePresencePerson *p1, c } LinphonePresenceModel * linphone_presence_model_new(void) { - return ms_new0(LinphonePresenceModel, 1); + LinphonePresenceModel *model = ms_new0(LinphonePresenceModel, 1); + model->refcnt = 1; + return model; } LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivityType acttype, const char *description) { @@ -444,14 +447,14 @@ LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(Linph return model; } -void linphone_presence_model_delete(LinphonePresenceModel *model) { +static void presence_model_delete(LinphonePresenceModel *model) { if (model == NULL) return; ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); ms_list_free(model->services); ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); ms_list_free(model->persons); - ms_list_for_each(model->notes, (MSIterateFunc)presence_note_delete); + ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref); ms_list_free(model->notes); ms_free(model); } @@ -464,7 +467,7 @@ LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) { model->refcnt--; if (model->refcnt == 0) { - linphone_presence_model_delete(model); + presence_model_delete(model); return NULL; } return model; @@ -734,16 +737,16 @@ int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *n } static void clear_presence_person_notes(struct _LinphonePresencePerson *person) { - ms_list_for_each(person->activities_notes, (MSIterateFunc)presence_note_delete); + 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)presence_note_delete); + 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(struct _LinphonePresenceService *service) { - ms_list_for_each(service->notes, (MSIterateFunc)presence_note_delete); + ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref); ms_list_free(service->notes); service->notes = NULL; } @@ -754,7 +757,7 @@ int linphone_presence_model_clear_notes(LinphonePresenceModel *model) { 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)presence_note_delete); + ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref); ms_list_free(model->notes); model->notes = NULL; @@ -1228,7 +1231,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing } if (err < 0) { - linphone_presence_model_delete(model); + linphone_presence_model_unref(model); model = NULL; } @@ -1669,7 +1672,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa 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_delete(lf->presence); + linphone_presence_model_unref(lf->presence); } lf->presence = presence; lf->subscribe_active=TRUE; @@ -1678,7 +1681,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); - linphone_presence_model_delete(presence); + linphone_presence_model_unref(presence); } if (ss==SalSubscribeTerminated){ sal_op_release(op); From 2d862f98ba3baea697e7c1a54f35c1c966417a98 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 10:45:14 +0200 Subject: [PATCH 492/909] Remove useless minutes_away and contact parameters to the linphone_core_set_presence_model() function. --- coreapi/help/buddy_status.c | 4 ++-- coreapi/linphonecore.c | 20 +++++++++---------- coreapi/linphonecore_jni.cc | 6 ++---- coreapi/linphonefriend.h | 4 +--- .../org/linphone/core/LinphoneCore.java | 6 ++---- .../org/linphone/core/LinphoneCoreImpl.java | 6 +++--- tester/presence_tester.c | 8 ++++---- 7 files changed, 24 insertions(+), 30 deletions(-) diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 4f1f64906..5e073d75a 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -168,7 +168,7 @@ int main(int argc, char *argv[]){ } /*set my status to online*/ - linphone_core_set_presence_model(lc, 0, NULL, linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL)); + 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){ @@ -177,7 +177,7 @@ int main(int argc, char *argv[]){ } /* change my presence status to offline*/ - linphone_core_set_presence_model(lc, 0, NULL, linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL)); + 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/linphonecore.c b/coreapi/linphonecore.c index 8c79e75d4..5e1820ce4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3646,6 +3646,14 @@ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const c 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; + } + if (contact) lc->alt_contact=ms_strdup(contact); + switch (os) { case LinphoneStatusOffline: acttype = LinphonePresenceActivityOffline; @@ -3691,18 +3699,10 @@ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const c return; } presence = linphone_presence_model_new_with_activity(acttype, description); - linphone_core_set_presence_model(lc, minutes_away, contact, presence); + linphone_core_set_presence_model(lc, presence); } -void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *contact, LinphonePresenceModel *presence) { - if (minutes_away>0) lc->minutes_away=minutes_away; - - if (lc->alt_contact!=NULL) { - ms_free(lc->alt_contact); - lc->alt_contact=NULL; - } - if (contact) lc->alt_contact=ms_strdup(contact); - +void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence) { // TODO: Check that the presence timestamp is newer than the last sent presence. linphone_core_notify_all_friends(lc,presence); /* diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4278ca466..e80a2c587 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1099,12 +1099,10 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPresenceInfo(JNIEnv * * Method: setPresenceModel * Signature: (JILjava/lang/String;J)V */ -JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPresenceModel(JNIEnv *env, jobject jobj, jlong ptr, jint minutes_away, jstring jalternative_contact, jlong modelPtr) { +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPresenceModel(JNIEnv *env, jobject jobj, jlong ptr, jlong modelPtr) { LinphoneCore *lc = (LinphoneCore *)ptr; - const char *calternative_contact = jalternative_contact ? env->GetStringUTFChars(jalternative_contact, NULL) : NULL; LinphonePresenceModel *model = (LinphonePresenceModel *)modelPtr; - linphone_core_set_presence_model(lc, minutes_away, calternative_contact, model); - if (calternative_contact) env->ReleaseStringUTFChars(jalternative_contact, calternative_contact); + linphone_core_set_presence_model(lc, model); } /* diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index d7c7cd8d8..312efec6a 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -249,11 +249,9 @@ LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minute /** * @brief Set my presence status * @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] presence #LinphonePresenceModel */ -LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *alternative_contact, LinphonePresenceModel *presence); +LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence); /** * @brief Get my presence status diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 66db71526..76ced4133 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -671,7 +671,7 @@ public interface LinphoneCore { /** * @brief Set my presence status * @param minutes_away how long in away - * @param status sip uri used to redirect call in state LinphoneStatusMoved + * @param alternative_contact sip uri used to redirect call in state LinphoneStatusMoved * @param status OnlineStatus * @deprecated Use setPresenceModel() instead */ @@ -684,11 +684,9 @@ public interface LinphoneCore { OnlineStatus getPresenceInfo(); /** * @brief Set my presence status - * @param minutess_away how long in away - * @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved * @param presence #LinphonePresenceModel */ - void setPresenceModel(int minutes_away, String alternative_contact, PresenceModel presence); + void setPresenceModel(PresenceModel presence); /** * @brief Get my presence status * @return A #PresenceModel object, or null if no presence model has been set. diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 7884fb011..a61bd1cc5 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -82,7 +82,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void addFriend(long nativePtr,long friend); 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, int minutes_away, String alternative_contact, long presencePtr); + private native void setPresenceModel(long nativePtr, long presencePtr); private native Object getPresenceModel(long nativePtr); private native long createChatRoom(long nativePtr,String to); private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled); @@ -378,8 +378,8 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized OnlineStatus getPresenceInfo() { return OnlineStatus.fromInt(getPresenceInfo(nativePtr)); } - public synchronized void setPresenceModel(int minutes_away, String alternative_contact, PresenceModel presence) { - setPresenceModel(nativePtr, minutes_away, alternative_contact, ((PresenceModelImpl)presence).getNativePtr()); + public synchronized void setPresenceModel(PresenceModel presence) { + setPresenceModel(nativePtr, ((PresenceModelImpl)presence).getNativePtr()); } public synchronized PresenceModel getPresenceModel() { return (PresenceModel)getPresenceModel(nativePtr); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 1363c4045..029d2e01a 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -134,7 +134,7 @@ static void simple_publish(void) { 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,0,NULL,presence); + linphone_core_set_presence_model(marie->lc,presence); wait_core(marie->lc); linphone_core_manager_destroy(marie); } @@ -222,7 +222,7 @@ static void presence_information(void) { /* Presence activity without description. */ presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityDinner, NULL); - linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); + linphone_core_set_presence_model(pauline->lc, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); @@ -233,7 +233,7 @@ static void presence_information(void) { /* Presence activity with description. */ presence = linphone_presence_model_new_with_activity(LinphonePresenceActivitySteering, bike_description); - linphone_core_set_presence_model(pauline->lc, 0, NULL, presence); + linphone_core_set_presence_model(pauline->lc, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); @@ -245,7 +245,7 @@ static void presence_information(void) { /* 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, 0, NULL, presence); + linphone_core_set_presence_model(pauline->lc, presence); wait_core(marie->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); From bbd8ec8ba4b703a7d488b691dd8e26b40fe6afba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 11:13:35 +0200 Subject: [PATCH 493/909] Add API to get and set contact of a presence model. --- coreapi/callbacks.c | 8 ++++++-- coreapi/linphonecore.c | 6 +----- coreapi/linphonepresence.h | 16 ++++++++++++++++ coreapi/presence.c | 27 +++++++++++++++++++++++++++ coreapi/private.h | 1 - tester/presence_tester.c | 15 +++++++++++++++ 6 files changed, 65 insertions(+), 8 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index bb0ae00ce..89bc20846 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -215,6 +215,7 @@ static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call; const char *from,*to; + char *alt_contact; LinphoneAddress *from_addr, *to_addr; bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE); @@ -232,8 +233,11 @@ static void call_received(SalOp *h){ sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); break; case LinphonePresenceActivityPermanentAbsence: - if (lc->alt_contact != NULL) - sal_call_decline(h,SalReasonRedirect,lc->alt_contact); + 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; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5e1820ce4..3549f34b6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3648,11 +3648,6 @@ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const c 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; - } - if (contact) lc->alt_contact=ms_strdup(contact); switch (os) { case LinphoneStatusOffline: @@ -3699,6 +3694,7 @@ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const c return; } presence = linphone_presence_model_new_with_activity(acttype, description); + linphone_presence_model_set_contact(presence, contact); linphone_core_set_presence_model(lc, presence); } diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index c9624bcd9..835ba855b 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -251,6 +251,22 @@ LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceMode */ LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); +/** + * @brief 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); + +/** + * @brief 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. + */ +LINPHONE_PUBLIC void linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact); + /** * @brief Gets the number of activities included in the presence model. * @param[in] model The #LinphonePresenceModel object to get the number of activities from. diff --git a/coreapi/presence.c b/coreapi/presence.c index 52289d85b..260b2a47d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -539,6 +539,33 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph return status; } +static void presence_model_find_contact(struct _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); +} + +void linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact) { + struct _LinphonePresenceService *service; + if (model != NULL) { + service = (struct _LinphonePresenceService *)ms_list_nth_data(model->services, 0); + if (service != NULL) { + if (service->contact != NULL) + ms_free(service->contact); + if (contact != NULL) + service->contact = ms_strdup(contact); + else + service->contact = NULL; + } + } +} + static void presence_model_count_activities(const struct _LinphonePresencePerson *person, unsigned int *nb) { *nb += ms_list_size(person->activities); } diff --git a/coreapi/private.h b/coreapi/private.h index d83ab161a..f1b0ccee2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -601,7 +601,6 @@ struct _LinphoneCore MSList *subscribers; /* unknown subscribers */ int minutes_away; LinphonePresenceModel *presence_model; - char *alt_contact; void *data; char *play_file; char *rec_file; diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 029d2e01a..3ca907d92 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -210,6 +210,7 @@ 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; @@ -217,6 +218,7 @@ static void presence_information(void) { LinphonePresenceNote *note = NULL; const char *description = NULL; const char *note_content = NULL; + char *contact2; CU_ASSERT_TRUE(subscribe_to_callee_presence(marie, pauline)); @@ -263,6 +265,19 @@ static void presence_information(void) { } } + /* 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_core(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone, 1); + contact2 = linphone_presence_model_get_contact(presence); + CU_ASSERT_PTR_NOT_NULL(contact2); + if (contact2 != NULL) { + CU_ASSERT_EQUAL(strcmp(contact, contact2), 0); + ms_free(contact2); + } + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From 9609991767f3fd668df9062eaee0403c566850e4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 11:23:50 +0200 Subject: [PATCH 494/909] Add linphone_presence_model_get_timestamp() function. --- coreapi/linphonepresence.h | 7 +++++++ coreapi/presence.c | 22 ++++++++++++++++++++++ tester/presence_tester.c | 10 ++++++++++ 3 files changed, 39 insertions(+) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 835ba855b..5129d7981 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -251,6 +251,13 @@ LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceMode */ LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); +/** + * @brief 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); + /** * @brief Gets the contact of a presence model. * @param[in] model The #LinphonePresenceModel object to get the contact from. diff --git a/coreapi/presence.c b/coreapi/presence.c index 260b2a47d..21ec3deeb 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -539,6 +539,28 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph return status; } +static void presence_service_find_newer_timestamp(struct _LinphonePresenceService *service, time_t *timestamp) { + if (service->timestamp > *timestamp) + *timestamp = service->timestamp; +} + +static void presence_person_find_newer_timestamp(struct _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(struct _LinphonePresenceService *service, char **contact) { if ((service->contact != NULL) && (*contact == NULL)) *contact = service->contact; diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 3ca907d92..75c0cd00d 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -219,6 +219,7 @@ static void presence_information(void) { const char *description = NULL; const char *note_content = NULL; char *contact2; + time_t current_timestamp, presence_timestamp; CU_ASSERT_TRUE(subscribe_to_callee_presence(marie, pauline)); @@ -278,6 +279,15 @@ static void presence_information(void) { ms_free(contact2); } + /* Presence timestamp. */ + current_timestamp = time(NULL); + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityShopping, NULL); + linphone_core_set_presence_model(pauline->lc, presence); + wait_core(marie->lc); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityShopping, 1); + presence_timestamp = linphone_presence_model_get_timestamp(presence); + CU_ASSERT_TRUE(presence_timestamp >= current_timestamp); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From c91ba396337a42cff7b04edf123e8cf1a363fbd4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 11:27:04 +0200 Subject: [PATCH 495/909] Remove useless equality testing code. --- coreapi/linphonepresence.h | 8 --- coreapi/presence.c | 116 ------------------------------------- 2 files changed, 124 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 5129d7981..f275d59d4 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -236,14 +236,6 @@ void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *u */ void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); -/** - * @brief Compares two presence models. - * @param[in] m1 The first #LinphonePresenceModel object. - * @param[in] m2 The second #LinphonePresenceModel object. - * @return TRUE if the #LinphonePresenceModel objects are equals, FALSE otherwise. - */ -LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2); - /** * @brief Gets the basic status of a presence model. * @param[in] model The #LinphonePresenceModel object to get the basic status from. diff --git a/coreapi/presence.c b/coreapi/presence.c index 21ec3deeb..3f2985d03 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -357,73 +357,6 @@ static void presence_model_find_open_basic_status(struct _LinphonePresenceServic } } -static bool_t presence_service_equals(const struct _LinphonePresenceService *s1, const struct _LinphonePresenceService *s2) { - if (s1->status != s2->status) - return FALSE; - return TRUE; -} - -static bool_t presence_note_equals(const struct _LinphonePresenceNote *n1, const struct _LinphonePresenceNote *n2) { - if (((n1->lang == NULL) && (n2->lang != NULL)) - || ((n1->lang != NULL) && (n2->lang == NULL))) - return FALSE; - - if (strcmp(n1->content, n2->content) != 0) - return FALSE; - if ((n1->lang != NULL) && (n2->lang != NULL)) { - if (strcmp(n1->lang, n2->lang) != 0) - return FALSE; - } - - return TRUE; -} - -static bool_t presence_activity_equals(const struct _LinphonePresenceActivity *a1, const struct _LinphonePresenceActivity *a2) { - if (((a1->description == NULL) && (a2->description != NULL)) - || ((a1->description != NULL) && (a2->description == NULL))) - return FALSE; - - if (a1->type != a2->type) - return FALSE; - - if ((a1->description != NULL) && (a2->description != NULL)) { - if (strcmp(a1->description, a2->description) != 0) - return FALSE; - } - - return TRUE; -} - -static bool_t presence_person_equals(const struct _LinphonePresencePerson *p1, const struct _LinphonePresencePerson *p2) { - int nb; - int i; - - if ((ms_list_size(p1->activities) != ms_list_size(p2->activities)) - || (ms_list_size(p1->activities_notes) != ms_list_size(p2->activities_notes)) - || (ms_list_size(p1->notes) != ms_list_size(p2->notes))) - return FALSE; - - nb = ms_list_size(p1->activities); - for (i = 0; i < nb; i++) { - if (presence_activity_equals(ms_list_nth_data(p1->activities, i), ms_list_nth_data(p2->activities, i)) == FALSE) - return FALSE; - } - - nb = ms_list_size(p1->activities_notes); - for (i = 0; i < nb; i++) { - if (presence_note_equals(ms_list_nth_data(p1->activities_notes, i), ms_list_nth_data(p2->activities_notes, i)) == FALSE) - return FALSE; - } - - nb = ms_list_size(p1->notes); - for (i = 0; i < nb; i++) { - if (presence_note_equals(ms_list_nth_data(p1->notes, i), ms_list_nth_data(p2->notes, i)) == FALSE) - return FALSE; - } - - return TRUE; -} - LinphonePresenceModel * linphone_presence_model_new(void) { LinphonePresenceModel *model = ms_new0(LinphonePresenceModel, 1); model->refcnt = 1; @@ -481,55 +414,6 @@ void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) { return model->user_data; } -bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2) { - LinphonePresenceActivity *activity = NULL; - int nb; - int i; - - /* If the two pointers are the same, the presence model are equals. */ - if (m1 == m2) - return TRUE; - - /* A null activity is equal to an activity with no activity but a basic status of Closed. */ - if (m1 == NULL) { - activity = linphone_presence_model_get_activity(m2); - if (linphone_presence_activity_get_type(activity) != LinphonePresenceActivityOffline) - return FALSE; - return TRUE; - } - if (m2 == NULL) { - activity = linphone_presence_model_get_activity(m2); - if (linphone_presence_activity_get_type(activity) != LinphonePresenceActivityOffline) - return FALSE; - return TRUE; - } - - if ((ms_list_size(m1->services) != ms_list_size(m2->services)) - || (ms_list_size(m1->persons) != ms_list_size(m2->persons)) - || (ms_list_size(m1->notes) != ms_list_size(m2->notes))) - return FALSE; - - nb = ms_list_size(m1->services); - for (i = 0; i < nb; i++) { - if (presence_service_equals(ms_list_nth_data(m1->services, i), ms_list_nth_data(m2->services, i)) == FALSE) - return FALSE; - } - - nb = ms_list_size(m1->persons); - for (i = 0; i < nb; i++) { - if (presence_person_equals(ms_list_nth_data(m1->persons, i), ms_list_nth_data(m2->persons, i)) == FALSE) - return FALSE; - } - - nb = ms_list_size(m1->notes); - for (i = 0; i < nb; i++) { - if (presence_note_equals(ms_list_nth_data(m1->notes, i), ms_list_nth_data(m2->notes, i)) == FALSE) - return FALSE; - } - - return TRUE; -} - /* 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; From 50f145ed7791cee65750ed6c84c380c370dea8da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 11:59:27 +0200 Subject: [PATCH 496/909] Add missing functions to presence JNI. --- coreapi/linphonecore_jni.cc | 37 ++++++++++++++++++- .../org/linphone/core/PresenceModel.java | 18 +++++++++ .../org/linphone/core/PresenceModelImpl.java | 18 +++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index e80a2c587..316e28c11 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2007,7 +2007,7 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env */ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneFriendImpl_getPresenceModel(JNIEnv *env, jobject jobj, jlong ptr) { LinphoneFriend *lf = (LinphoneFriend *)ptr; - const LinphonePresenceModel *model = linphone_friend_get_presence_model(lf); + LinphonePresenceModel *model = (LinphonePresenceModel *)linphone_friend_get_presence_model(lf); if (model == NULL) return NULL; RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model); } @@ -3120,6 +3120,41 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_getBasicStatus(J return (jint)linphone_presence_model_get_basic_status(model); } +/* + * 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: nbActivities diff --git a/java/common/org/linphone/core/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java index 9644e04cb..08cb2ad4b 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -56,6 +56,24 @@ public interface PresenceModel { */ BasicStatus getBasicStatus(); + /** + * @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 number of activities included in the presence model. * @return The number of activities included in the #PresenceModel object. diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java index c7720fa2e..839961ee9 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -41,6 +41,24 @@ public class PresenceModelImpl implements PresenceModel { return BasicStatus.fromInt(getBasicStatus(mNativePtr)); } + 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 long nbActivities(long nativePtr); @Override public long nbActivities() { From fae029b1874cd341f0a5e5c7886a9dc9db5bbbe9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 25 Jun 2013 12:07:55 +0200 Subject: [PATCH 497/909] Put BasicStatus in its own file. --- .../linphone/core/PresenceBasicStatus.java | 47 +++++++++++++++++++ .../org/linphone/core/PresenceModel.java | 31 +----------- 2 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 java/common/org/linphone/core/PresenceBasicStatus.java 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 index 08cb2ad4b..5a6a9bf93 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -21,40 +21,11 @@ package org.linphone.core; public interface PresenceModel { - /** Basic status as defined in section 4.1.4 of RFC 3863 */ - public enum BasicStatus { - /** 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 BasicStatus(int value) { - mValue = value; - } - - public int toInt() { - return mValue; - } - - static protected BasicStatus fromInt(int value) { - switch (value) { - case 0: return Open; - case 1: return Closed; - default: return Invalid; - } - } - } - - - /** * @brief Gets the basic status of a presence model. * @return The #BasicStatus of the #PresenceModel object. */ - BasicStatus getBasicStatus(); + PresenceBasicStatus getBasicStatus(); /** * @brief Gets the timestamp of a presence model. From 30e74df86b36db4825b7c9d9cfd4357a1d66e642 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 26 Jun 2013 13:16:19 +0200 Subject: [PATCH 498/909] disable multi thread support for vp8 on IOS simulator --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 94b4434c3..b291a292b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 94b4434c34d1ae9de5438b9cfa614ee1821eb709 +Subproject commit b291a292bfa5e6f90cbd05c68eb753fd1fcfbb50 From 6a033f8a646a9d1621e5e6c0a8886ad687ed77a6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 Jun 2013 15:11:00 +0200 Subject: [PATCH 499/909] retry the PUBLISH if they get a bad match (412) --- coreapi/bellesip_sal/sal_op_publish.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 2445d20e4..c54d3f8e4 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -26,8 +26,13 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher SalOp* op = (SalOp*)user_pointer; /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); - - + if (status_code==412){ + /*resubmit the request after removing the SIP-If-Match*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match"); + belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + } } /*presence publish */ int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence){ From 8cdbcae27a2282fa3f8adfc04bb5a77ce28dbce6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 Jun 2013 17:43:07 +0200 Subject: [PATCH 500/909] fix bad unref during out of subscribe notify --- coreapi/bellesip_sal/sal_op_events.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index a1a88fec8..e454ab293 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -123,10 +123,11 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *event 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) { From c5dcc52b29faa1703747d4d428f69fe30bbf9eda Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 26 Jun 2013 18:19:09 +0200 Subject: [PATCH 501/909] configure ms_set_cpu_count according to the number of cpu found Conflicts: sal_op_message.c --- gtk/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gtk/main.c b/gtk/main.c index 1aa2e287c..ec442b8bc 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -223,6 +223,15 @@ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); + long num_cpu=1; +#ifdef WIN32 /*fixme to be tested*/ + SYSTEM_INFO sysinfo; + GetSystemInfo( &sysinfo ); + + num_cpu = sysinfo.dwNumberOfProcessors; +#else if __APPLE_ || __linux + num_cpu = sysconf( _SC_NPROCESSORS_ONLN ); +#endif vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; @@ -243,6 +252,9 @@ static void linphone_gtk_init_liblinphone(const char *config_file, the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); + if (num_cpu>1) { + ms_set_cpu_count(num_cpu); + } 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); From d64e2fd0f635423c332302c3975506b625c9c869 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 26 Jun 2013 21:29:55 +0200 Subject: [PATCH 502/909] MS2:fix opus build, remove deprecated function from macsnd.c --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b291a292b..8da2151d2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b291a292bfa5e6f90cbd05c68eb753fd1fcfbb50 +Subproject commit 8da2151d27c24413c22ae5a681d9c21b7e711b1a From 88d02758b9c7187563d07e4d72e6a1781e366006 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 27 Jun 2013 18:49:52 +0200 Subject: [PATCH 503/909] Fix Android compilation with BasicStatus being moved in its own file. --- java/impl/org/linphone/core/PresenceModelImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java index 839961ee9..0a7173036 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -37,8 +37,8 @@ public class PresenceModelImpl implements PresenceModel { private native int getBasicStatus(long nativePtr); @Override - public BasicStatus getBasicStatus() { - return BasicStatus.fromInt(getBasicStatus(mNativePtr)); + public PresenceBasicStatus getBasicStatus() { + return PresenceBasicStatus.fromInt(getBasicStatus(mNativePtr)); } private native long getTimestamp(long nativePtr); From 68284f6358c1dd529930b9b8de9c85e1dd839289 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 1 Jul 2013 15:55:45 +0200 Subject: [PATCH 504/909] Add Visual Studio project for libxml2 and make linphone depend on it. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 5 +- .../LibLinphoneTester-wp8.sln | 80 ++++-- .../LibLinphoneTester.vcxproj | 1 + build/vsx/libxml2/libxml2.sln | 26 ++ build/vsx/libxml2/libxml2/libxml2.vcxproj | 234 ++++++++++++++++++ build/vsx/libxml2/libxml2/libxml2_port.h | 9 + coreapi/presence.c | 2 +- 7 files changed, 335 insertions(+), 22 deletions(-) create mode 100644 build/vsx/libxml2/libxml2.sln create mode 100644 build/vsx/libxml2/libxml2/libxml2.vcxproj create mode 100644 build/vsx/libxml2/libxml2/libxml2_port.h diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index f7f456fa3..6a04816c6 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -116,7 +116,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default @@ -251,6 +251,9 @@ {59500dd1-b192-4ddf-a402-8a8e3739e032} + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} +
diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index 6dab53c7a..cccf2645c 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -41,8 +41,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcaecm", "..\..\..\..\webrtc\build\windows\webrtcaecm\webrtcaecm\webrtcaecm.vcxproj", "{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\belle-sip\build\windows\polarssl\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\windows\libilbc-rfc3951\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" @@ -71,6 +69,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrwb\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\windows\polarssl\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\windows\tunnel\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -331,24 +335,6 @@ Global {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.Build.0 = Release|Win32 {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.ActiveCfg = Release|Win32 {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 - {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Any CPU.ActiveCfg = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM @@ -475,6 +461,60 @@ Global {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32 {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32 + {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|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Mixed Platforms.Build.0 = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32 + {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|Any CPU.ActiveCfg = Debug|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|Mixed Platforms.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {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}.Debug|x86.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Any CPU.ActiveCfg = Release|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|Mixed Platforms.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj index cf408958e..3b8e9bfc0 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -131,6 +131,7 @@ + diff --git a/build/vsx/libxml2/libxml2.sln b/build/vsx/libxml2/libxml2.sln new file mode 100644 index 000000000..62fad2d3f --- /dev/null +++ b/build/vsx/libxml2/libxml2.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Phone +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj new file mode 100644 index 000000000..6ed209ed9 --- /dev/null +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + libxml2 + en-US + 11.0 + + + + DynamicLibrary + true + v110 + false + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + false + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + MaxSpeed + $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + true + true + Default + true + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + false + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + false + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + true + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + MaxSpeed + $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + true + true + Default + true + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + false + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/libxml2/libxml2/libxml2_port.h b/build/vsx/libxml2/libxml2/libxml2_port.h new file mode 100644 index 000000000..761d1ae69 --- /dev/null +++ b/build/vsx/libxml2/libxml2/libxml2_port.h @@ -0,0 +1,9 @@ + +#ifndef LIBXML2_PORT_H +#define LIBXML2_PORT_H + +#define CreateMutex(a, b, c) CreateMutexEx(a, c, ((b) ? CREATE_MUTEX_INITIAL_OWNER : 0), 0) + +#define GetVersionEx(osvi) (((osvi)->dwPlatformId = 0) != 0) + +#endif /* LIBXML2_PORT_H */ diff --git a/coreapi/presence.c b/coreapi/presence.c index 3f2985d03..4b5f8425a 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -244,7 +244,7 @@ static char * timestamp_to_string(time_t timestamp) { struct tm gmt; ret = gmtime_r(×tamp,&gmt); #else - ret = gmtime(&curtime); + 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); From 47e06165fe20ffac79342ee817b0819efd867578 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 1 Jul 2013 16:34:29 +0200 Subject: [PATCH 505/909] Add missing exports. --- coreapi/event.h | 36 ++++++++++++++++---------------- coreapi/linphonecore.h | 24 +++++++++++----------- coreapi/linphonefriend.h | 44 ++++++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/coreapi/event.h b/coreapi/event.h index 6db01f46e..8ed3dae4b 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -77,31 +77,31 @@ typedef void (*LinphoneSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEve * @param body an optional body, may be NULL. * @return a LinphoneEvent holding the context of the created subcription. **/ -LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); +LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); /** * Update an outgoing subscription. * @param lev a LinphoneEvent * @param body an optional body to include in the subscription update, may be NULL. **/ -int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body); +LINPHONE_PUBLIC int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body); /** * Accept an incoming subcription. **/ -int linphone_event_accept_subscription(LinphoneEvent *lev); +LINPHONE_PUBLIC int linphone_event_accept_subscription(LinphoneEvent *lev); /** * Deny an incoming subscription with given reason. **/ -int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason); +LINPHONE_PUBLIC int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason); /** * Send a notification. * @param lev a #LinphoneEvent corresponding to an incoming subscription previously received and accepted. * @param body an optional body containing the actual notification data. * @return 0 if successful, -1 otherwise. **/ -int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body); +LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body); /** @@ -114,72 +114,72 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body); * @param body the actual published data * @return the LinphoneEvent holding the context of the publish. **/ -LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); +LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); /** * Update a publication. * @param lev the #LinphoneEvent * @param body the new data to be published **/ -int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body); +LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body); /** * Return reason code (in case of error state reached). **/ -LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev); +LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev); /** * Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned. **/ -LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev); +LINPHONE_PUBLIC LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev); /** * Get subscription direction. * If the object wasn't created by a subscription mechanism, #LinphoneSubscriptionInvalidDir is returned. **/ -LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev); +LINPHONE_PUBLIC LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev); /** * Set a user (application) pointer. **/ -void linphone_event_set_user_data(LinphoneEvent *ev, void *up); +LINPHONE_PUBLIC void linphone_event_set_user_data(LinphoneEvent *ev, void *up); /** * Retrieve user pointer. **/ -void *linphone_event_get_user_data(const LinphoneEvent *ev); +LINPHONE_PUBLIC void *linphone_event_get_user_data(const LinphoneEvent *ev); /** * Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication. **/ -void linphone_event_terminate(LinphoneEvent *lev); +LINPHONE_PUBLIC void linphone_event_terminate(LinphoneEvent *lev); /** * Increase reference count. **/ -LinphoneEvent *linphone_event_ref(LinphoneEvent *lev); +LINPHONE_PUBLIC LinphoneEvent *linphone_event_ref(LinphoneEvent *lev); /** * Decrease reference count. **/ -void linphone_event_unref(LinphoneEvent *lev); +LINPHONE_PUBLIC void linphone_event_unref(LinphoneEvent *lev); /** * Get the name of the event as specified in the event package RFC. **/ -const char *linphone_event_get_name(const LinphoneEvent *lev); +LINPHONE_PUBLIC const char *linphone_event_get_name(const LinphoneEvent *lev); /** * Get the "from" address of the subscription. **/ -const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev); /** * Get the resource address of the subscription or publish. **/ -const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev); +LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev); /** * @} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9f66bfd81..116ceb865 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -833,27 +833,27 @@ typedef enum _LinphoneChatMessageStates { */ typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); -void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path); LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); -LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); -void linphone_chat_room_destroy(LinphoneChatRoom *cr); +LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); -MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); -void linphone_chat_room_delete_history(LinphoneChatRoom *cr); -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); -LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); +LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); +LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); +LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); +LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); +LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); -LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); -void linphone_chat_message_destroy(LinphoneChatMessage* msg); -void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_destroy(LinphoneChatMessage* msg); +LINPHONE_PUBLIC void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); @@ -862,7 +862,7 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMe LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); LINPHONE_PUBLIC void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); -LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); +LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg); LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 312efec6a..d102728dc 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -121,7 +121,7 @@ typedef struct _LinphoneFriend LinphoneFriend; * Contructor * @return a new empty #LinphoneFriend */ -LinphoneFriend * linphone_friend_new(); +LINPHONE_PUBLIC LinphoneFriend * linphone_friend_new(); /** * Contructor same as linphone_friend_new() + linphone_friend_set_addr() * @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org @@ -133,21 +133,21 @@ LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_addr(const char *addr); * Destructor * @param lf #LinphoneFriend object */ -void linphone_friend_destroy(LinphoneFriend *lf); +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_addr(LinphoneFriend *fr, const LinphoneAddress* address); /** * set the display name for this friend * @param lf #LinphoneFriend object * @param name */ -int linphone_friend_set_name(LinphoneFriend *lf, const char *name); +LINPHONE_PUBLIC int linphone_friend_set_name(LinphoneFriend *lf, const char *name); /** * get address of this friend @@ -161,7 +161,7 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_friend_get_address(const Linphon * @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 /** @@ -178,14 +178,14 @@ LINPHONE_PUBLIC int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t * @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. @@ -212,19 +212,19 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); * @return #LinphoneOnlineStatus * @deprecated Use linphone_friend_get_presence_model() instead */ -LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); +LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); /** * @brief Get the presence information 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 LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); +LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(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); +LINPHONE_PUBLIC BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); +LINPHONE_PUBLIC const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); +LINPHONE_PUBLIC bool_t linphone_friend_in_list(const LinphoneFriend *lf); #define linphone_friend_url(lf) ((lf)->url) @@ -233,7 +233,7 @@ bool_t linphone_friend_in_list(const LinphoneFriend *lf); * @param ss * @deprecated Use #LinphonePresenceModel, #LinphonePresenceActivity and linphone_presence_activity_to_string() instead. */ -const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); +LINPHONE_PUBLIC const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); /** @@ -259,16 +259,16 @@ LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, Linphone * @return #LinphoneOnlineStatus * @deprecated Use linphone_core_get_presence_model() instead */ -LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); /** * @brief Get my presence status * @param[in] lc #LinphoneCore object * @return A #LinphonePresenceModel object, or NULL if no presence model has been set. */ -LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); -void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result); +LINPHONE_PUBLIC 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 @@ -280,13 +280,13 @@ LINPHONE_PUBLIC void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend * * @param lc #LinphoneCore object * @param fr #LinphoneFriend to add */ -void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr); /** * Black list a friend. same as linphone_friend_set_inc_subscribe_policy() with #LinphoneSPDeny policy; * @param lc #LinphoneCore object * @param lf #LinphoneFriend to add */ -void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); /** * get Buddy list of LinphoneFriend * @param lc #LinphoneCore object @@ -297,9 +297,9 @@ LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore * @param lc #LinphoneCore object * @param os #LinphoneOnlineStatus to notify * */ -void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); -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_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); +LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); +LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); /** * @} From 5cd4d1025410ca686b5a7e83875d86c0ad6b1923 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 1 Jul 2013 16:45:00 +0200 Subject: [PATCH 506/909] Fix wrong code. --- tester/liblinphone_tester.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f66255e89..cd278a7f9 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -100,8 +100,8 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* if (path==NULL) path="."; if (path && file){ - sprintf(filepath, "%s/%s", path, file); - CU_ASSERT_TRUE_FATAL(ortp_file_exist(path)==0); + snprintf(filepath, sizeof(filepath), "%s/%s", path, file); + CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); } lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); From 67abaa117c0a0139a54d1454f7f11a8690104630 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 1 Jul 2013 18:19:12 +0200 Subject: [PATCH 507/909] Update tester rc files for Windows Phone 8. --- .../LibLinphoneTester-wp8/Assets/empty_rc | 5 +++-- .../LibLinphoneTester-wp8/Assets/laure_rc | 11 +++++------ .../LibLinphoneTester-wp8/Assets/marie_early_rc | 7 ++----- .../LibLinphoneTester-wp8/Assets/marie_rc | 12 ++++++------ .../LibLinphoneTester-wp8/Assets/multi_account_lrc | 12 +++--------- .../LibLinphoneTester-wp8/Assets/pauline_rc | 12 ++++++------ .../LibLinphoneTester-wp8.csproj | 3 +++ 7 files changed, 28 insertions(+), 34 deletions(-) diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc index e8de43fa4..2fa8c43a3 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc @@ -1,5 +1,6 @@ -[net] +[net] mtu=1300 [sip] -ping_with_options=0 \ No newline at end of file +ping_with_options=0 +sip_random_port=1 \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc index 443c4e918..54a682401 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc @@ -1,6 +1,3 @@ -[net] -mtu=1300 - [sip] sip_port=5092 sip_tcp_port=5092 @@ -17,8 +14,7 @@ realm="sip.example.org" [proxy_0] -reg_proxy=sip2.linphone.org -reg_route=sip2.linphone.org +reg_proxy=sip.example.org reg_identity=sip:laure@sip.example.org reg_expires=3600 reg_sendregister=1 @@ -39,4 +35,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc index cf7fd383c..65934c3f3 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc @@ -1,6 +1,3 @@ -[net] -mtu=1300 - [sip] sip_port=5082 sip_tcp_port=5082 @@ -18,8 +15,8 @@ realm="sip.example.org" [proxy_0] -reg_proxy=sip2.linphone.org;transport=tcp -reg_route=sip2.linphone.org;transport=tcp;lr +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 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc index 760db76ba..56c96bc98 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc @@ -1,6 +1,3 @@ -[net] -mtu=1300 - [sip] sip_port=5082 sip_tcp_port=5082 @@ -17,8 +14,8 @@ realm="sip.example.org" [proxy_0] -reg_proxy=sip2.linphone.org;transport=tcp -reg_route=sip2.linphone.org;transport=tcp;lr +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 @@ -44,4 +41,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc index ea24951a3..23705a733 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc @@ -1,6 +1,3 @@ -[net] -mtu=1300 - [sip] sip_port=5072 sip_tcp_port=5072 @@ -32,8 +29,7 @@ passwd=secret realm="sip.example.org" [proxy_0] -reg_proxy=sip2.linphone.org -reg_route=sip2.linphone.org +reg_proxy=sip2.linphone.org;transport=tls reg_identity=sip:pauline@sip.example.org reg_expires=3600 reg_sendregister=1 @@ -41,8 +37,7 @@ publish=0 dial_escape_plus=0 [proxy_1] -reg_proxy=sip2.linphone.org;transport=tcp -reg_route=sip2.linphone.org;transport=tcp +reg_proxy=sip.example.org;transport=tcp reg_identity=sip:marie@sip.example.org reg_expires=3600 reg_sendregister=1 @@ -50,8 +45,7 @@ publish=0 dial_escape_plus=0 [proxy_2] -reg_proxy=sip2.linphone.org -reg_route=sip2.linphone.org +reg_proxy=auth1.example.org reg_identity=sip:liblinphone_tester@auth1.example.org reg_expires=3600 reg_sendregister=1 diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc index eb588cfc6..4ff876cf7 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc @@ -1,6 +1,3 @@ -[net] -mtu=1300 - [sip] sip_port=5072 sip_tcp_port=5072 @@ -17,8 +14,8 @@ realm="sip.example.org" [proxy_0] -reg_proxy=sip2.linphone.org;transport=tcp -reg_route=sip2.linphone.org;transport=tcp;lr +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 @@ -43,4 +40,7 @@ enabled=0 self_view=0 automatically_initiate=0 automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj index be5ee44f0..6ab7c0d58 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -187,4 +187,7 @@ --> + + Xcopy /I /Y $(ProjectDir)..\..\..\..\tester\*rc $(ProjectDir)Assets\ + \ No newline at end of file From 62e978c0bd4f46b16df1cbf0652af19e376ec579 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 1 Jul 2013 17:47:35 +0200 Subject: [PATCH 508/909] fix mline when media is declined, remove not implemented test --- coreapi/bellesip_sal/sal_sdp.c | 23 ++++++++++----- mediastreamer2 | 2 +- tester/call_tester.c | 3 +- tester/flexisip.conf | 54 +++++++++++++++++++--------------- tester/register_tester.c | 3 +- 5 files changed, 51 insertions(+), 34 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 00bba6505..c01d1d83b 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -92,18 +92,25 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia ,1 ,sal_media_proto_to_string ( stream->proto ) ,NULL ); - 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 + if (stream->payloads) { + for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { + pt= ( PayloadType* ) pt_it->data; + mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate ,stream->type==SalAudio?1:-1 ); - belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp ); - if ( stream->ptime>0 ) { - belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime ); + belle_sdp_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 ); } - 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){ diff --git a/mediastreamer2 b/mediastreamer2 index 8da2151d2..d49f3eead 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8da2151d27c24413c22ae5a681d9c21b7e711b1a +Subproject commit d49f3eeadb4faf93dd16b381957e45088ad891fd diff --git a/tester/call_tester.c b/tester/call_tester.c index d7f4ae0d6..0817082c1 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -345,9 +345,10 @@ static void early_declined_call(void) { CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); + /* FIXME http://git.linphone.org/mantis/view.php?id=757 CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_call_logs(marie->lc)),1); CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); - + */ if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { CU_ASSERT_PTR_NOT_NULL(in_call=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data)); CU_ASSERT_EQUAL(linphone_call_log_get_status(in_call),LinphoneCallDeclined); diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 6093289ca..28ab406a5 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -241,6 +241,37 @@ register-on-gateway=true # Default value: routing-domain routing-param=routing-domain +[module::Router] + +# Store and retrieve contacts without using the domain. +# Default value: false +use-global-domain=false + +# Fork messages to all registered devices +# Default value: true +fork=true + +# Force forking and thus the creation of an outgoing transaction +# even when only one contact found +# Default value: true +stateful=true + +# Fork invites to late registers +# Default value: false +fork-late=false + +# Only forward one response of forked invite to the caller +# Default value: true +fork-one-response=true + +# All the forked have to decline in order to decline the caller +# invite +# Default value: false +fork-no-global-decline=false + +# Maximum duration for delivering a message (text) +# Default value: 3600 +message-delivery-timeout=3600 ## ## The Registrar module accepts REGISTERs for domains it manages, ## and store the address of record in order to route other requests @@ -296,35 +327,12 @@ static-records-timeout=600 # Default value: internal db-implementation=internal -# Store and retrieve contacts without using the domain. -# Default value: false -use-global-domain=false -# Fork messages to all registered devices -# Default value: true -fork=true -# Force forking and thus the creation of an outgoing transaction -# even when only one contact found -# Default value: true -stateful=true -# Fork invites to late registers -# Default value: false -fork-late=false -# Only forward one response of forked invite to the caller -# Default value: true -fork-one-response=true -# All the forked have to decline in order to decline the caller -# invite -# Default value: false -fork-no-global-decline=false -# Maximum duration for delivering a message (text) -# Default value: 3600 -message-delivery-timeout=3600 # Generate a contact from the TO header and route it to the above # destination. [sip:host:port] diff --git a/tester/register_tester.c b/tester/register_tester.c index 0263a4567..9108368f1 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -458,8 +458,9 @@ static void tls_with_non_tls_server(){ linphone_proxy_config_set_server_addr(proxy_cfg,tmp); linphone_proxy_config_done(proxy_cfg); linphone_address_destroy(addr); - + /* FIXME http://git.linphone.org/mantis/view.php?id=758 CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); + */ linphone_core_manager_destroy(mgr); } From ee43d5d3bd7ba067a65f88fff917cb95c5580d6f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 1 Jul 2013 20:35:56 +0200 Subject: [PATCH 509/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d49f3eead..d5bcd59bb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d49f3eeadb4faf93dd16b381957e45088ad891fd +Subproject commit d5bcd59bb14f2ef4715b42ad6ae8995fc3903d80 From 6ac4aed2f0fc5151b72c19a2734720cd506c9979 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 2 Jul 2013 09:11:30 +0200 Subject: [PATCH 510/909] Fix compilation of libxml2 on Windows Phone 8. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 8 +- build/vsx/libxml2/libxml2/install_headers.bat | 6 + build/vsx/libxml2/libxml2/libxml2.vcxproj | 20 +- build/vsx/libxml2/libxml2/xmlversion.h | 476 ++++++++++++++++++ 4 files changed, 502 insertions(+), 8 deletions(-) create mode 100644 build/vsx/libxml2/libxml2/install_headers.bat create mode 100644 build/vsx/libxml2/libxml2/xmlversion.h diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 6a04816c6..fca4e0fa7 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -66,7 +66,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default @@ -90,7 +90,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true @@ -116,7 +116,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) false Default @@ -146,7 +146,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) true true diff --git a/build/vsx/libxml2/libxml2/install_headers.bat b/build/vsx/libxml2/libxml2/install_headers.bat new file mode 100644 index 000000000..8e97127d8 --- /dev/null +++ b/build/vsx/libxml2/libxml2/install_headers.bat @@ -0,0 +1,6 @@ +SET curdir=%CD% +SET incdir=..\..\..\..\..\libxml2\include\libxml +SET installdir=%1\libxml + +Xcopy /I /Y %incdir%\*.h %installdir%\ +Xcopy /I /Y xmlversion.h %installdir%\ diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj index 6ed209ed9..8f7b347fb 100644 --- a/build/vsx/libxml2/libxml2/libxml2.vcxproj +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -66,7 +66,7 @@ Level4 - $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false @@ -83,6 +83,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -91,7 +94,7 @@ Level4 MaxSpeed - $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true @@ -110,6 +113,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -117,7 +123,7 @@ Level4 - $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false @@ -135,6 +141,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -143,7 +152,7 @@ Level4 MaxSpeed - $(ProjectDir)..\..\..\..\..\libxml2\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true @@ -162,6 +171,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) diff --git a/build/vsx/libxml2/libxml2/xmlversion.h b/build/vsx/libxml2/libxml2/xmlversion.h new file mode 100644 index 000000000..f918d354d --- /dev/null +++ b/build/vsx/libxml2/libxml2/xmlversion.h @@ -0,0 +1,476 @@ +/* + * Summary: compile-time version informations + * Description: compile-time version informations for the XML library + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +XMLPUBFUN void XMLCALL xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.8.0" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXML_VERSION 20800 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXML_VERSION_STRING "20800" + +/** + * LIBXML_VERSION_EXTRA: + * + * extra version information, used to show a CVS compilation + */ +#define LIBXML_VERSION_EXTRA "" + +/** + * LIBXML_TEST_VERSION: + * + * Macro to check that the libxml version in use is compatible with + * the version the software has been compiled against + */ +#define LIBXML_TEST_VERSION xmlCheckVersion(20800); + +#ifndef VMS +#if 0 +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO +#else +/** + * WITHOUT_TRIO: + * + * defined if the trio support should not be configured in + */ +#define WITHOUT_TRIO +#endif +#else /* VMS */ +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO 1 +#endif /* VMS */ + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 1 +#if defined(_REENTRANT) || defined(__MT__) || \ + (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 >= 199506L)) +#define LIBXML_THREAD_ENABLED +#endif +#endif + +/** + * LIBXML_TREE_ENABLED: + * + * Whether the DOM like tree manipulation API support is configured in + */ +#if 1 +#define LIBXML_TREE_ENABLED +#endif + +/** + * LIBXML_OUTPUT_ENABLED: + * + * Whether the serialization/saving support is configured in + */ +#if 1 +#define LIBXML_OUTPUT_ENABLED +#endif + +/** + * LIBXML_PUSH_ENABLED: + * + * Whether the push parsing interfaces are configured in + */ +#if 1 +#define LIBXML_PUSH_ENABLED +#endif + +/** + * LIBXML_READER_ENABLED: + * + * Whether the xmlReader parsing interface is configured in + */ +#if 1 +#define LIBXML_READER_ENABLED +#endif + +/** + * LIBXML_PATTERN_ENABLED: + * + * Whether the xmlPattern node selection interface is configured in + */ +#if 1 +#define LIBXML_PATTERN_ENABLED +#endif + +/** + * LIBXML_WRITER_ENABLED: + * + * Whether the xmlWriter saving interface is configured in + */ +#if 1 +#define LIBXML_WRITER_ENABLED +#endif + +/** + * LIBXML_SAX1_ENABLED: + * + * Whether the older SAX1 interface is configured in + */ +#if 1 +#define LIBXML_SAX1_ENABLED +#endif + +/** + * LIBXML_FTP_ENABLED: + * + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#endif + +/** + * LIBXML_HTTP_ENABLED: + * + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#endif + +/** + * LIBXML_VALID_ENABLED: + * + * Whether the DTD validation support is configured in + */ +#if 1 +#define LIBXML_VALID_ENABLED +#endif + +/** + * LIBXML_HTML_ENABLED: + * + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#endif + +/** + * LIBXML_LEGACY_ENABLED: + * + * Whether the deprecated APIs are compiled in for compatibility + */ +#if 1 +#define LIBXML_LEGACY_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 1 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 1 +#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 + + From 7f4646760a4a7f9bd3b41839645bec39f1a8199c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 2 Jul 2013 09:47:43 +0200 Subject: [PATCH 511/909] Really fix compilation of libxml2 on Windows Phone 8. --- build/vsx/libxml2/libxml2/libxml2.vcxproj | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj index 8f7b347fb..f4d2bef17 100644 --- a/build/vsx/libxml2/libxml2/libxml2.vcxproj +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -66,7 +66,7 @@ Level4 - $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false @@ -83,9 +83,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) - + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -94,7 +94,7 @@ Level4 MaxSpeed - $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true @@ -113,9 +113,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) - + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -123,7 +123,7 @@ Level4 - $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false @@ -141,9 +141,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) - + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) @@ -152,7 +152,7 @@ Level4 MaxSpeed - $(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true @@ -171,9 +171,9 @@ $(TargetDir)$(TargetName)_dll.lib Ws2_32.lib;%(AdditionalDependencies) - + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) From df87ec318a09af8369aa0f07b55eb7fefdf89ef6 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 2 Jul 2013 13:40:21 +0200 Subject: [PATCH 512/909] avoid as much a possible audio resampler --- coreapi/linphonecore.c | 19 +++++++++++++++++-- mediastreamer2 | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3549f34b6..b33b4ad3e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2477,9 +2477,16 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_core_stop_dtmf_stream(lc); linphone_call_init_media_streams(call); - if (lc->ringstream==NULL) - audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); linphone_call_make_local_media_description(lc,call); + + if (lc->ringstream==NULL) { + /*give a chance a set card prefered sampling frequency*/ + if (call->localdesc->streams[0].max_rate>0) { + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + } + audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); + } + if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -3211,6 +3218,14 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (call->audiostream==NULL) linphone_call_init_media_streams(call); + + /*give a chance a set card prefered sampling frequency*/ + if (call->localdesc->streams[0].max_rate>0) { + ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate); + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); + } + if (!was_ringing && call->audiostream->ms.ticker==NULL){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } diff --git a/mediastreamer2 b/mediastreamer2 index d5bcd59bb..196084d7c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d5bcd59bb14f2ef4715b42ad6ae8995fc3903d80 +Subproject commit 196084d7ce9d94a72b670592b5ba2ff455d16408 From 8b674d05e33a80261dde28930591ff37dc8938b4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 2 Jul 2013 16:37:42 +0200 Subject: [PATCH 513/909] avoid crash if SIP request cannot be created --- coreapi/bellesip_sal/sal_op_impl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 0002a013b..0f829de91 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -268,6 +268,9 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req 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 ___________________________________________________________ From 866bc5c4c0c786f92f078aec36a5f1f9e2115e3c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 2 Jul 2013 16:37:39 +0200 Subject: [PATCH 514/909] add missing wrappers to the PayloadType object --- coreapi/linphonecore_jni.cc | 49 +++++++++++++++++++ .../common/org/linphone/core/PayloadType.java | 33 ++++++++++++- .../org/linphone/core/PayloadTypeImpl.java | 22 +++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 316e28c11..4e0e824a5 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3316,3 +3316,52 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceNoteImpl_getLang(JNIEnv const char *clang = linphone_presence_note_get_lang(note); return clang ? env->NewStringUTF(clang) : NULL; } + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: setRecvFmtp + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PayloadTypeImpl_setRecvFmtp(JNIEnv *env, jobject jobj, jlong ptr, jstring jfmtp){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=jfmtp ? env->GetStringUTFChars(jfmtp,NULL) : NULL; + payload_type_set_recv_fmtp(pt,fmtp); + if (fmtp) env->ReleaseStringUTFChars(jfmtp,fmtp); +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: getRecvFmtp + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getRecvFmtp(JNIEnv *env, jobject jobj, jlong ptr){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=pt->recv_fmtp; + return fmtp ? env->NewStringUTF(fmtp) : NULL; +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: setSendFmtp + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PayloadTypeImpl_setSendFmtp(JNIEnv *env, jobject jobj, jlong ptr , jstring jfmtp){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=jfmtp ? env->GetStringUTFChars(jfmtp,NULL) : NULL; + payload_type_set_send_fmtp(pt,fmtp); + if (fmtp) env->ReleaseStringUTFChars(jfmtp,fmtp); +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: getSendFmtp + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getSendFmtp(JNIEnv *env, jobject jobj, jlong ptr){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=pt->send_fmtp; + return fmtp ? env->NewStringUTF(fmtp) : NULL; +} + + + diff --git a/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/impl/org/linphone/core/PayloadTypeImpl.java b/java/impl/org/linphone/core/PayloadTypeImpl.java index 864b094ff..436cd3f30 100644 --- a/java/impl/org/linphone/core/PayloadTypeImpl.java +++ b/java/impl/org/linphone/core/PayloadTypeImpl.java @@ -42,4 +42,26 @@ class PayloadTypeImpl implements PayloadType { public String toString() { return toString(nativePtr); } + + private native void setRecvFmtp(long ptr, String fmtp); + @Override + public void setRecvFmtp(String fmtp) { + setRecvFmtp(nativePtr,fmtp); + } + private native String getRecvFmtp(long ptr); + @Override + public String getRecvFmtp() { + return getRecvFmtp(nativePtr); + } + + private native void setSendFmtp(long ptr, String fmtp); + @Override + public void setSendFmtp(String fmtp) { + setSendFmtp(nativePtr,fmtp); + } + private native String getSendFmtp(long ptr); + @Override + public String getSendFmtp() { + return getSendFmtp(nativePtr); + } } From ace8d8f094fbaf2ea2eb4377061566b3cee3fe93 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 2 Jul 2013 17:53:33 +0200 Subject: [PATCH 515/909] Fix compilation. --- gtk/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/main.c b/gtk/main.c index ec442b8bc..b7505dd87 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -229,7 +229,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, GetSystemInfo( &sysinfo ); num_cpu = sysinfo.dwNumberOfProcessors; -#else if __APPLE_ || __linux +#elif __APPLE_ || __linux num_cpu = sysconf( _SC_NPROCESSORS_ONLN ); #endif From 370dff2ad6891c5c857e3ada4bcf58dcbae38981 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 3 Jul 2013 18:34:14 +0200 Subject: [PATCH 516/909] make sure nowebcam is still compiled on IOS, even without ffmpeg --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index cab341d59..9398ac25a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit cab341d59bc4d37f82ddccbfcf1ae2563f9c5028 +Subproject commit 9398ac25a804fa4e6ee9ac0b3ed2774a4fea13ea From 14b83dc601eca72a3839dc6d15d5c810968791a6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 4 Jul 2013 12:26:20 +0200 Subject: [PATCH 517/909] Fix compilation of libxml2 in release mode on Windows Phone 8. --- build/vsx/libxml2/libxml2/libxml2.vcxproj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj index f4d2bef17..15fd066c1 100644 --- a/build/vsx/libxml2/libxml2/libxml2.vcxproj +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -67,13 +67,14 @@ Level4 $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false Default NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h Console @@ -95,7 +96,7 @@ Level4 MaxSpeed $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true true @@ -104,6 +105,7 @@ NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h Console @@ -153,7 +155,7 @@ Level4 MaxSpeed $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true true @@ -162,6 +164,7 @@ NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h Console From 83268b313b7302d38e3f5bd8ebc8ea867dc4db1c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Jul 2013 16:09:52 +0200 Subject: [PATCH 518/909] * fixes for dialog serialization * fix crash when receiving a NOTIFY after a SUBSCRIBE is terminated --- NEWS | 8 ++ coreapi/bellesip_sal/sal_impl.c | 4 + coreapi/bellesip_sal/sal_impl.h | 4 +- coreapi/bellesip_sal/sal_op_call.c | 130 +++++++------------- coreapi/bellesip_sal/sal_op_call_transfer.c | 7 +- coreapi/bellesip_sal/sal_op_impl.c | 10 +- coreapi/bellesip_sal/sal_op_presence.c | 1 + coreapi/bellesip_sal/sal_op_publish.c | 6 +- coreapi/callbacks.c | 5 + coreapi/linphonecall.c | 3 +- coreapi/linphonecore.c | 4 +- coreapi/misc.c | 4 + coreapi/private.h | 6 +- coreapi/proxy.c | 11 +- include/sal/sal.h | 5 +- tester/call_tester.c | 14 +-- tester/liblinphone_tester.c | 26 ++-- tester/tester_hosts | 2 +- 18 files changed, 118 insertions(+), 132 deletions(-) diff --git a/NEWS b/NEWS index 5b775e1bb..6a7106c6d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,14 @@ linphone-3.7...?? * multiple SIP transports simualtaneously now allowed * IP dual stack: can use IPv6 and IPv4 simultaneously * fully asynchronous behavior: no more lengthly DNS or connections + * +sip.instance parameter (RFC???) + * alias parameter (RFC????) + * better management of network disconnections + * SIP/TLS handled through lightweighted polarssl library (instead of openssl) + * SIP transaction state machines improved (RFC6026) + * Privacy API + * Full support of rich presence + linphone-3.6.1 -- June 17, 2013 * fix memory leak with some video cameras on windows. diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 2ff7041e6..e147efd32 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -181,6 +181,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev 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*)sal); op->dir=SalOpDirIncoming; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 7bc92e2c7..2848e97ac 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -128,8 +128,8 @@ void sal_op_message_fill_cbs(SalOp*op); void sal_op_subscribe_fill_cbs(SalOp*op); /*call transfer*/ -void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); -void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); +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); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 05157cb04..dc3489aca 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -23,10 +23,13 @@ static void call_set_released(SalOp* op){ op->state=SalOpStateTerminated; op->base.root->callbacks.call_released(op); } + +/*used when the SalOp was ref'd by the dialog*/ static void call_set_released_and_unref(SalOp* op) { call_set_released(op); sal_op_unref(op); } + static void call_set_error(SalOp* op,belle_sip_response_t* response){ SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; @@ -41,7 +44,6 @@ static void call_set_error(SalOp* op,belle_sip_response_t* response){ if (reason_header != NULL){ ms_free(reason); } - call_set_released(op); } static void sdp_process(SalOp *h){ @@ -124,60 +126,28 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat SalOp* op=(SalOp*)ctx; if (op->dialog && op->dialog==belle_sip_dialog_terminated_get_dialog(event)) { - belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog); - + /*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_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; - case BELLE_SIP_DIALOG_NULL: { - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_server_transaction_t)) { - /*call declined very early, no need to notify call release*/ - break; - } - } - default: { - - belle_sip_response_t* response=belle_sip_transaction_get_response(trans); - int code = belle_sip_response_get_status_code(response); - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_client_transaction_t)) { - switch (code) { - case 487: - call_set_released(op); - break; - case 401: - case 407: - if (op->state!=SalOpStateTerminating) { - /*normal termination for challenged dialog */ - break; - } - default: - call_set_error(op,response); + 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; } - } else { - sal_op_ref(op); /*to make sure op is still there when call released is scheduled*/ - belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) - ,(belle_sip_callback_t) call_set_released_and_unref - , op); - } - + break; + default: + break; } - } - belle_sip_object_unref(op->dialog); - op->dialog=NULL; - sal_op_unref(op); + belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) + ,(belle_sip_callback_t) call_set_released_and_unref + , op); } else { ms_error("dialog unknown for op "); } - - ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_get_dialog(event) - ,op); - } + static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { @@ -205,21 +175,22 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t if (!client_transaction) { - ms_warning("Discarding state less response [%i] on op [%p]",code,op); + ms_warning("Discarding stateless response [%i] on op [%p]",code,op); return; } req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; + + ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state)); switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { - if ( op->state == SalOpStateTerminating) { + if (op->state == SalOpStateTerminating) { if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { - if (code <200) { + if (code<200) { cancelling_invite(op); } else if (code<400) { sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); @@ -229,32 +200,16 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } else { /*nop, already cancelled*/ } - break; } else if (code >= 180 && code<300) { handle_sdp_from_response(op,response); op->base.root->callbacks.call_ringing(op); - break; } else if (code>=300){ - if (dialog_state==BELLE_SIP_DIALOG_NULL) { - call_set_error(op,response); - break; - } else { - /*nop let process_dialog_terminated manage error reporting*/ - } + call_set_error(op,response); + if (op->dialog==NULL) call_set_released(op); } - - } else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0 - || strcmp("BYE",belle_sip_request_get_method(req))==0) { - break;/*200ok for cancel or BYE*/ - } else { - /*nop error*/ - } - if (code >= 100 && code < 180) { - ms_message("call op [%p] receive [%i]",op,code); - } else { - ms_error("call op [%p] receive an unexpected answer [%i]",op,code); } } + break; case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { case SalOpStateEarly:/*invite case*/ @@ -278,7 +233,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->state=SalOpStateActive; } else { - /*nop*/ + if (code >= 300){ + call_set_error(op,response); + } } break; case SalOpStateTerminating: @@ -290,12 +247,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t break; } case BELLE_SIP_DIALOG_TERMINATED: { - /*if (code>=400 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ + if (code >= 300){ call_set_error(op,response); - call_set_released(op); - op->state=SalOpStateTerminated; - break; - }*/ + } break; } /* no break */ @@ -366,6 +320,7 @@ static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { }else op->sdp_offering=TRUE; } + static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; belle_sip_server_transaction_t* server_transaction=NULL; @@ -383,7 +338,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { - if (op->pending_server_trans)belle_sip_object_unref(op->pending_server_trans); + 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); @@ -502,9 +457,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { - sal_op_process_refer(op,event); + sal_op_process_refer(op,event,server_transaction); } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { - sal_op_call_process_notify(op,event); + sal_op_call_process_notify(op,event,server_transaction); } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); @@ -706,15 +661,18 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti } int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); - sal_op_fill_invite(op, reinvite); - return sal_op_send_request(op,reinvite); + if (reinvite){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); + sal_op_fill_invite(op, reinvite); + return sal_op_send_request(op,reinvite); + } + return -1; } + SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ return h->base.remote_media;; } - SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ if (h->base.local_media && h->base.remote_media && !h->result){ sdp_process(h); @@ -763,8 +721,8 @@ int sal_call_terminate(SalOp *op){ } else { /*just schedule call released*/ belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) - ,(belle_sip_callback_t) call_set_released - , op); + ,(belle_sip_callback_t) call_set_released + , op); } break; } diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index b0058e15e..c7fca7241 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -168,14 +168,14 @@ int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ } -void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ +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_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); 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)); @@ -200,8 +200,7 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ } -void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event){ - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); +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"); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 0f829de91..3feb54f98 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -31,7 +31,7 @@ SalOp * sal_op_new(Sal *sal){ void sal_op_release(SalOp *op){ op->state=SalOpStateTerminated; - sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/ + 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); } @@ -292,7 +292,6 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonUnknown: ret=400; break; - case SalReasonBusy: ret=486; break; @@ -320,6 +319,9 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonServiceUnavailable: ret=503; break; + case SalReasonRequestPending: + ret=491; + break; } return ret; } @@ -354,6 +356,10 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal break; case 487: break; + case 491: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonRequestPending; + break; case 600: *sal_err=SalErrorFailure; *sal_reason=SalReasonDoNotDisturb; diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 62acc81aa..99769f326 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -47,6 +47,7 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo 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) { diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index c54d3f8e4..9f23b849d 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -35,7 +35,7 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher } } /*presence publish */ -int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence){ +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) @@ -47,13 +47,13 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenc req=sal_op_build_request(op,"PUBLISH"); 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,600,publish_refresher_listener); + 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),presence); - return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + return belle_sip_refresher_refresh(op->refresher,expires); } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 352ab3c58..f4a475dae 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -646,6 +646,11 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); break; + case SalReasonRequestPending: + /*restore previous state, the application will decide to resubmit the action if relevant*/ + linphone_call_set_state(call,call->prevstate,msg); + return; + break; default: if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Call failed.")); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dd63fdb0a..c19a7a882 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -700,6 +700,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const LinphoneCore *lc=call->core; if (call->state!=cstate){ + call->prevstate=call->state; if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){ if (cstate!=LinphoneCallReleased){ ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state), @@ -2585,7 +2586,7 @@ void linphone_call_set_contact_op(LinphoneCall* call) { if (contact){ sal_op_set_contact(call->op, contact); #ifndef USE_BELLESIP - ms_free(contact); + ms_free(contact); #else linphone_address_destroy(contact); #endif diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c5dc2d056..5f3aa37a1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2813,7 +2813,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ sal_call_decline(call->op,SalReasonMedia,NULL); linphone_core_del_call(lc,call); - linphone_call_ref(call); + linphone_call_unref(call); return; } } @@ -3327,7 +3327,7 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) switch (call->state) { case LinphoneCallReleased: case LinphoneCallEnd: - ms_warning("No need to terminate a call [%p] in sate [%s]",call,linphone_call_state_to_string(call->state)); + 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: diff --git a/coreapi/misc.c b/coreapi/misc.c index 24775553d..272d37960 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1219,6 +1219,10 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ break; case SalReasonServiceUnavailable: ret=LinphoneReasonIOError; + break; + case SalReasonRequestPending: + ret=LinphoneReasonNone; + break; } return ret; } diff --git a/coreapi/private.h b/coreapi/private.h index f1b0ccee2..1e28939c9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -163,7 +163,8 @@ struct _LinphoneCall char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ - LinphoneCallState state; + LinphoneCallState state; + LinphoneCallState prevstate; LinphoneCallState transfer_state; /*idle if no transfer*/ LinphoneReason reason; LinphoneProxyConfig *dest_proxy; @@ -384,7 +385,6 @@ struct _LinphoneProxyConfig char *realm; char *contact_params; int expires; - int reg_time; SalOp *op; char *type; struct _SipSetupContext *ssctx; @@ -396,6 +396,8 @@ struct _LinphoneProxyConfig bool_t reg_sendregister; bool_t publish; bool_t dial_escape_plus; + bool_t send_publish; + bool_t pad[3]; void* user_data; time_t deletion_date; LinphoneReason error; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 814c00766..aacde9920 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -252,11 +252,6 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ sal_unregister(obj->op); } } - if (obj->publish_op){ - /*we should certainly cancel our publish by some manner*/ - sal_op_release(obj->publish_op); - obj->publish_op=NULL; - } } void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) @@ -858,7 +853,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); } - err=sal_publish_presence(proxy->publish_op,NULL,NULL,(SalPresenceModel *)presence); + err=sal_publish_presence(proxy->publish_op,NULL,NULL,proxy->expires,(SalPresenceModel *)presence); return err; } @@ -1186,10 +1181,12 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ if (can_register(cfg)){ linphone_proxy_config_register(cfg); cfg->commit=FALSE; + if (cfg->publish) cfg->send_publish=TRUE; } } - if (cfg->publish && cfg->publish_op==NULL && cfg->state==LinphoneRegistrationOk){ + if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){ linphone_proxy_config_send_publish(cfg,lc->presence_model); + cfg->send_publish=FALSE; } } diff --git a/include/sal/sal.h b/include/sal/sal.h index 0e94faf5b..48f9905be 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -273,7 +273,8 @@ typedef enum SalReason{ SalReasonMedia, SalReasonForbidden, SalReasonUnknown, - SalReasonServiceUnavailable + SalReasonServiceUnavailable, + SalReasonRequestPending }SalReason; const char* sal_reason_to_string(const SalReason reason); @@ -538,7 +539,7 @@ int sal_notify_presence(SalOp *op, SalPresenceModel *presence); int sal_notify_presence_close(SalOp *op); /*presence publish */ -int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence); +int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence); /*ping: main purpose is to obtain its own contact address behind firewalls*/ diff --git a/tester/call_tester.c b/tester/call_tester.c index 0817082c1..d16180732 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -336,22 +336,22 @@ static void cancelled_ringing_call(void) { static void early_declined_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCallLog* in_call; + LinphoneCallLog* out_call_log; LinphoneCall* out_call; linphone_core_set_max_calls(marie->lc,0); out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); /* FIXME http://git.linphone.org/mantis/view.php?id=757 - CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_call_logs(marie->lc)),1); - CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy); */ - if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { - CU_ASSERT_PTR_NOT_NULL(in_call=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data)); - CU_ASSERT_EQUAL(linphone_call_log_get_status(in_call),LinphoneCallDeclined); + if (ms_list_size(linphone_core_get_call_logs(pauline->lc))>0) { + CU_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(pauline->lc)->data)); + CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted); } linphone_call_unref(out_call); linphone_core_manager_destroy(marie); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index cd278a7f9..466ef1278 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -99,29 +99,29 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* if (path==NULL) path="."; - if (path && file){ - snprintf(filepath, sizeof(filepath), "%s/%s", path, file); + if (file){ + sprintf(filepath, "%s/%s", path, file); CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); } lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); - if (path){ + #ifndef ANDROID - snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path); + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path); #else - snprintf(rootcapath, sizeof(rootcapath), "%s/cacert.pem", path); + snprintf(rootcapath, sizeof(rootcapath), "%s/cacert.pem", path); #endif - linphone_core_set_root_ca(lc,rootcapath); + linphone_core_set_root_ca(lc,rootcapath); - sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); - sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); + sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + + sprintf(ringpath, "%s/%s", path, "oldphone.wav"); + sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); - sprintf(ringpath, "%s/%s", path, "oldphone.wav"); - sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); - linphone_core_set_ring(lc, ringpath); - linphone_core_set_ringback(lc, ringbackpath); - } return lc; } diff --git a/tester/tester_hosts b/tester/tester_hosts index b5ffa240a..39b811654 100644 --- a/tester/tester_hosts +++ b/tester/tester_hosts @@ -1 +1 @@ -37.59.129.74 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org +94.23.19.176 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org From 0b2d04d624b93c861d8487573164e98cb4ccf713 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Jul 2013 23:05:20 +0200 Subject: [PATCH 519/909] many improvements * re-send SUBSCRIBEs after network gets reachable again * allow to set the default SUBSCRIBE expires using [sip] "subscribe_expires" property * re-send initial SUBSCRIBE if remote peer lost the dialog context --- coreapi/bellesip_sal/sal_op_presence.c | 27 +++++++++++++++++++--- coreapi/friend.c | 31 ++++++++++++++++++++------ coreapi/linphonecore.c | 11 ++++----- coreapi/private.h | 2 ++ include/sal/sal.h | 2 +- 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 99769f326..4c65ff3f7 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -56,6 +56,20 @@ static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog } } +static void presence_refresher_listener( const 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); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + 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; @@ -96,6 +110,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); + belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); } } break; @@ -246,7 +261,7 @@ void sal_op_presence_fill_cbs(SalOp*op) { /*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ +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); @@ -255,10 +270,16 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ sal_op_presence_fill_cbs(op); - /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ + if (expires==-1){ + if (op->refresher){ + expires=belle_sip_refresher_get_expires(op->refresher); + }else{ + ms_error("sal_subscribe_presence(): cannot guess expires from previous refresher."); + } + } req=sal_op_build_request(op,"SUBSCRIBE"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); + 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); } diff --git a/coreapi/friend.c b/coreapi/friend.c index 80549e4f2..5437a5a03 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -111,6 +111,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ char *friend=NULL; const char *from=NULL; LinphoneProxyConfig *cfg; + LinphoneCore *lc=fr->lc; friend=linphone_address_as_string(fr->uri); cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); @@ -129,9 +130,9 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ sal_op_release(fr->outsub); fr->outsub=NULL; } - fr->outsub=sal_op_new(fr->lc->sal); - linphone_configure_op(fr->lc,fr->outsub,fr->uri,NULL,TRUE); - 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,from,friend,lp_config_get_int(lc->config,"sip","subscribe_expires",600)); fr->subscribe_active=TRUE; ms_free(friend); } @@ -243,6 +244,14 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ } } +static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ + if (lf->outsub!=NULL) { + sal_op_release(lf->outsub); + lf->outsub=NULL; + lf->subscribe_active=FALSE; + } +} + void linphone_friend_close_subscriptions(LinphoneFriend *lf){ linphone_friend_unsubscribe(lf); if (lf->insub){ @@ -383,9 +392,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ break; case LinphoneSPAccept: if (fr->lc!=NULL) - { linphone_friend_notify(fr,fr->lc->presence_model); - } break; case LinphoneSPDeny: linphone_friend_notify(fr,NULL); @@ -441,11 +448,21 @@ void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ void linphone_core_send_initial_subscribes(LinphoneCore *lc){ const MSList *elem; + if (lc->initial_subscribes_sent) return; for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *f=(LinphoneFriend*)elem->data; - if (f->commit) - linphone_friend_apply(f,lc); + linphone_friend_apply(f,lc); } + lc->initial_subscribes_sent=TRUE; +} + +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){ + const MSList *elem; + for(elem=lc->friends;elem!=NULL;elem=elem->next){ + LinphoneFriend *f=(LinphoneFriend*)elem->data; + linphone_friend_invalidate_subscription(f); + } + lc->initial_subscribes_sent=FALSE; } void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5f3aa37a1..15ca4867a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2206,10 +2206,9 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_run_hooks(lc); linphone_core_do_plugin_tasks(lc); - if (lc->initial_subscribes_sent==FALSE && lc->netup_time!=0 && - (curtime-lc->netup_time)>3){ + if (lc->network_reachable && lc->netup_time!=0 && (curtime-lc->netup_time)>3){ + /*not do that immediately, take your time.*/ linphone_core_send_initial_subscribes(lc); - lc->initial_subscribes_sent=TRUE; } if (one_second_elapsed) { @@ -5581,13 +5580,15 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu lc->netup_time=curtime; lc->network_reachable=isReachable; + if (!lc->network_reachable) linphone_core_invalidate_friend_subscriptions(lc); + if(!isReachable) { sal_reset_transports(lc->sal); } #ifdef BUILD_UPNP if(lc->upnp == NULL) { if(isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { - lc->upnp = linphone_upnp_context_new(lc); + lc->upnp = linphone_upnp_context_new(lc); } } else { if(!isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { @@ -5595,7 +5596,7 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu lc->upnp = NULL; } } -#endif +#endif } void linphone_core_refresh_registers(LinphoneCore* lc) { diff --git a/coreapi/private.h b/coreapi/private.h index 1e28939c9..984735ffe 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -758,6 +758,8 @@ void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); + #ifdef __cplusplus } #endif diff --git a/include/sal/sal.h b/include/sal/sal.h index 48f9905be..9cbaba73e 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -534,7 +534,7 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text) int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg); /*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to); +int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires); int sal_notify_presence(SalOp *op, SalPresenceModel *presence); int sal_notify_presence_close(SalOp *op); From bdd9839dea820ec38171b3a6a8ea14358bf9210b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Jul 2013 10:40:07 +0200 Subject: [PATCH 520/909] add alias to SUBSCRIBE as well --- coreapi/bellesip_sal/sal_op_impl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 3feb54f98..c2a198353 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -213,6 +213,8 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req const MSList *elem=sal_op_get_route_addresses(op); belle_sip_uri_t *next_hop_uri; const char *transport; + const char *method=belle_sip_request_get_method(request); + if (elem) { outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); next_hop_uri=outbound_proxy; @@ -236,7 +238,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req } belle_sip_uri_fix(next_hop_uri); } - if (strcmp(belle_sip_request_get_method(request),"REGISTER")==0 && transport && + if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); From d8469f7074b64493299841432835a66a0ec1403e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 8 Jul 2013 15:29:47 +0200 Subject: [PATCH 521/909] =?UTF-8?q?Add=20XGA,=20SXGA=E2=88=92=20and=20UXGA?= =?UTF-8?q?=20to=20the=20list=20of=20supported=20HD=20resolutions.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coreapi/linphonecore.c | 3 +++ mediastreamer2 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 15ca4867a..329a273cd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4960,6 +4960,9 @@ 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} , "720p" }, + { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, + { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H , "sxga-" }, + { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, #endif { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, diff --git a/mediastreamer2 b/mediastreamer2 index 9398ac25a..2d30405af 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9398ac25a804fa4e6ee9ac0b3ed2774a4fea13ea +Subproject commit 2d30405af1fbfd8192de3ebecdd9db01011b4672 From 1b6da4751b11482d46bc680289c563e4e0965718 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 9 Jul 2013 11:35:38 +0200 Subject: [PATCH 522/909] fix potential problem with ringback beeing stopped automatically by mistake. --- coreapi/callbacks.c | 26 ++++++-------------------- coreapi/linphonecore.c | 39 +++++++++++++++++---------------------- coreapi/private.h | 2 +- 3 files changed, 24 insertions(+), 43 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f4a475dae..1e8a3fb11 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -89,10 +89,7 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ SalMediaDescription *oldmd=call->resultdesc; - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); if (new_md!=NULL){ sal_media_description_ref(new_md); call->media_pending=FALSE; @@ -302,12 +299,8 @@ static void call_ringing(SalOp *h){ md=sal_call_get_final_media_description(h); if (md==NULL){ - if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; - } - if (lc->ringstream!=NULL) return; /*already ringing !*/ + linphone_core_stop_dtmf_stream(lc); + if (lc->ringstream!=NULL) return;/*already ringing !*/ if (lc->sound_conf.play_sndcard!=NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate); @@ -331,10 +324,7 @@ static void call_ringing(SalOp *h){ if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Early media.")); linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media"); - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); ms_message("Doing early media..."); linphone_core_update_streams(lc,call,md); } @@ -552,8 +542,7 @@ static void call_terminated(SalOp *op, const char *from){ ms_message("Current call terminated..."); //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) @@ -657,10 +646,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } } - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); 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*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 329a273cd..93b2e5a46 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2138,9 +2138,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0 && (curtime-lc->dmfs_playing_start_time)>5){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; + linphone_core_stop_dtmf_stream(lc); } sal_iterate(lc->sal); @@ -2831,9 +2829,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (ms_list_size(lc->calls)==1){ lc->current_call=call; if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; + linphone_core_stop_dtmf_stream(lc); } if (lc->sound_conf.ring_sndcard!=NULL){ if(lc->ringstream==NULL && lc->sound_conf.local_ring){ @@ -3192,9 +3188,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){ @@ -3249,10 +3243,7 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e sal_call_terminate(call->op); /*stop ringing*/ - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); #ifdef BUILD_UPNP @@ -3271,10 +3262,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ call->reason=LinphoneReasonDeclined; } /*stop ringing*/ - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); @@ -3510,8 +3498,7 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ _linphone_core_pause_call(lc,current_call); } if (lc->ringstream){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; + linphone_core_stop_ringing(lc); } } @@ -5523,7 +5510,7 @@ static void linphone_core_uninit(LinphoneCore *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); @@ -5834,10 +5821,18 @@ 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) { +void linphone_core_stop_ringing(LinphoneCore* lc) { + if (lc->ringstream) { ring_stop(lc->ringstream); lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + lc->ringstream_autorelease=TRUE; + } +} + +void linphone_core_stop_dtmf_stream(LinphoneCore* lc) { + if (lc->dmfs_playing_start_time!=0) { + linphone_core_stop_ringing(lc); } } diff --git a/coreapi/private.h b/coreapi/private.h index 984735ffe..71cd69136 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -757,7 +757,7 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); - +void linphone_core_stop_ringing(LinphoneCore *lc); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); #ifdef __cplusplus From 226657f35876471b401fdb30d126cf2527ba83ec Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Jul 2013 11:58:18 +0200 Subject: [PATCH 523/909] Add API to get the sizes of the sent and received video streams of a call. --- coreapi/linphonecall.c | 18 ++++++++++++++++++ coreapi/linphonecore.h | 14 ++++++++++++++ mediastreamer2 | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c19a7a882..01dbaf8db 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2506,6 +2506,24 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } +MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call) { + VideoStream *vstream = call->videostream; + MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; + if (vstream != NULL) { + vsize = video_stream_get_sent_video_size(vstream); + } + return vsize; +} + +MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call) { + VideoStream *vstream = call->videostream; + MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; + if (vstream != NULL) { + vsize = video_stream_get_received_video_size(vstream); + } + return vsize; +} + #ifndef USE_BELLESIP static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ #else diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5053961f9..a48ec44b8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -589,6 +589,20 @@ LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_ **/ LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); +/** + * Gets the size of the video that is sent. + * @param[in] call The call for which to get the sent video size. + * @return The sent video size or MS_VIDEO_SIZE_UNKNOWN if not available. + */ +LINPHONE_PUBLIC MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call); + +/** + * Gets the size of the video that is received. + * @param[in] call The call for which to get the received video size. + * @return The received video size or MS_VIDEO_SIZE_UNKNOWN if not available. + */ +LINPHONE_PUBLIC MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call); + /*keep this in sync with mediastreamer2/msvolume.h*/ /** diff --git a/mediastreamer2 b/mediastreamer2 index 2d30405af..e09b7d290 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2d30405af1fbfd8192de3ebecdd9db01011b4672 +Subproject commit e09b7d2903732769e9121baf8d9d1b989ab0bb00 From 2ecb66aa42cb58c51e964f3fb0a70a6a7420366a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Jul 2013 16:53:42 +0200 Subject: [PATCH 524/909] Update ms2 submodule for work on video encoders configurations. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e09b7d290..053603969 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e09b7d2903732769e9121baf8d9d1b989ab0bb00 +Subproject commit 05360396963de551078d3465ea8e5a8fa09c1cf2 From 2f3f66534375c40d2170286e059c5cd47b931107 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 9 Jul 2013 16:07:06 +0200 Subject: [PATCH 525/909] make sure dialog is in the right state before notifying --- coreapi/bellesip_sal/sal_op_presence.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 4c65ff3f7..89a6dbbb5 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -292,7 +292,13 @@ static belle_sip_request_t *create_presence_notify(SalOp *op){ } int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ - belle_sip_request_t* notify=create_presence_notify(op); + belle_sip_dialog_state_t state=op->dialog?belle_sip_dialog_get_state(op->dialog): BELLE_SIP_DIALOG_NULL; + belle_sip_request_t* notify=NULL; + if (state != BELLE_SIP_DIALOG_CONFIRMED) { + ms_warning("Cannot notify presence because dialog in state [%s]",belle_sip_dialog_state_to_string(state)); + return -1; + } + notify=create_presence_notify(op); 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))); From 3fda5955fd5bdef7717af044706942373a27ad0c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 9 Jul 2013 17:05:23 +0200 Subject: [PATCH 526/909] fix various crash due to // transaction --- coreapi/bellesip_sal/sal_op_events.c | 5 +++-- coreapi/bellesip_sal/sal_op_presence.c | 25 +++++++++++++++++++++---- tester/eventapi_tester.c | 5 +++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index e454ab293..2c490ce6b 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -293,7 +293,8 @@ int sal_notify(SalOp *op, const SalBody *body){ if (!op->dialog) return -1; - notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1; + if (set_event_name(op,(belle_sip_message_t*)notify)==-1){ belle_sip_object_unref(notify); return -1; @@ -309,7 +310,7 @@ int sal_notify(SalOp *op, const SalBody *body){ int sal_notify_close(SalOp *op){ belle_sip_request_t* notify; if (!op->dialog) return -1; - notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1; set_event_name(op,(belle_sip_message_t*)notify); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 89a6dbbb5..769e1740d 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -287,18 +287,29 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi static belle_sip_request_t *create_presence_notify(SalOp *op){ belle_sip_request_t* notify=belle_sip_dialog_create_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; } -int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ +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; - belle_sip_request_t* notify=NULL; if (state != BELLE_SIP_DIALOG_CONFIRMED) { - ms_warning("Cannot notify presence because dialog in state [%s]",belle_sip_dialog_state_to_string(state)); + 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))); @@ -306,7 +317,13 @@ int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ } int sal_notify_presence_close(SalOp *op){ - belle_sip_request_t* notify=create_presence_notify(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))); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 9e3e15a36..cc7a6905b 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -30,6 +30,8 @@ static const char *notify_content="blabla"; void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ CU_ASSERT_PTR_NOT_NULL_FATAL(content); CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); + LinphoneCoreManager *mgr=get_manager(lc); + mgr->stat.number_of_NotifyReceived++; } void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { @@ -124,6 +126,9 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + /*make sure marie receives first notification before terminating + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000));*/ + if (terminated_by_subscriber){ linphone_event_terminate(lev); }else{ From 9bb6ac525b5471b3215d92e81d1b201b597ce712 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 11 Jul 2013 13:36:56 +0200 Subject: [PATCH 527/909] Updated ms2 and android build to use renamed ffmepg libraries --- build/android/Android-no-neon.mk | 8 ++++---- build/android/Android.mk | 8 ++++---- .../org/linphone/core/LinphoneCoreFactoryImpl.java | 12 ++++++------ mediastreamer2 | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 39818fbf4..c1f9e7f05 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -27,10 +27,10 @@ include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - libavcodecnoneon \ - libswscale \ - libavcore \ - libavutil + liblinavcodecnoneon \ + liblinswscale \ + liblinavcore \ + liblinavutil endif LOCAL_MODULE := liblinphonenoneon diff --git a/build/android/Android.mk b/build/android/Android.mk index 0dc0bd041..645676ffc 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -27,10 +27,10 @@ include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - libavcodec \ - libswscale \ - libavcore \ - libavutil + liblinavcodec \ + liblinswscale \ + liblinavcore \ + liblinavutil endif LOCAL_MODULE := liblinphone diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index b3c638b68..e757389c9 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -40,19 +40,19 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { static { // FFMPEG (audio/video) - loadOptionalLibrary("avutil"); - loadOptionalLibrary("swscale"); - loadOptionalLibrary("avcore"); + loadOptionalLibrary("linavutil"); + loadOptionalLibrary("linswscale"); + loadOptionalLibrary("linavcore"); System.loadLibrary("neon"); if (!hasNeonInCpuFeatures()) { - boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon"); + boolean noNeonLibrariesLoaded = loadOptionalLibrary("linavcodecnoneon"); if (!noNeonLibrariesLoaded) { - loadOptionalLibrary("avcodec"); + loadOptionalLibrary("linavcodec"); } } else { - loadOptionalLibrary("avcodec"); + loadOptionalLibrary("linavcodec"); } // OPENSSL (cryptography) diff --git a/mediastreamer2 b/mediastreamer2 index 053603969..407d6591e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 05360396963de551078d3465ea8e5a8fa09c1cf2 +Subproject commit 407d6591e14bf90816b88e7615408230136b3de5 From 9582489a45b097c0ba4669669b3c2f5c8073cf43 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 11 Jul 2013 14:38:51 +0200 Subject: [PATCH 528/909] Fix android compilation --- coreapi/linphonecall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 01dbaf8db..e2a305fe5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2507,20 +2507,24 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, } MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call) { - VideoStream *vstream = call->videostream; MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; +#ifdef VIDEO_ENABLED + VideoStream *vstream = call->videostream; if (vstream != NULL) { vsize = video_stream_get_sent_video_size(vstream); } +#endif return vsize; } MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call) { - VideoStream *vstream = call->videostream; MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; +#ifdef VIDEO_ENABLED + VideoStream *vstream = call->videostream; if (vstream != NULL) { vsize = video_stream_get_received_video_size(vstream); } +#endif return vsize; } From ecaa31dc45473ed496fb641dbf04253643ebb67b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 11 Jul 2013 16:05:46 +0200 Subject: [PATCH 529/909] fix refresh of SUBCRIBEs that failed with 481 --- coreapi/bellesip_sal/sal_op_presence.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 769e1740d..7c5613731 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -62,8 +62,6 @@ static void presence_refresher_listener( const belle_sip_refresher_t* refresher, 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); - belle_sip_object_unref(op->refresher); - op->refresher=NULL; sal_subscribe_presence(op,NULL,NULL,-1); break; } @@ -273,10 +271,15 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi 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; } } + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag"); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag"); req=sal_op_build_request(op,"SUBSCRIBE"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); From 0386daaecffda23471d160218da36f3f09c80964 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 11 Jul 2013 17:45:55 +0200 Subject: [PATCH 530/909] Update ms2 submodule for HD video. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 407d6591e..7d935debb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 407d6591e14bf90816b88e7615408230136b3de5 +Subproject commit 7d935debb51a915e3405d767830806cd6a1898e6 From 89f3e2ceda901574092b14bd37a5079e9d95ed84 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Jul 2013 09:04:10 +0200 Subject: [PATCH 531/909] set callid more early, add option to disable uuid (to reduce message size) --- coreapi/bellesip_sal/sal_op_impl.c | 12 ++++++++++-- coreapi/linphonecore.c | 2 +- coreapi/offeranswer.c | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index c2a198353..b8bdeb1a1 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -205,6 +205,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req 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; _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); @@ -264,7 +265,14 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL); } - return belle_sip_client_transaction_send_request_to(client_transaction,outbound_proxy/*might be null*/); + result = belle_sip_client_transaction_send_request_to(client_transaction,outbound_proxy/*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; } @@ -519,7 +527,7 @@ bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){ salbody->size=belle_sip_header_content_length_get_content_length(clen); return TRUE; } - memset(salbody,0,sizeof(salbody)); + memset(salbody,0,sizeof(SalBody)); return FALSE; } void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 93b2e5a46..28be12be3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1230,7 +1230,7 @@ static void misc_config_read (LinphoneCore *lc) { char tmp[64]; sal_create_uuid(lc->sal,tmp,sizeof(tmp)); lp_config_set_string(config,"misc","uuid",tmp); - }else + }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/ sal_set_uuid(lc->sal, uuid); } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index c07e6e381..42d856310 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -40,7 +40,8 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; /* the compare between G729 and G729A is for some stupid uncompliant phone*/ - if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0 || + if ( pt->mime_type && refpt->mime_type && + (strcasecmp(pt->mime_type,refpt->mime_type)==0 || (strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) && pt->clock_rate==refpt->clock_rate){ candidate=pt; From afff48e4e212e776cf3d079471721c8f25c8b6aa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Jul 2013 21:58:57 +0200 Subject: [PATCH 532/909] update NEWS --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 6a7106c6d..a85eae026 100644 --- a/NEWS +++ b/NEWS @@ -2,8 +2,8 @@ linphone-3.7...?? * multiple SIP transports simualtaneously now allowed * IP dual stack: can use IPv6 and IPv4 simultaneously * fully asynchronous behavior: no more lengthly DNS or connections - * +sip.instance parameter (RFC???) - * alias parameter (RFC????) + * +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) From d37169c73faa186c41eaf8aa397c3b55730123a9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 15 Jul 2013 09:56:45 +0200 Subject: [PATCH 533/909] update ms2 (recv packet bufsize bugfix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 7d935debb..0bf7097df 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7d935debb51a915e3405d767830806cd6a1898e6 +Subproject commit 0bf7097dfee8ebaaf75b5b18517348397dc6536a From 119d05ef8a548aa96f503a787d13e39d4a565efc Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 16 Jul 2013 14:16:44 +0200 Subject: [PATCH 534/909] Test alternate name and wildcard certs. + fix get_suite --- configure.ac | 3 - mediastreamer2 | 2 +- oRTP | 2 +- tester/certificates/agent.pem | 101 ++++++++++++++++++++++++++++++++++ tester/liblinphone_tester.c | 10 +--- tester/pauline_alt_rc | 42 ++++++++++++++ tester/pauline_wild_rc | 42 ++++++++++++++ tester/register_tester.c | 33 +++++++++++ 8 files changed, 223 insertions(+), 12 deletions(-) create mode 100644 tester/pauline_alt_rc create mode 100644 tester/pauline_wild_rc diff --git a/configure.ac b/configure.ac index 9160f00e9..a4f2242bf 100644 --- a/configure.ac +++ b/configure.ac @@ -784,9 +784,6 @@ AM_CONDITIONAL([BUILD_CUNIT_TESTS], [test x$found_cunit = xyes && test x$tests_e 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]) diff --git a/mediastreamer2 b/mediastreamer2 index 0bf7097df..43b68b22c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0bf7097dfee8ebaaf75b5b18517348397dc6536a +Subproject commit 43b68b22cf8d0d1b0b5a064516d35899e5527358 diff --git a/oRTP b/oRTP index 49b16793b..7c2805c2e 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 49b16793b9ef8251a4c42434b57387c6e3c6d251 +Subproject commit 7c2805c2e2c1edadf9e9efe313d98f06c4c3614a diff --git a/tester/certificates/agent.pem b/tester/certificates/agent.pem index b2a0c5f19..e3d88e21e 100644 --- a/tester/certificates/agent.pem +++ b/tester/certificates/agent.pem @@ -34,3 +34,104 @@ uAXrftoKrsvTysRU7Lr+N5W9FPoWqBh35Kx5SnRN3LYf0OIaJ5hufC8v+SOIJ6Me QpKMlMY05Fz7R2aXkSS3Ie1GUJNKnWmos2uRFIMgIpFpr2VAZqVlsjC6J7SKIdGw JvmtefxJrjl8Tpzw5uRNC58= -----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAxx5TlbzfmfCneIzofE09/4lr+hQk2ihrBAgZi+kVto5o/oW8 +xtvUfek6dOcF8lK6Ss6AvTQH/4SrK8Ico72eOaxTXjBxpdZuEvftmowawUqvr8DV +dwsleFcp7pmdNarG6WxW9d690ixE4TKpvSYAzoVv2z/0PxjGLNTALcfav8tCvjEv +804Pw4NuSmW6wjw+kRKTz/l4wYNlVXsAXt30xAuELkbHEVmcFBL5Al4CsgwF0su3 +oA8/IYE+eOIFu6ANZa8h2t9yHZSDlAwhe0yPRt0NDzp3RbsaG0oPudkmP3ithTJz +5Pmf7Oq46Ko2Wk3GfxykaoYpvjBTahkWOUoFowIDAQABAoIBABMZ/qy7rLuo0XgI +FHlwM4VjGn+oFQz0maeOW10HpDSaHspj7AMrrYvSpu/2BaUEeKiafNEpv6ashHsz +KOowU5B2zpyXix98nZymOh38WMi4MHhsyE2ePR75RaWFCQbP9jsIUKNPlegmpQjx +gkUJ80PcmyluTjELYF+GnVUG+h4x5y2RiUiQr+zTUXGTBDny3jKdtMrmctqkG9hQ +cgIV/RG+CaFGxdkTShHEAhpd+g0DIivHZctwrF7Q1WFJBj3zChe223a6JdF2ke4c +Rr79PkHkCWGwv6Rp/95XUnQKJ8/FPTNtFoGzR6bhKmWqh3q2qfZKRKtXw2LBwFJp +f8U5++kCgYEA8ieuaVqKmCZwm/WRWeimG+UHs+EtHLgmj18ylD1jKQaRetSDcZ4m +6ounfrxyBL7DBDym/CeWbq9OI9cQB2RGLK3To6vj1UbRQ6tKiRzDq933sYZoEcTs +kBzexW8oUsclAvqYbqEjxEoEQrgHTWvjuHYiTrNlOAo+eL0VV6trZMUCgYEA0oC8 +40I8quYILtlkSYT3+iMRX4Vy1BzzMOkzRrA9jFoJZIxcOnWitJWmfBcXgOckt9ka +XchsxOcYbNa9CuI7YKrJ5SNP9cjxcxsd/gieQXcN3J/nebFwlsQFN1e8mZIZj7ik +nDf+r0lyuighDR7dLjR00a39csLCx6dH0amb90cCgYB+9jEqya7q0RSvoJQh2Knm +7DEardASQ7br6tTBBmKMKwZxqSR1mJ780FX0S+dX95CWExrWEAd+ZumIPwUHaxqj +6EuTf9cHhobHfPKqautonAt3B2pfDqmdcZWXXI1+wSz1n9/1+QSgsNIFDSm+/Pc7 +Sqz4KHTEahKRCUo8WgMHpQKBgQCXeFdy2Bi7iKbev0Mwu+OMNGut5mLISsSbr1Jc +TTkcozUbCvzafAdGFmEj7aHV+X0sZaZZUX0i+n9S4fpJuJytZHe+z/gbjipff2XH +hAAMb1SkKtPvd0Ti185BEnr9rmmCR4T7fDdhfmJ1naaawFi7hLeCocY8K/TooXBG +Z9t4xQKBgQDCqZ5Gumy+pvyUqLXtgrCmWlbr03ONBKb9n662thWeBWpCKb2e0RUA +oxTZvVsTQz88Ageoh55QHIe85//iT2wDtjUFcc80aoWDDhQuwxnu7jtEyj1wytl9 +SIsjG4JDTK1tBAVZFxyS5sMLZ2nonzynAyHPN0j1UCHF2T2Hk7/vEQ== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIEFzCCA4CgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNzE1MTQzNDQ3WhcN +MTYwNzE0MTQzNDQ3WjCBnTELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEi +MCAGA1UECgwZQmVsbGVkb25uZSBDb21tdW5pY2F0aW9uczEMMAoGA1UECwwDTEFC +MRUwEwYDVQQDDAx1c2VsZXNzLm5hbWUxNDAyBgkqhkiG9w0BCQEWJWNvbnRhY3RA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDHHlOVvN+Z8Kd4jOh8TT3/iWv6FCTaKGsECBmL6RW2jmj+ +hbzG29R96Tp05wXyUrpKzoC9NAf/hKsrwhyjvZ45rFNeMHGl1m4S9+2ajBrBSq+v +wNV3CyV4VynumZ01qsbpbFb13r3SLEThMqm9JgDOhW/bP/Q/GMYs1MAtx9q/y0K+ +MS/zTg/Dg25KZbrCPD6REpPP+XjBg2VVewBe3fTEC4QuRscRWZwUEvkCXgKyDAXS +y7egDz8hgT544gW7oA1lryHa33IdlIOUDCF7TI9G3Q0POndFuxobSg+52SY/eK2F +MnPk+Z/s6rjoqjZaTcZ/HKRqhim+MFNqGRY5SgWjAgMBAAGjgcIwgb8wCQYDVR0T +BAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh +dGUwHQYDVR0OBBYEFFTLqxYKaMQ+dgVPEwvjWt0QWh2uMB8GA1UdIwQYMBaAFAZf +XccWr2L4LW5xA4ig1h0rBH+6MAsGA1UdDwQEAwIF4DA3BgNVHREEMDAughVhbHRu +YW1lMS5saW5waG9uZS5vcmeCFWFsdG5hbWUyLmxpbnBob25lLm9yZzANBgkqhkiG +9w0BAQUFAAOBgQBZ8yk7MMp+wyiEH/4HF/MTobAmNJxgnVGvz3lnGGNXCrE9hJiA +xNdh0jfQfLMVJN5MtkpcM6Md9wowXkIMakpDIiTwnl+ve6GPOypZv2TXrm68sYid +SXlvHqN5G12HMUP577NNQxgpod6+d0jW6oPYWx1a7kCa8hOlKTRvajMyjQ== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAxGYHUVdxtkJCtFbaFd31aflHq7px9Yz/QhJUuivf30UNfgwT +k7n8UQG4G7F+LXno04uNR0B4mPPLRcfibLCKzDgMwHKReqnwtS35r2Pvfva3vvdB +ZOA7HkFIEpcp8R8XxK3Lcmcn1yYAravYKawM6QwkQv1FdM0TeRNTXXSqc4/Ty1Sd +WjoJxyEbGb8N44MRIfi6fePYlpKKI7/nQ8Y+E1f87OhOcBV+33b0hBXDLBY9XqsR +7JaZDpwlMBRsTTFU6+ApF4q4RmGFoACA2ZO4GkE8OdIbRLhPa8DPVzfo52sJhmSM +gPw8JN3TRYxbmEF+KhVejdmGxtAKNEBzEwbnwwIDAQABAoIBAQCbhdP7pMxGMLhT +yIcQU+C4F4+avJzrfsjP0GZJut6gFjV2ACgsjlXw6/SX8XjimCw4AMVSjAozzLLG +Ql/aA/8VcrkeWFs9kH8tagfTzMZlewfMcE3XjP0jmzxwhEXRS/btZ1a49FkHNW/K +F0+oyDa9AUFhzuAGezMVaKlWU0F7GiGciGWRTUqt9CxtbagVdCo6Oilo1pEVpf8S +aEM0Eyl7VnkjPBWZ/wZwEhetvrFl/Wb0k31d0TkmcNpIGHd+nAbBhoJkZ0MISC64 +TmJaDW982xIV30FlGmm/tKGO4a5xTEwlw5E3k8ReubLGS8RkHLXNZKmxQK5fA1BJ +mcwa5ue5AoGBAOg40SDdLYzL8fpASBVXi15s3muAOODO9hVGzIUp/2OVxQ6SGK2P +tEI2UJwjKJtgVHgs/dN4uHhmYN+n6DPOWMt0x7UigFlskr0qjKfAEfi1hb6S1ZPR +hCWPe1NnOMKkNnasMVETkfS7FKxQ4DfhU+I0geXfKXCY7HZZRz/4Fg+XAoGBANiC +LlCzeTzkdY1+Es1MyBApyZCHWUK1aJbHhA5BYr+aojIl9t/962ioBcFQ3j4krq4x +OcQqcbu7lUSR/YdDSLkRxMH7AEfbKwwJUa4NrxAjSRkvbWVyNVGLa5B9eXj9zS3Q +AV23BKwjuWOmSCg70EsxeSyKEwvdvdrGfKWMfW61AoGAIC5PfNhpyYsxu1ZRJvP8 +0lcP86HPQAguPgCTsxiA1dIZfs1sMhEqD8rrHNgadn3A9u51NmsSVU0Ku7PPD+7W +i0thqY5gbwQGycQtvcl2NBsjr6c1hciRIYtiscoqKX8MNSHjq7KklV+fm8mRaO0G +7OAN6EcmvP3UNwpkP08n730CgYEAhtcM4VXle/cM/0I1k4buUqKz1j91aAZzTPSV +Wgt+5LX5riHWz0nlAxkh/HPQ9gMCh5pAz9tfWfxJyprhuww8joZydB1O33GwLZ7g +L/Z1wSc4r2bKSxQGAPND2olKzf/DeXTCZQtG7a6SF23IIsadwzbcsNCNbCZ9x3M2 +ziPhOsECgYB9BU7vYn5LMTtA7FIx+Fv//aepoBT/+pC8AUCA7EX5vEIf3cxEwesm +CkHknaKWlxhlK379OKQryYrUsRxjxwFd0DNK5tT+jx6m8VVKe1Bz/8uYZDNCtJr0 +zoqngR61r5jCYZLYcggcTimVoHMJXxcdsReBX8P7u3JNU2CulGvX7w== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIID6DCCA1GgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNzE1MTQ0MDM4WhcN +MTYwNzE0MTQ0MDM4WjCBpzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEi +MCAGA1UECgwZQmVsbGVkb25uZSBDb21tdW5pY2F0aW9uczEMMAoGA1UECwwDTEFC +MR8wHQYDVQQDDBYqLndpbGRjYXJkLmxpbnBob25lLmZyMTQwMgYJKoZIhvcNAQkB +FiVjb250YWN0QGJlbGxlZG9ubmUtY29tbXVuaWNhdGlvbnMuY29tMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxGYHUVdxtkJCtFbaFd31aflHq7px9Yz/ +QhJUuivf30UNfgwTk7n8UQG4G7F+LXno04uNR0B4mPPLRcfibLCKzDgMwHKReqnw +tS35r2Pvfva3vvdBZOA7HkFIEpcp8R8XxK3Lcmcn1yYAravYKawM6QwkQv1FdM0T +eRNTXXSqc4/Ty1SdWjoJxyEbGb8N44MRIfi6fePYlpKKI7/nQ8Y+E1f87OhOcBV+ +33b0hBXDLBY9XqsR7JaZDpwlMBRsTTFU6+ApF4q4RmGFoACA2ZO4GkE8OdIbRLhP +a8DPVzfo52sJhmSMgPw8JN3TRYxbmEF+KhVejdmGxtAKNEBzEwbnwwIDAQABo4GJ +MIGGMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk +IENlcnRpZmljYXRlMB0GA1UdDgQWBBRJAgxmoZo5VCDjeR/tR5XZtE2NtzAfBgNV +HSMEGDAWgBQGX13HFq9i+C1ucQOIoNYdKwR/ujALBgNVHQ8EBAMCBeAwDQYJKoZI +hvcNAQEFBQADgYEAXxtgbwO3/ilkEx3jW8wlBN4dg++EBCsw0RkhhiNyWLwF7OOf +xttppVNF4HW3xiOAs7FUSIgiNwHd+j8N3LpJxBpd7ePSaKy/U1EWoj38u8q5Q1gU +d3Lu+D0XaQvZyVW7xoYwTLa9CmRItow4GIkExoUhyrurbOmJ/3q9/SRGWF8= +-----END CERTIFICATE----- diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 466ef1278..25e91aa1e 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -179,7 +179,6 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f int proxy_count=check_for_proxies?(rc_file?1:0):0; int retry=0; - memset(mgr,0,sizeof(LinphoneCoreManager)); 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; @@ -334,18 +333,17 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) run_test_suite(test_suite[i]); } -#if HAVE_CU_GET_SUITE if (suite_name){ CU_pSuite suite; CU_basic_set_mode(CU_BRM_VERBOSE); - suite=CU_get_suite(suite_name); + suite=CU_get_suite_by_name(suite_name, CU_get_registry()); if (test_name) { CU_pTest test=CU_get_test_by_name(test_name, suite); - CU_basic_run_test(suite, test); + CU_ErrorCode err= CU_basic_run_test(suite, test); + if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); } else CU_basic_run_suite(suite); } else -#endif { #if HAVE_CU_CURSES if (curses) { @@ -413,10 +411,8 @@ void helper(const char *name) { "\t\t\t--config \n" "\t\t\t--domain \n" "\t\t\t--auth-domain \n" -#if HAVE_CU_GET_SUITE "\t\t\t--suite \n" "\t\t\t--test \n" -#endif #if HAVE_CU_CURSES "\t\t\t--curses\n" #endif diff --git a/tester/pauline_alt_rc b/tester/pauline_alt_rc new file mode 100644 index 000000000..3a7114d4f --- /dev/null +++ b/tester/pauline_alt_rc @@ -0,0 +1,42 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm="altname2.linphone.org" + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_route=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@altname2.linphone.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + +[rtp] +audio_rtp_port=8090 +video_rtp_port=8092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/pauline_wild_rc b/tester/pauline_wild_rc new file mode 100644 index 000000000..a9b07ed93 --- /dev/null +++ b/tester/pauline_wild_rc @@ -0,0 +1,42 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm="sip.wildcard.linphone.org" + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_route=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.wildcard.linphone.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + +[rtp] +audio_rtp_port=8090 +video_rtp_port=8092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/register_tester.c b/tester/register_tester.c index 9108368f1..317c8d5e3 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -204,6 +204,7 @@ static void simple_tls_register(){ linphone_core_manager_destroy(lcm); } + static void simple_authenticated_register(){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); @@ -464,11 +465,43 @@ static void tls_with_non_tls_server(){ linphone_core_manager_destroy(mgr); } +static void tls_alt_name_register(){ + LinphoneCoreManager* mgr; + LinphoneCore *lc; + char rootcapath[256]; + + mgr=linphone_core_manager_new2("pauline_alt_rc",FALSE); + lc=mgr->lc; + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); + linphone_core_destroy(mgr->lc); +} + +static void tls_wildcard_register(){ + LinphoneCoreManager* mgr; + LinphoneCore *lc; + char rootcapath[256]; + + mgr=linphone_core_manager_new2("pauline_wild_rc",FALSE); + lc=mgr->lc; + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); + linphone_core_destroy(mgr->lc); +} + test_t register_tests[] = { { "Simple register", simple_register }, { "TCP register", simple_tcp_register }, { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, { "TLS register", simple_tls_register }, + { "TLS register with alt. name certificate", tls_alt_name_register }, + { "TLS register with wildcard certificate", tls_wildcard_register }, { "TLS certificate not verified",tls_certificate_failure}, { "TLS with non tls server",tls_with_non_tls_server}, { "Simple authenticated register", simple_authenticated_register }, From 61f0f0bcd0c55c67b75af09df03cd3d20f593cbc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Jul 2013 14:45:21 +0200 Subject: [PATCH 535/909] prohibit resuming of two calls simultaneously. --- coreapi/linphonecore.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 28be12be3..60313fbc2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3488,10 +3488,12 @@ 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."); @@ -3518,6 +3520,10 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) return -1; } if (call->params.in_conference==FALSE){ + if (linphone_core_sound_resources_locked(lc)){ + ms_warning("Cannot resume call %p because another call is locking the sound resources.",the_call); + return -1; + } linphone_core_preempt_sound_resources(lc); ms_message("Resuming call %p",call); } @@ -3541,7 +3547,9 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) if(sal_call_update(call->op,subject) != 0){ return -1; } - linphone_call_set_state (call,LinphoneCallResuming,"Resuming"); + linphone_call_set_state(call,LinphoneCallResuming,"Resuming"); + if (call->params.in_conference==FALSE) + lc->current_call=call; snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call)); if (lc->vtable.display_status) lc->vtable.display_status(lc,temp); @@ -5928,10 +5936,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: @@ -5941,6 +5948,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; From 7a6d1c2946925520c30c8108acfb58631a7fc624 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Jul 2013 19:29:56 +0200 Subject: [PATCH 536/909] better test in case of io error --- coreapi/bellesip_sal/sal_impl.c | 7 ++++ coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_impl.c | 1 + include/sal/sal.h | 3 ++ tester/register_tester.c | 61 ++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index e147efd32..e2052dc15 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -440,6 +440,7 @@ Sal * sal_init(){ belle_sip_provider_add_sip_listener(sal->prov,sal->listener); sal->tls_verify=TRUE; sal->tls_verify_cn=TRUE; + sal->refresher_retry_after=60000; /*default value in ms*/ return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ @@ -872,3 +873,9 @@ belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_req belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); 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; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 2848e97ac..6826d445e 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -44,6 +44,7 @@ struct Sal{ bool_t tls_verify; bool_t tls_verify_cn; bool_t use_dates; + int refresher_retry_after; /*retry after value for refresher*/ }; typedef enum SalOpState { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index b8bdeb1a1..a0e58d726 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -451,6 +451,7 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { belle_sip_refresher_enable_nat_helper(op->refresher,op->base.root->nat_helper_enabled); belle_sip_refresher_set_listener(op->refresher,listener,op); + belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); return 0; } else { return -1; diff --git a/include/sal/sal.h b/include/sal/sal.h index 9cbaba73e..a52757ce8 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -606,6 +606,9 @@ void __sal_op_free(SalOp *b); 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); +/*refresher retry after value in ms*/ +LINPHONE_PUBLIC void sal_set_refresher_retry_after(Sal *sal,int value); +LINPHONE_PUBLIC int sal_get_refresher_retry_after(const Sal *sal); /*enable contact fixing*/ void sal_nat_helper_enable(Sal *sal,bool_t enable); bool_t sal_nat_helper_enabled(Sal *sal); diff --git a/tester/register_tester.c b/tester/register_tester.c index 317c8d5e3..66263ab07 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -383,6 +383,65 @@ static void io_recv_error(){ linphone_core_manager_destroy(mgr); } +static void io_recv_error_retry_immediatly(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + + + mgr=configure_lcm(); + lc=mgr->lc; + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + sal_set_recv_error(lc->sal, 0); + + CU_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + sal_set_recv_error(lc->sal, 1); /*reset*/ + + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*(register_ok-number_of_udp_proxy))); + + linphone_core_manager_destroy(mgr); +} + +static void io_recv_error_late_recovery(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + MSList* lcs; + + mgr=linphone_core_manager_new2( "multi_account_lrc",FALSE); /*to make sure iterates are not call yet*/ + lc=mgr->lc; + sal_set_refresher_retry_after(lc->sal,1000); + counters=&mgr->stat; + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)))); + + + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + /*simulate a general socket error*/ + sal_set_recv_error(lc->sal, 0); + sal_set_send_error(lc->sal, -1); + + CU_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + + CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(lc->sal)+1000)); + + sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_send_error(lc->sal, 0); + + CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy +register_ok,sal_get_refresher_retry_after(lc->sal)+1000)); + + linphone_core_manager_destroy(mgr); +} + static void io_recv_error_without_active_register(){ LinphoneCoreManager *mgr; LinphoneCore* lc; @@ -516,6 +575,8 @@ test_t register_tests[] = { { "Transport change", transport_change }, { "Network state change", network_state_change }, { "Io recv error", io_recv_error }, + { "Io recv error with recovery", io_recv_error_retry_immediatly}, + { "Io recv error with late recovery", io_recv_error_late_recovery}, { "Io recv error without active registration", io_recv_error_without_active_register} }; From 60334f9d213173554dcc8edaa7aa6309039b6c0b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Jul 2013 22:10:57 +0200 Subject: [PATCH 537/909] only repport call error for negative answer to INVITE transaction --- coreapi/bellesip_sal/sal_op_call.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index dc3489aca..af40df207 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -232,10 +232,10 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->base.root->callbacks.call_accepted(op); /*INVITE*/ op->state=SalOpStateActive; - } else { - if (code >= 300){ - call_set_error(op,response); - } + } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ + call_set_error(op,response); + } else { + /*ignoring*/ } break; case SalOpStateTerminating: From ddf2dcc409428eeee94bef978cadfdb7758a06cc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 17 Jul 2013 14:18:03 +0200 Subject: [PATCH 538/909] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index aebfe443e..407d6591e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit aebfe443e91aa1e1c1e32b2410cc1d9a5db629c1 +Subproject commit 407d6591e14bf90816b88e7615408230136b3de5 From 53f7cedf0047ee73d5f0d2c823dfbe1297322cab Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 11 Jul 2013 13:36:56 +0200 Subject: [PATCH 539/909] Updated ms2 and android build to use renamed ffmepg libraries --- build/android/Android-no-neon.mk | 8 ++++---- build/android/Android.mk | 8 ++++---- .../org/linphone/core/LinphoneCoreFactoryImpl.java | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 39818fbf4..c1f9e7f05 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -27,10 +27,10 @@ include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - libavcodecnoneon \ - libswscale \ - libavcore \ - libavutil + liblinavcodecnoneon \ + liblinswscale \ + liblinavcore \ + liblinavutil endif LOCAL_MODULE := liblinphonenoneon diff --git a/build/android/Android.mk b/build/android/Android.mk index 0dc0bd041..645676ffc 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -27,10 +27,10 @@ include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - libavcodec \ - libswscale \ - libavcore \ - libavutil + liblinavcodec \ + liblinswscale \ + liblinavcore \ + liblinavutil endif LOCAL_MODULE := liblinphone diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 8cedba445..a8f9754ce 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -40,19 +40,19 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { static { // FFMPEG (audio/video) - loadOptionalLibrary("avutil"); - loadOptionalLibrary("swscale"); - loadOptionalLibrary("avcore"); + loadOptionalLibrary("linavutil"); + loadOptionalLibrary("linswscale"); + loadOptionalLibrary("linavcore"); System.loadLibrary("neon"); if (!hasNeonInCpuFeatures()) { - boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon"); + boolean noNeonLibrariesLoaded = loadOptionalLibrary("linavcodecnoneon"); if (!noNeonLibrariesLoaded) { - loadOptionalLibrary("avcodec"); + loadOptionalLibrary("linavcodec"); } } else { - loadOptionalLibrary("avcodec"); + loadOptionalLibrary("linavcodec"); } // OPENSSL (cryptography) From 60c1b0a4ce88fe816c1530faa6b688c9a36aa668 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 18 Jul 2013 14:48:20 +0200 Subject: [PATCH 540/909] Some changes to only use API allowed for WP8 applications. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 8 ++++---- build/vsx/libxml2/libxml2/libxml2.vcxproj | 8 ++++---- build/vsx/libxml2/libxml2/libxml2_port.h | 12 +++++++++++- build/vsx/libxml2/libxml2/xmlversion.h | 2 +- coreapi/linphonecore.c | 18 +++--------------- coreapi/misc.c | 6 +----- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index fca4e0fa7..25e1543e4 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -67,7 +67,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) false Default NotUsing @@ -91,7 +91,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) true true Default @@ -117,7 +117,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) false Default NotUsing @@ -147,7 +147,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) true true Default diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj index 15fd066c1..fb873bf4e 100644 --- a/build/vsx/libxml2/libxml2/libxml2.vcxproj +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -67,7 +67,7 @@ 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;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false Default @@ -96,7 +96,7 @@ Level4 MaxSpeed $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true true @@ -126,7 +126,7 @@ Level4 $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) + _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED false Default @@ -155,7 +155,7 @@ Level4 MaxSpeed $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;%(PreprocessorDefinitions) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) LIBXML_MODULES_ENABLED true true diff --git a/build/vsx/libxml2/libxml2/libxml2_port.h b/build/vsx/libxml2/libxml2/libxml2_port.h index 761d1ae69..bde826374 100644 --- a/build/vsx/libxml2/libxml2/libxml2_port.h +++ b/build/vsx/libxml2/libxml2/libxml2_port.h @@ -2,8 +2,18 @@ #ifndef LIBXML2_PORT_H #define LIBXML2_PORT_H -#define CreateMutex(a, b, c) CreateMutexEx(a, c, ((b) ? CREATE_MUTEX_INITIAL_OWNER : 0), 0) +#define CreateMutex(a, b, c) CreateMutexExW(a, c, ((b) ? CREATE_MUTEX_INITIAL_OWNER : 0), 0) #define GetVersionEx(osvi) (((osvi)->dwPlatformId = 0) != 0) +#define InitializeCriticalSection(cs) InitializeCriticalSectionEx(cs, 0, 0) + +#define WaitForSingleObject(hHandle, dwMilliseconds) WaitForSingleObjectEx(hHandle, dwMilliseconds, 0) + +#define Sleep(ms) { \ + HANDLE sleepEvent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); \ + if (!sleepEvent) return; \ + WaitForSingleObjectEx(sleepEvent, ms, FALSE); \ +} + #endif /* LIBXML2_PORT_H */ diff --git a/build/vsx/libxml2/libxml2/xmlversion.h b/build/vsx/libxml2/libxml2/xmlversion.h index f918d354d..40c192eba 100644 --- a/build/vsx/libxml2/libxml2/xmlversion.h +++ b/build/vsx/libxml2/libxml2/xmlversion.h @@ -219,7 +219,7 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(int version); * * Whether the Catalog support is configured in */ -#if 1 +#if 0 #define LIBXML_CATALOG_ENABLED #endif diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 60313fbc2..2ef871b29 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5254,11 +5254,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); } } @@ -5342,11 +5338,7 @@ void sip_config_uninit(LinphoneCore *lc) LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); still_registered|=linphone_proxy_config_is_registered(cfg); } -#ifndef WIN32 - usleep(100000); -#else - Sleep(100); -#endif + ms_usleep(100000); } if (i>=20) ms_warning("Cannot complete unregistration, giving up"); ms_list_for_each(config->proxies,(void (*)(void*)) linphone_proxy_config_destroy); @@ -5490,11 +5482,7 @@ static void linphone_core_uninit(LinphoneCore *lc) LinphoneCall *the_call = lc->calls->data; linphone_core_terminate_call(lc,the_call); linphone_core_iterate(lc); -#ifdef WIN32 - Sleep(50000); -#else - usleep(50000); -#endif + ms_usleep(50000); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 272d37960..203d0f461 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -535,11 +535,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE); } } -#ifdef WIN32 - Sleep(10); -#else - usleep(10000); -#endif + ms_usleep(10000); if (recvStunResponse(sock1,ac->addr, &ac->port,&id)>0){ From fe7f78c52eae0859fe26503db35a33cfc466363d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 19 Jul 2013 12:05:11 +0200 Subject: [PATCH 541/909] Fix compilation on Windows. --- coreapi/linphonecall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e2a305fe5..fc5ad5428 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2507,9 +2507,11 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, } MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call) { - MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; + MSVideoSize vsize; + VideoStream *vstream; + MS_VIDEO_SIZE_ASSIGN(vsize, UNKNOWN); #ifdef VIDEO_ENABLED - VideoStream *vstream = call->videostream; + vstream = call->videostream; if (vstream != NULL) { vsize = video_stream_get_sent_video_size(vstream); } @@ -2518,9 +2520,11 @@ MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call) { } MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call) { - MSVideoSize vsize = MS_VIDEO_SIZE_UNKNOWN; + MSVideoSize vsize; + VideoStream *vstream; + MS_VIDEO_SIZE_ASSIGN(vsize, UNKNOWN); #ifdef VIDEO_ENABLED - VideoStream *vstream = call->videostream; + vstream = call->videostream; if (vstream != NULL) { vsize = video_stream_get_received_video_size(vstream); } From 37ca2d40dbc2b262e137fc3b25a8154ab191b8ba Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 23 Jul 2013 16:23:03 +0200 Subject: [PATCH 542/909] make sure to delete ongoing dialog if any in case of 481 received to a subscription --- coreapi/bellesip_sal/sal_op_presence.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 7c5613731..b0799232c 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -62,6 +62,11 @@ static void presence_refresher_listener( const belle_sip_refresher_t* refresher, 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; + } sal_subscribe_presence(op,NULL,NULL,-1); break; } From 9702eeb2816bbf60831bea6bf9e59a57fdad9c15 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 23 Jul 2013 20:35:59 +0200 Subject: [PATCH 543/909] wait until linphone friend proxy config is registered before sending first subscribe --- coreapi/friend.c | 21 +++++++++++++++++++-- coreapi/linphonecore.c | 2 +- coreapi/private.h | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 5437a5a03..7f77e9b94 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -449,11 +449,28 @@ void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ void linphone_core_send_initial_subscribes(LinphoneCore *lc){ const MSList *elem; if (lc->initial_subscribes_sent) return; + lc->initial_subscribes_sent=TRUE; /*set to true and see if looping on friends will change this status*/ for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *f=(LinphoneFriend*)elem->data; - linphone_friend_apply(f,lc); + LinphoneProxyConfig* cfg; + if (!f->initial_subscribes_sent) { + lc->initial_subscribes_sent=FALSE; /*at least 1 was not sent */ + if ((cfg=linphone_core_lookup_known_proxy(f->lc,linphone_friend_get_address(f)))) { + /*check if already registered*/ + if (linphone_proxy_config_get_state(cfg) != LinphoneRegistrationOk) + continue; /*skip this friend because not registered yet*/ + else { + char* lf_string = linphone_address_as_string(linphone_friend_get_address(f)); + ms_message("Identity [%s] registered, we can now subscribe to [%s]",linphone_proxy_config_get_identity(cfg),lf_string); + ms_free(lf_string); + } + } + linphone_friend_apply(f,lc); + f->initial_subscribes_sent=TRUE; + } + } - lc->initial_subscribes_sent=TRUE; + } void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2ef871b29..888b07dda 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2414,7 +2414,7 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L } end: if (found_cfg!=NULL && found_cfg!=default_cfg){ - ms_message("Overriding default proxy setting for this call/message/subscribe operation."); + ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); }else found_cfg=default_cfg; return found_cfg; diff --git a/coreapi/private.h b/coreapi/private.h index 71cd69136..c6ef374f9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -439,6 +439,7 @@ 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*/ }; From 3051c9bdad1974f0c7e4a74620f363166a7ea557 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 23 Jul 2013 21:10:14 +0200 Subject: [PATCH 544/909] add LinphoneReasonDoNotDisturb --- coreapi/linphonecore.c | 5 +++++ coreapi/linphonecore.h | 4 +++- coreapi/misc.c | 4 +++- java/common/org/linphone/core/Reason.java | 14 +++++++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 888b07dda..5a76fbc58 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3357,6 +3357,9 @@ int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneRe case LinphoneReasonBusy: sal_reason=SalReasonBusy; break; + case LinphoneReasonDoNotDistrub: + sal_reason = SalReasonDoNotDisturb; + break; default: ms_error("linphone_core_decline_call(): unsupported reason %s",linphone_reason_to_string(reason)); return -1; @@ -5782,6 +5785,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Incompatible media capabilities"; case LinphoneReasonIOError: return "IO error"; + case LinphoneReasonDoNotDistrub: + return "Do not distrub"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a48ec44b8..bca080aa3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -133,7 +133,9 @@ enum _LinphoneReason{ LinphoneReasonNotAnswered, /** Date: Tue, 23 Jul 2013 21:18:28 +0200 Subject: [PATCH 545/909] fix typo in dnd reason --- coreapi/linphonecore.c | 21 +++------------------ coreapi/linphonecore.h | 2 +- coreapi/misc.c | 4 ++-- java/common/org/linphone/core/Reason.java | 2 +- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5a76fbc58..8c950450b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3345,27 +3345,12 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) * @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy **/ int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason){ - SalReason sal_reason=SalReasonUnknown; if (call->state!=LinphoneCallIncomingReceived && call->state!=LinphoneCallIncomingEarlyMedia){ ms_error("linphone_core_decline_call(): Cannot decline a call that is in state %s",linphone_call_state_to_string(call->state)); return -1; } - switch(reason){ - case LinphoneReasonDeclined: - sal_reason=SalReasonDeclined; - break; - case LinphoneReasonBusy: - sal_reason=SalReasonBusy; - break; - case LinphoneReasonDoNotDistrub: - sal_reason = SalReasonDoNotDisturb; - 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; } @@ -5785,7 +5770,7 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Incompatible media capabilities"; case LinphoneReasonIOError: return "IO error"; - case LinphoneReasonDoNotDistrub: + case LinphoneReasonDoNotDisturb: return "Do not distrub"; } return "unknown error"; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index bca080aa3..ea5db6719 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -134,7 +134,7 @@ enum _LinphoneReason{ LinphoneReasonBusy, /** Date: Wed, 24 Jul 2013 22:54:10 +0200 Subject: [PATCH 546/909] make sure lf->initial_subscribes_sent reset when subscription is invalidated --- coreapi/friend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/friend.c b/coreapi/friend.c index 7f77e9b94..6d1d830e4 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -250,6 +250,7 @@ static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ lf->outsub=NULL; lf->subscribe_active=FALSE; } + lf->initial_subscribes_sent=FALSE; } void linphone_friend_close_subscriptions(LinphoneFriend *lf){ From c76dab4120c4c3a4b01455578cd443439db92282 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 25 Jul 2013 10:25:42 +0200 Subject: [PATCH 547/909] make sure vfu request creation failure does not lead for a crash --- coreapi/bellesip_sal/sal_op_call.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index af40df207..f95f8b884 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -759,10 +759,16 @@ void sal_call_send_vfu_request(SalOp *op){ 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_request(op->dialog,"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); - sal_op_send_request(op,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 From 15d4773e7777077c81180a497e07a6c16aca07d9 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 26 Jul 2013 12:06:54 +0200 Subject: [PATCH 548/909] put version number to 3.6.99 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a4f2242bf..e5cab9a09 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.6.1],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.6.99],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) From eb1f6822d7497a6ed5708878e979603ee89ca18c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 26 Jul 2013 22:09:16 +0200 Subject: [PATCH 549/909] fix crash when receiving a NOTIFY for a closed subscription. --- coreapi/bellesip_sal/sal_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index e2052dc15..6ddecefd8 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -181,7 +181,7 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); - if (op==NULL && op->state==SalOpStateTerminated){ + if (op==NULL || op->state==SalOpStateTerminated){ ms_warning("Receiving request for null or terminated op [%p], ignored",op); return; } From 2454b37eb46327d7c232e5d394a83ebbf0f0d1c8 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 26 Jul 2013 23:48:44 +0200 Subject: [PATCH 550/909] reset contact ip/port in case of 481 answer to a subscribe --- coreapi/bellesip_sal/sal_op_presence.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index b0799232c..cee7b0093 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -59,7 +59,8 @@ static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog static void presence_refresher_listener( const 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: + 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*/ @@ -67,8 +68,19 @@ static void presence_refresher_listener( const belle_sip_refresher_t* refresher, 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_int(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; + } } } From 5ebe1a5296d669b8cbbd319793b2482bd7c9267f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 27 Jul 2013 00:01:35 +0200 Subject: [PATCH 551/909] fix android compilation issue --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 52514d03d..de83e4a8e 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2512,7 +2512,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIE extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_findCallFromUri(JNIEnv *env,jobject thiz,jlong pCore, jstring jUri) { const char* cUri=env->GetStringUTFChars(jUri, NULL); - LinphoneCall *call=linphone_core_find_call_from_uri((LinphoneCore *) pCore,cUri); + 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); From af0df9b19b40aa1e46d7135c809db4f694218790 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 27 Jul 2013 00:10:36 +0200 Subject: [PATCH 552/909] fix android compilation issue 2 --- coreapi/linphonecore_jni.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index de83e4a8e..74fdf1b99 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2512,10 +2512,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIE extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_findCallFromUri(JNIEnv *env,jobject thiz,jlong pCore, jstring jUri) { const char* cUri=env->GetStringUTFChars(jUri, NULL); - LinphoneCall *call=linphone_core_find_call_from_uri((const LinphoneCore *) pCore,cUri); + const LinphoneCall *call=linphone_core_find_call_from_uri((const LinphoneCore *) pCore,cUri); env->ReleaseStringUTFChars(jUri, cUri); LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)pCore); - return (jobject) lcdata->getCall(env,call); + return (jobject) lcdata->getCall(env,(LinphoneCall*)call); } From 046e422602ee0bc290cc653b12f566a966d3dcfc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 27 Jul 2013 00:57:52 +0200 Subject: [PATCH 553/909] repair build (buggy AM_CONDITIONAL) and update README.macos --- README.macos | 9 +++++++-- configure.ac | 5 +---- coreapi/Makefile.am | 10 ++-------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.macos b/README.macos index e2f1593bd..b69843be1 100644 --- a/README.macos +++ b/README.macos @@ -16,8 +16,6 @@ You need: - Install some linphone dependencies with macports $ sudo port install speex - $ sudo port install libosip2 # WARNING: currently outdated in macport - $ sudo port install libeXosip2 #WARNING: currently outdated in macport $ sudo port install ffmpeg-devel -gpl2 $ sudo port install libvpx $ sudo port install readline @@ -37,6 +35,13 @@ You need: The softwares below need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do: $ export MACOSX_DEPLOYMENT_TARGET=10.6 + +- Install belle-sip (sip stack) + $ git clone git://git.linphone.org/belle-sip.git + $ cd belle-sip + $ ./autogen.sh && ./configure --prefix=/opt/local && make + $ sudo make install + - Install srtp (optional) for call encryption $ sudo port install srtp If that fails, get from source: diff --git a/configure.ac b/configure.ac index e5cab9a09..181c7ef34 100644 --- a/configure.ac +++ b/configure.ac @@ -685,13 +685,10 @@ if test x$enable_msg_storage != xfalse; then fi -PKG_CHECK_MODULES(BELLESIP, [belle-sip],[bellesip_found=yes],foo=bar) - -AM_CONDITIONAL([USE_BELLESIP], [test "x$bellesip_found" == "xyes"]) +PKG_CHECK_MODULES(BELLESIP, [belle-sip]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" SIPSTACK_LIBS="$BELLESIP_LIBS" -AC_DEFINE(USE_BELLESIP,1,[Defined when bellesip is used]) AC_SUBST(SIPSTACK_CFLAGS) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 183fe92f0..69eff144e 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -53,7 +53,6 @@ if BUILD_UPNP liblinphone_la_SOURCES+=upnp.c upnp.h endif -if USE_BELLESIP liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ bellesip_sal/sal_op_impl.c \ @@ -66,11 +65,7 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_call_transfer.c \ bellesip_sal/sal_op_info.c \ bellesip_sal/sal_op_events.c -else -liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ - sal_eXosip2_sdp.c \ - sal_eXosip2_presence.c -endif + if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c endif @@ -133,9 +128,8 @@ AM_CFLAGS=\ if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD endif -if USE_BELLESIP + AM_CFLAGS+= -DUSE_BELLESIP -endif AM_CXXFLAGS=$(AM_CFLAGS) From 23ce8194013f12721cc8363a4d7605a905442d3b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 27 Jul 2013 01:07:00 +0200 Subject: [PATCH 554/909] fix constness of LinphoneCall * returned by linphone_core_find_call_by_uri(). There is no reason to return a const pointer, there's nothing you can do with a const LinphoneCall* in liblinphone. --- coreapi/linphonecore.c | 4 ++-- coreapi/linphonecore.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 17e77a41d..de9bac4cf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5885,9 +5885,9 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ return lc->zrtp_secrets_cache; } -const LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) { +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; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index dff394515..231ba0c05 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1626,7 +1626,7 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); * @param uri which should match call remote uri * @return LinphoneCall or NULL is no match is found */ -LINPHONE_PUBLIC const LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri); +LINPHONE_PUBLIC LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri); LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc); From cc2a5467d38456f14ed1fbf0a08f239483e49408 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 27 Jul 2013 01:27:08 +0200 Subject: [PATCH 555/909] replace call to belle_sip_object_instance_of(). --- coreapi/bellesip_sal/sal_impl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 6ddecefd8..9a7bc23f6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -153,7 +153,7 @@ static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminat 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_OBJECT(belle_sip_io_error_event_get_source(event)),BELLE_SIP_TYPE_ID(belle_sip_client_transaction_t))) { + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); if (op->callbacks.process_io_error) { From b2d873fab8753b8a4b1dacf6f632977c07ade96a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 27 Jul 2013 15:48:36 +0200 Subject: [PATCH 556/909] add linphone_core_stop_ringing() to public API. --- coreapi/linphonecore.c | 8 ++++++++ coreapi/linphonecore.h | 13 +++++++------ coreapi/private.h | 1 - mediastreamer2 | 2 +- oRTP | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index de9bac4cf..7de37b853 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5809,6 +5809,14 @@ void linphone_core_start_dtmf_stream(LinphoneCore* lc) { lc->ringstream_autorelease=FALSE; /*disable autorelease mode*/ } +/** + * Whenever the liblinphone is playing a ring to advertise an incoming call or ringback of an outgoing call, this function stops + * the ringing. Typical use is to stop ringing when the user requests to ignore the call. + * + * @param lc The LinphoneCore object + * + * @ingroup media_parameters +**/ void linphone_core_stop_ringing(LinphoneCore* lc) { if (lc->ringstream) { ring_stop(lc->ringstream); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 231ba0c05..1fafac383 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1428,19 +1428,20 @@ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); char linphone_core_get_sound_source(LinphoneCore *lc); void linphone_core_set_sound_source(LinphoneCore *lc, char source); +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); +LINPHONE_PUBLIC const char *linphone_core_get_ring(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno); -void linphone_core_verify_server_cn(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); +LINPHONE_PUBLIC void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *); +LINPHONE_PUBLIC const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc); -int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); +LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index c6ef374f9..cae6254b0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -758,7 +758,6 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); -void linphone_core_stop_ringing(LinphoneCore *lc); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); #ifdef __cplusplus diff --git a/mediastreamer2 b/mediastreamer2 index 43b68b22c..453f0057b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 43b68b22cf8d0d1b0b5a064516d35899e5527358 +Subproject commit 453f0057b5a6b872cd1deedf7873168ab912378f diff --git a/oRTP b/oRTP index 7c2805c2e..679d0d325 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7c2805c2e2c1edadf9e9efe313d98f06c4c3614a +Subproject commit 679d0d325f22ab3670eeee19b3f09d494efe3056 From 6e6e33ae23ff7fade0091621cccdf309617d3828 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 30 Jul 2013 16:56:54 +0200 Subject: [PATCH 557/909] - few renamings - robustify releasing of calls --- coreapi/bellesip_sal/sal_impl.c | 5 +-- coreapi/bellesip_sal/sal_impl.h | 16 +++++---- coreapi/bellesip_sal/sal_op_call.c | 57 ++++++++++++++++++------------ coreapi/bellesip_sal/sal_op_impl.c | 5 ++- coreapi/callbacks.c | 2 +- coreapi/linphonecall.c | 1 + 6 files changed, 53 insertions(+), 33 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 9a7bc23f6..e8ff58595 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -141,7 +141,7 @@ void sal_process_authentication(SalOp *op) { } static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ - belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_get_dialog(event); + belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event); SalOp* op = belle_sip_dialog_get_application_data(dialog); if (op && op->callbacks.process_dialog_terminated) { op->callbacks.process_dialog_terminated(op,event); @@ -749,7 +749,8 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)) ; return auth_info; } -const char* sal_op_type_to_string(const SalOpType_t type) { + +const char* sal_op_type_to_string(const SalOpType type) { switch(type) { case SalOpRegister: return "SalOpRegister"; case SalOpCall: return "SalOpCall"; diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 6826d445e..3989ee54a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -59,7 +59,7 @@ const char* sal_op_state_to_string(SalOpState value); typedef enum SalOpDir { SalOpDirIncoming=0 ,SalOpDirOutgoing -}SalOpDir_t; +}SalOpDir; typedef enum SalOpType { SalOpUnknown, SalOpRegister, @@ -68,8 +68,9 @@ typedef enum SalOpType { SalOpPresence, SalOpPublish, SalOpSubscribe -}SalOpType_t; -const char* sal_op_type_to_string(const SalOpType_t type); +}SalOpType; + +const char* sal_op_type_to_string(SalOpType type); struct SalOp{ SalOpBase base; @@ -78,20 +79,21 @@ struct SalOp{ belle_sip_server_transaction_t* pending_server_trans; belle_sip_client_transaction_t* pending_client_trans; SalAuthInfo* auth_info; - bool_t sdp_offering; belle_sip_dialog_t* dialog; belle_sip_header_replaces_t *replaces; belle_sip_header_referred_by_t *referred_by; - bool_t auto_answer_asked; SalMediaDescription *result; belle_sdp_session_description_t *sdp_answer; bool_t supports_session_timers; SalOpState state; - SalOpDir_t dir; + SalOpDir dir; belle_sip_refresher_t* refresher; int ref; - SalOpType_t type; + SalOpType type; SalPrivacyMask privacy; + bool_t auto_answer_asked; + bool_t sdp_offering; + bool_t call_released; }; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f95f8b884..b5c83ea81 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,17 +19,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" +/*used for calls terminated before creation of a dialog*/ static void call_set_released(SalOp* op){ - op->state=SalOpStateTerminated; - op->base.root->callbacks.call_released(op); + if (!op->call_released){ + op->state=SalOpStateTerminated; + op->base.root->callbacks.call_released(op); + op->call_released=TRUE; + } } -/*used when the SalOp was ref'd by the dialog*/ +/*used when the SalOp was ref'd by the dialog, in which case we rely only on the dialog terminated notification*/ static void call_set_released_and_unref(SalOp* op) { call_set_released(op); sal_op_unref(op); } + static void call_set_error(SalOp* op,belle_sip_response_t* response){ SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; @@ -114,6 +119,9 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription } static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ SalOp* op=(SalOp*)user_ctx; + + if (op->state==SalOpStateTerminated) return; + if (!op->dialog) { /*call terminated very early*/ op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); @@ -125,14 +133,14 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event 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_get_dialog(event)) { + 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_get_dialog(event),op); + 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*/ + /*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; } @@ -156,6 +164,7 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { 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)); @@ -264,15 +273,18 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; + + if (op->state==SalOpStateTerminated) return; + if (!op->dialog) { /*call terminated very early*/ op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); call_set_released(op); - op->state=SalOpStateTerminated; } 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); @@ -286,23 +298,21 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ 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))) { - - call_set_released(op); + if (op->state ==SalOpStateTerminating + && strcmp("BYE",belle_sip_request_get_method(req))==0 + && (!resp || (belle_sip_response_get_status_code(resp) !=401 + && belle_sip_response_get_status_code(resp) !=407))) { + if (op->dialog==NULL) call_set_released(op); } - } + static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) { belle_sip_response_t* resp; op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); resp=sal_op_create_response_from_request(op,request,status_code); belle_sip_server_transaction_send_response(server_transaction,resp); - - return; } + static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { belle_sip_response_t* resp; resp=belle_sip_response_create_from_request(request,500); @@ -382,8 +392,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t ,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); + ,op->pending_server_trans + ,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487); } else { @@ -508,6 +518,7 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { }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; @@ -528,8 +539,6 @@ int sal_call(SalOp *op, const char *from, const char *to){ } return sal_op_send_request(op,invite); - - } void sal_op_call_fill_cbs(SalOp*op) { @@ -616,6 +625,7 @@ int sal_call_accept(SalOp*h){ belle_sip_server_transaction_send_response(h->pending_server_trans,response); return 0; } + int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ belle_sip_response_t* response; belle_sip_header_contact_t* contact=NULL; @@ -699,7 +709,7 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ } 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; /*no dialog = dialog in NULL state*/ + 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; @@ -720,7 +730,7 @@ int sal_call_terminate(SalOp *op){ break; } else { /*just schedule call released*/ - belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) + if (op->dialog==NULL) belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) ,(belle_sip_callback_t) call_set_released , op); } @@ -742,9 +752,11 @@ int sal_call_terminate(SalOp *op){ } 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[] = "" @@ -777,6 +789,7 @@ void sal_call_send_vfu_request(SalOp *op){ return ; } + int sal_call_is_offerer(const SalOp *h){ return h->sdp_offering; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a0e58d726..ae9baedc8 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -436,8 +436,11 @@ SalOp* sal_op_ref(SalOp* op) { } /*return null, destroy op if ref count =0*/ void* sal_op_unref(SalOp* op) { - if (--op->ref <=0) { + 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; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1e8a3fb11..4f6981e5a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -568,7 +568,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call==NULL){ - ms_warning("Call faillure reported on already cleaned call ?"); + ms_warning("Call faillure reported on already terminated call."); return ; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index fc5ad5428..7741d5305 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -749,6 +749,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const static void linphone_call_destroy(LinphoneCall *obj) { + ms_message("Call [%p] freed.",obj); #ifdef BUILD_UPNP linphone_call_delete_upnp_session(obj); #endif //BUILD_UPNP From a7255768a7638b9307259f792b8f1a8a832676c5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 30 Jul 2013 21:59:41 +0200 Subject: [PATCH 558/909] update ms2 --- configure.ac | 3 --- mediastreamer2 | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 181c7ef34..cc1091bf3 100644 --- a/configure.ac +++ b/configure.ac @@ -702,9 +702,6 @@ 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) diff --git a/mediastreamer2 b/mediastreamer2 index 453f0057b..c3ddff9d1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 453f0057b5a6b872cd1deedf7873168ab912378f +Subproject commit c3ddff9d19556678ff3f3b41e5fe76c044206231 From 53e4a3c585d1ca7b9d5d79f73fbf0d8a1de30675 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 31 Jul 2013 23:27:42 +0200 Subject: [PATCH 559/909] fix condition for requiring 100rel --- coreapi/bellesip_sal/sal_op_call.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index b5c83ea81..eb92d14e8 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -573,17 +573,22 @@ 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); } - /*fixme it should support PRACK in the right way*/ - if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require") || belle_sip_message_get_header((belle_sip_message_t*)req,"Supported")) { + 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_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); belle_sip_header_contact_t* contact_header; - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100Rel"))); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100rel"))); belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1"))); 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_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); From 7614c63d613b766a291b697f7e82cc2cc937aaa4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 31 Jul 2013 23:42:12 +0200 Subject: [PATCH 560/909] configure refresher nat helper for subscribtion --- coreapi/bellesip_sal/sal_op_presence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index cee7b0093..b88af986d 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -125,6 +125,7 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); + belle_sip_refresher_enable_nat_helper(op->refresher,op->base.root->nat_helper_enabled); belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); } } From d85aeddbd15e29d1f9cb2bd5470888095773d698 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 31 Jul 2013 23:57:14 +0200 Subject: [PATCH 561/909] logs cleanup --- coreapi/friend.c | 2 +- coreapi/linphonecall.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 6d1d830e4..36743699d 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -454,7 +454,7 @@ void linphone_core_send_initial_subscribes(LinphoneCore *lc){ for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *f=(LinphoneFriend*)elem->data; LinphoneProxyConfig* cfg; - if (!f->initial_subscribes_sent) { + if (f->subscribe && !f->initial_subscribes_sent) { lc->initial_subscribes_sent=FALSE; /*at least 1 was not sent */ if ((cfg=linphone_core_lookup_known_proxy(f->lc,linphone_friend_get_address(f)))) { /*check if already registered*/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7741d5305..89cc397ce 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -187,7 +187,8 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw PayloadType *pt=(PayloadType*)it->data; if (pt->flags & PAYLOAD_TYPE_ENABLED){ if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){ - ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate); + ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", + pt->mime_type,pt->clock_rate,bandwidth_limit); continue; } if (linphone_core_check_payload_type_usability(lc,pt)){ From c19925c0d95312263d07e14ce021c8ffd7e01d32 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 1 Aug 2013 00:20:47 +0200 Subject: [PATCH 562/909] add reason in case of automatic proxyconfig re-registration due to io error --- coreapi/callbacks.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4f6981e5a..534b488d0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -782,16 +782,13 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const lc->vtable.display_status(lc,msg); ms_free(msg); } - if (error== SalErrorFailure && reason == SalReasonForbidden) { - linphone_proxy_config_set_error(cfg, LinphoneReasonBadCredentials); - } else if (error == SalErrorNoResponse) { - linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse); - } + + linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason)); + if (error== SalErrorFailure && reason == SalReasonServiceUnavailable && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); - } else { linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } From 0ac4617c35c8da8503f4b7f963c480226e1f3c17 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 1 Aug 2013 10:09:29 +0200 Subject: [PATCH 563/909] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 407d6591e..e97944a41 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 407d6591e14bf90816b88e7615408230136b3de5 +Subproject commit e97944a4171d4f7efdbc88f594b27d24ec9a55a6 From bf782bcea7fabedf4d4cd73ec70dffa85a515f2b Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 1 Aug 2013 16:14:24 +0200 Subject: [PATCH 564/909] Add C/CXX/OBJC flags for debug mode (same as ms2) --- configure.ac | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index eb4d533e8..d7061178a 100644 --- a/configure.ac +++ b/configure.ac @@ -356,6 +356,25 @@ AC_ARG_ENABLE(debug, esac], [debug_enabled=no] ) +AS_CASE([$enable_debug], + [yes],[ + CFLAGS="$CFLAGS -g -DDEBUG" + CXXFLAGS="$CXXFLAGS -g -DDEBUG" + OBJCFLAGS="$OBJCFLAGS -g -DDEBUG" + ], + [no], + [ + case "$CFLAGS" in + *-O*) + ;; + *) + CFLAGS="$CFLAGS -O2 -g" + CXXFLAGS="$CXXFLAGS -O2 -g" + OBJCFLAGS="$OBJCFLAGS -O2 -g" + ;; + esac + ], + [AC_MSG_ERROR([Bad value ($enable_debug) for --enable-debug. Valid values are yes or no.])]) dnl enable truespeech codec support AC_ARG_ENABLE(truespeech, From 9de977a968cef1c0bb1cbffde37540979f007bc1 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Fri, 2 Aug 2013 10:45:04 +0200 Subject: [PATCH 565/909] Update ms2(qtcapture memory leak fix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e97944a41..4ec110b9d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e97944a4171d4f7efdbc88f594b27d24ec9a55a6 +Subproject commit 4ec110b9dc24c1eb4defaae0e109a4c71c9cff1a From 9dd8b9aafe431fe685721c516ecb3300a3d70fd6 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 2 Aug 2013 14:08:26 +0200 Subject: [PATCH 566/909] add a test to test subscribetion recovery at app level --- tester/presence_tester.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 75c0cd00d..af287d141 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -163,12 +163,48 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph return result; } +static void subscribe_failure_handle_by_app(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + LinphoneProxyConfig* config; + LinphoneFriend* lf; + char* lf_identity=linphone_address_as_string_uri_only(pauline->identity); + linphone_core_get_default_proxy(marie->lc,&config); + + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1); /*just to wait for unsubscription even if not notified*/ + + sal_set_recv_error(marie->lc->sal, 0); /*simulate an error*/ + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationProgress,2)); + CU_ASSERT_EQUAL(linphone_proxy_config_get_error(config),LinphoneReasonIOError); + sal_set_recv_error(marie->lc->sal, 1); + + lf = linphone_core_get_friend_by_address(marie->lc,lf_identity); + linphone_friend_edit(lf); + linphone_friend_enable_subscribes(lf,FALSE); /*disable subscription*/ + linphone_friend_done(lf); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,2)); /*wait for register ok*/ + linphone_friend_edit(lf); + linphone_friend_enable_subscribes(lf,TRUE); + linphone_friend_done(lf); + CU_ASSERT_FALSE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(marie); + CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,3)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(pauline); +} + static void simple_subscribe(void) { LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + + + linphone_core_manager_destroy(marie); CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ @@ -298,6 +334,7 @@ test_t presence_tests[] = { { "Call with Presence", call_with_presence }, { "Unsubscribe while subscribing", unsubscribe_while_subscribing }, { "Presence information", presence_information }, + { "App managed presence failure", subscribe_failure_handle_by_app }, }; test_suite_t presence_test_suite = { From eaad8d79a9a0c2e94c4a0fb04e562ba7bf492734 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 3 Aug 2013 22:42:33 +0200 Subject: [PATCH 567/909] make sure offers/answer algo is executed on call accept to take call params into account --- coreapi/bellesip_sal/sal_op_call.c | 4 +- tester/call_tester.c | 91 +++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index eb92d14e8..dae5a4b27 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -557,7 +557,9 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon if (op->sdp_offering) { set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); }else{ - if (op->sdp_answer==NULL) sdp_process(op); + + sdp_process(op); + if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); belle_sip_object_unref(op->sdp_answer); diff --git a/tester/call_tester.c b/tester/call_tester.c index d16180732..309af77f4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -94,16 +94,19 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { -bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params) { +bool_t call_with_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + , const LinphoneCallParams *caller_params + , const LinphoneCallParams *callee_params) { int retry=0; stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; bool_t result=FALSE; - if (!params){ + if (!caller_params){ CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); }else{ - CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,params)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)); } /*linphone_core_invite(caller_mgr->lc,"pauline");*/ @@ -138,7 +141,10 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* cal CU_ASSERT_FALSE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); } - linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + if (callee_params) + linphone_core_accept_call_with_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc),callee_params); + else + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); @@ -156,9 +162,11 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* cal } return result; } - +bool_t call_with_caller_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params) { + return call_with_params(caller_mgr,callee_mgr,params,NULL); +} bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ - return call_with_params(caller_mgr,callee_mgr,NULL); + return call_with_params(caller_mgr,callee_mgr,NULL,NULL); } static void simple_call(void) { @@ -473,7 +481,7 @@ static void call_with_custom_headers(void) { linphone_call_params_add_custom_header(params,"Weather","bad"); linphone_call_params_add_custom_header(params,"Working","yes"); - CU_ASSERT_TRUE(call_with_params(pauline,marie,params)); + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); linphone_call_params_destroy(params); c1=linphone_core_get_current_call(marie->lc); @@ -610,6 +618,71 @@ static void call_with_video_added(void) { linphone_core_manager_destroy(pauline); } +static void call_with_declined_video(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallParams* callee_params; + LinphoneCallParams* caller_params; + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + + linphone_core_enable_video(marie->lc,TRUE,TRUE); + linphone_core_enable_video(pauline->lc,TRUE,FALSE); + + caller_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(caller_params,TRUE); + callee_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(callee_params,FALSE); + CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + CU_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallParams* callee_params; + LinphoneCallParams* caller_params; + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + + linphone_core_enable_video(marie->lc,TRUE,TRUE); + linphone_core_enable_video(pauline->lc,TRUE,FALSE); + + caller_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(caller_params,TRUE); + callee_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(callee_params,TRUE); + CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc); + linphone_call_send_vfu_request(marie_call); + CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} #endif static void call_with_privacy(void) { @@ -621,7 +694,7 @@ static void call_with_privacy(void) { params=linphone_core_create_default_call_parameters(pauline->lc); linphone_call_params_set_privacy(params,LinphonePrivacyId); - CU_ASSERT_TRUE(call_with_params(pauline,marie,params)); + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); linphone_call_params_destroy(params); c1=linphone_core_get_current_call(pauline->lc); @@ -976,8 +1049,10 @@ test_t call_tests[] = { { "SRTP call", srtp_call }, { "SRTP call with declined srtp", call_with_declined_srtp }, #ifdef VIDEO_ENABLED + { "Simple video call",video_call}, { "SRTP ice video call", srtp_video_ice_call }, { "Call with video added", call_with_video_added }, + { "Call with video declined",call_with_declined_video}, #else { "SRTP ice call", srtp_ice_call }, #endif From eb37b082a0cd81a12e01f2a0a1a736b67c638ccd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sun, 4 Aug 2013 12:28:30 +0200 Subject: [PATCH 568/909] remove trailling " from external body url --- coreapi/bellesip_sal/sal_op_message.c | 5 ++--- tester/message_tester.c | 9 ++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 17a038080..9cece2659 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -111,9 +111,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t salmsg.url=NULL; if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); - char* url = ms_malloc(url_length); - if (sscanf(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"),"\"%s\"",url) ==1) - salmsg.url=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); diff --git a/tester/message_tester.c b/tester/message_tester.c index 8e543de38..f5388b0ab 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -22,6 +22,7 @@ #include "private.h" #include "liblinphone_tester.h" +static char* message_external_body_url; void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { stats* counters = get_stats(lc); @@ -37,8 +38,10 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess ms_free(from); counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; - if (linphone_chat_message_get_external_body_url(message)) + if (linphone_chat_message_get_external_body_url(message)) { counters->number_of_LinphoneMessageExtBodyReceived++; + CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + } } void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { @@ -160,14 +163,14 @@ static void text_message_with_external_body(void) { char* to = linphone_address_as_string(marie->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); - linphone_chat_message_set_external_body_url(message,"http://www.linphone.org"); + linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); - /*fixme use history to check message content*/ + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From 3a163296ba74850c91c2feae0029b386df5d8dec Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 4 Aug 2013 14:43:29 +0200 Subject: [PATCH 569/909] fix linphone_core_accept_call_with_params() as it was in exosip implementation so that it does not compute sdp answer two times (for 180 and 200). --- coreapi/bellesip_sal/sal_op_call.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index dae5a4b27..c74922b57 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -496,6 +496,16 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *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; } @@ -558,7 +568,7 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); }else{ - sdp_process(op); + if (op->sdp_answer==NULL) sdp_process(op); if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); From 0942ba67a61ba1b47647d1610ade2f4537906b40 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 4 Aug 2013 15:09:47 +0200 Subject: [PATCH 570/909] fix incorrect copy of parameters in linphone_core_accept_call_update() --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7de37b853..64e06a9f5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3072,7 +3072,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const if (params==NULL){ call->params.has_video=lc->video_policy.automatically_accept || call->current_params.has_video; }else - call->params=*params; + _linphone_call_params_copy(&call->params,params); if (call->params.has_video && !linphone_core_video_enabled(lc)){ ms_warning("linphone_core_accept_call_update(): requested video but video support is globally disabled. Refusing video."); From 491294b2794bfa6f60e80169fb44d028b3818c2a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 7 Aug 2013 00:55:43 +0200 Subject: [PATCH 571/909] Fix case where a call is cancelled by a user while no provisionnal response has been received yet (was not functional) Add a test for this case. Reformat the code for indentation and break statement positions. --- coreapi/bellesip_sal/sal_op_call.c | 106 +++++++++++++++-------------- coreapi/bellesip_sal/sal_op_impl.c | 5 +- coreapi/linphonecore.c | 2 +- tester/call_tester.c | 27 ++++++++ 4 files changed, 86 insertions(+), 54 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index c74922b57..b9ee908ee 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -173,7 +173,7 @@ static void cancelling_invite(SalOp* op ){ op->state=SalOpStateTerminating; } -static void call_response_event(void *op_base, const belle_sip_response_event_t *event){ +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; @@ -198,16 +198,20 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t case BELLE_SIP_DIALOG_EARLY: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { if (op->state == SalOpStateTerminating) { + /*check if CANCEL was sent before*/ if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { + /*it wasn't sent */ if (code<200) { cancelling_invite(op); - } else if (code<400) { - sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); - } else { - /*nop ?*/ + }else{ + /* no need to send the INVITE because the UAS rejected the INVITE*/ + if (op->dialog==NULL) call_set_released(op); } } else { - /*nop, already cancelled*/ + /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ + if (code>=300){ + if (op->dialog==NULL) call_set_released(op); + } } } else if (code >= 180 && code<300) { handle_sdp_from_response(op,response); @@ -221,54 +225,51 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t break; case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { - case SalOpStateEarly:/*invite case*/ - case SalOpStateActive: /*re-invite case*/ - if (code >=200 - && code<300 - && strcmp("INVITE",belle_sip_request_get_method(req))==0) { - handle_sdp_from_response(op,response); - ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); - if (ack==NULL) { - ms_error("This call has been already terminated."); - return ; + case SalOpStateEarly:/*invite case*/ + case SalOpStateActive: /*re-invite case*/ + if (code >=200 + && code<300 + && strcmp("INVITE",belle_sip_request_get_method(req))==0) { + handle_sdp_from_response(op,response); + ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); + if (ack==NULL) { + ms_error("This call has been already terminated."); + return ; + } + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); + op->sdp_answer=NULL; + } + belle_sip_dialog_send_ack(op->dialog,ack); + op->base.root->callbacks.call_accepted(op); /*INVITE*/ + op->state=SalOpStateActive; + } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ + call_set_error(op,response); + } else { + /*ignoring*/ } - if (op->sdp_answer){ - set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); - belle_sip_object_unref(op->sdp_answer); - op->sdp_answer=NULL; - } - belle_sip_dialog_send_ack(op->dialog,ack); - op->base.root->callbacks.call_accepted(op); /*INVITE*/ - - op->state=SalOpStateActive; - } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ - call_set_error(op,response); - } else { - /*ignoring*/ - } - break; - case SalOpStateTerminating: - //FIXME send bye - case SalOpStateTerminated: - default: - ms_error("call op [%p] receive answer [%i] not implemented",op,code); + 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; } + break; case BELLE_SIP_DIALOG_TERMINATED: { if (code >= 300){ call_set_error(op,response); } - break; } - /* no break */ + break; default: { ms_error("call op [%p] receive answer [%i] not implemented",op,code); } - /* no break */ + break; } - - } static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { @@ -553,7 +554,7 @@ int sal_call(SalOp *op, const char *from, const char *to){ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_io_error=call_process_io_error; - op->callbacks.process_response_event=call_response_event; + op->callbacks.process_response_event=call_process_response; op->callbacks.process_timeout=call_process_timeout; op->callbacks.process_transaction_terminated=call_process_transaction_terminated; op->callbacks.process_request_event=process_request_event; @@ -741,15 +742,16 @@ int sal_call_terminate(SalOp *op){ if (op->dir == SalOpDirIncoming) { sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; - } else if (op->pending_client_trans - && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ - cancelling_invite(op); - break; - } else { - /*just schedule call released*/ - if (op->dialog==NULL) 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 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; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index ae9baedc8..5fe48f8c3 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -30,7 +30,9 @@ SalOp * sal_op_new(Sal *sal){ } void sal_op_release(SalOp *op){ - op->state=SalOpStateTerminated; + /*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); @@ -413,6 +415,7 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S return FALSE; } } + void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { /*check if dialog has changed*/ if (dialog && dialog != op->dialog) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 64e06a9f5..426c85c3e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4917,7 +4917,7 @@ int linphone_core_get_device_rotation(LinphoneCore *lc ) { * **/ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { - ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); + if (rotation!=lc->device_rotation) ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); lc->device_rotation = rotation; #ifdef VIDEO_ENABLED { diff --git a/tester/call_tester.c b/tester/call_tester.c index 309af77f4..59d36a4a5 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -322,6 +322,32 @@ static void call_with_dns_time_out(void) { linphone_core_manager_destroy(marie); } +static void early_cancelled_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_alt_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"sip:marie@sip.example.org"); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + linphone_core_terminate_call(pauline->lc,out_call); + + /*since everything is executed in a row, no response can be received from the server, thus the CANCEL cannot be sent. + It will ring at Marie's side.*/ + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + /* now the CANCEL should have been sent and the the call at marie's side should terminate*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void cancelled_ringing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1037,6 +1063,7 @@ 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 }, { "Simple call", simple_call }, From 0c067e225eee1352709812741235a6676ba5fee0 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 7 Aug 2013 10:32:46 +0200 Subject: [PATCH 572/909] Fix configure.ac debug_enabled enable_debug mixup --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d7061178a..12dc06224 100644 --- a/configure.ac +++ b/configure.ac @@ -356,7 +356,7 @@ AC_ARG_ENABLE(debug, esac], [debug_enabled=no] ) -AS_CASE([$enable_debug], +AS_CASE([$debug_enabled], [yes],[ CFLAGS="$CFLAGS -g -DDEBUG" CXXFLAGS="$CXXFLAGS -g -DDEBUG" @@ -374,7 +374,7 @@ AS_CASE([$enable_debug], ;; esac ], - [AC_MSG_ERROR([Bad value ($enable_debug) for --enable-debug. Valid values are yes or no.])]) + [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, From 480c643418a72ea8822d5e898f3fe58cd75789fb Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Wed, 7 Aug 2013 11:35:32 +0200 Subject: [PATCH 573/909] Add uPnP blacklist --- coreapi/upnp.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--- mediastreamer2 | 2 +- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 0922dad59..cd9e14b31 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -86,7 +86,8 @@ struct _UpnpContext { bool_t linphone_core_upnp_hook(void *data); -void linphone_core_upnp_refresh(UpnpContext *ctx); +void linphone_upnp_update(UpnpContext *ctx); +bool_t linphone_upnp_is_blacklisted(UpnpContext *ctx); UpnpPortBinding *linphone_upnp_port_binding_new(); UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port); @@ -198,6 +199,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { const char *ip_address = NULL; const char *connection_status = NULL; bool_t nat_enabled = FALSE; + bool_t blacklisted = FALSE; LinphoneUpnpState old_state; if(lupnp == NULL || lupnp->upnp_igd_ctxt == NULL) { @@ -217,6 +219,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { ip_address = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); connection_status = upnp_igd_get_connection_status(lupnp->upnp_igd_ctxt); nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt); + blacklisted = linphone_upnp_is_blacklisted(lupnp); if(ip_address == NULL || connection_status == NULL) { ms_message("uPnP IGD: Pending"); @@ -224,11 +227,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { ms_message("uPnP IGD: Not Available"); lupnp->state = LinphoneUpnpStateNotAvailable; + } else if(blacklisted) { + ms_message("uPnP IGD: Router is blacklisted"); + lupnp->state = LinphoneUpnpStateNotAvailable; } else { ms_message("uPnP IGD: Connected"); lupnp->state = LinphoneUpnpStateOk; if(old_state != LinphoneUpnpStateOk) { - linphone_core_upnp_refresh(lupnp); + linphone_upnp_update(lupnp); } } @@ -495,6 +501,45 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { return port; } +bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) { + const char * device_model_name = upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt); + const char * device_model_number = upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt); + const char * blacklist = lp_config_get_string(lupnp->lc->config, "net", "upnp_blacklist", NULL); + bool_t blacklisted = FALSE; + char *str; + char *pch; + char *model_name; + char *model_number; + + // Sanity checks + if(device_model_name == NULL || device_model_number == NULL || blacklist == NULL) { + return FALSE; + } + + // Find in the list + str = strdup(blacklist); + pch = strtok(str, ";"); + while (pch != NULL && !blacklisted) { + // Extract model name & number + model_name = pch; + model_number = strstr(pch, ","); + if(model_number != NULL) { + *(model_number++) = '\0'; + } + + // Compare with current device + if(strcmp(model_name, device_model_name) == 0) { + if(model_number == NULL || strcmp(model_number, device_model_number) == 0) { + blacklisted = TRUE; + } + } + pch = strtok(NULL, ";"); + } + free(str); + + return blacklisted; +} + void linphone_upnp_refresh(UpnpContext * lupnp) { upnp_igd_refresh(lupnp->upnp_igd_ctxt); } @@ -800,13 +845,24 @@ int linphone_upnp_call_process(LinphoneCall *call) { return ret; } -void linphone_core_upnp_refresh(UpnpContext *lupnp) { +static const char *linphone_core_upnp_get_charptr_null(const char *str) { + if(str != NULL) { + return str; + } + return "(Null)"; +} + +void linphone_upnp_update(UpnpContext *lupnp) { MSList *global_list = NULL; MSList *list = NULL; MSList *item; LinphoneCall *call; UpnpPortBinding *port_mapping, *port_mapping2; + ms_message("uPnP IGD: Name:%s", linphone_core_upnp_get_charptr_null(upnp_igd_get_device_name(lupnp->upnp_igd_ctxt))); + ms_message("uPnP IGD: Device:%s %s", + linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt)), + linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt))); ms_message("uPnP IGD: Refresh mappings"); if(lupnp->sip_udp != NULL) { diff --git a/mediastreamer2 b/mediastreamer2 index 4ec110b9d..6c2a60880 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4ec110b9dc24c1eb4defaae0e109a4c71c9cff1a +Subproject commit 6c2a608800a221942f2a827e0abb60346e7d065f From c212173648d847a4e17ed07c332ce3e9ed62be50 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 8 Aug 2013 11:36:49 +0200 Subject: [PATCH 574/909] Upnp: add blacklisted state --- coreapi/linphonecore.h | 1 + coreapi/upnp.c | 2 +- java/common/org/linphone/core/LinphoneCore.java | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 93ab0ca88..1f4f71e6b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -306,6 +306,7 @@ enum _LinphoneUpnpState{ LinphoneUpnpStateNotAvailable, /**< uPnP is not available */ LinphoneUpnpStateOk, /**< uPnP is enabled */ LinphoneUpnpStateKo, /**< uPnP processing has failed */ + LinphoneUpnpStateBlacklisted, /**< IGD router is blacklisted */ }; /** diff --git a/coreapi/upnp.c b/coreapi/upnp.c index cd9e14b31..adbd377ac 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -229,7 +229,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { lupnp->state = LinphoneUpnpStateNotAvailable; } else if(blacklisted) { ms_message("uPnP IGD: Router is blacklisted"); - lupnp->state = LinphoneUpnpStateNotAvailable; + lupnp->state = LinphoneUpnpStateBlacklisted; } else { ms_message("uPnP IGD: Connected"); lupnp->state = LinphoneUpnpStateOk; diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index d76acad9a..8219e8d95 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -327,6 +327,11 @@ public interface LinphoneCore { * Ko */ static public UpnpState Ko = new UpnpState(6, "Ko"); + /** + * Blacklisted + */ + static public UpnpState Blacklisted = new UpnpState(6, "Blacklisted"); + protected final int mValue; private final String mStringValue; From 321043603a9be8dff090129846590e12b55043f1 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 8 Aug 2013 11:40:07 +0200 Subject: [PATCH 575/909] Fix Upnp Blacklisted int value in java --- java/common/org/linphone/core/LinphoneCore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 8219e8d95..8cc9316e4 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -330,7 +330,7 @@ public interface LinphoneCore { /** * Blacklisted */ - static public UpnpState Blacklisted = new UpnpState(6, "Blacklisted"); + static public UpnpState Blacklisted = new UpnpState(7, "Blacklisted"); protected final int mValue; private final String mStringValue; From 9d3fb120064b0d42048e3e14c0f0e1d6f4857a46 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 8 Aug 2013 12:35:51 +0200 Subject: [PATCH 576/909] Added liblinsqlite3 to android compilation --- build/android/common.mk | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/android/common.mk b/build/android/common.mk index cffaa1e0c..adb73ff42 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -215,6 +215,13 @@ LOCAL_SRC_FILES += ../tools/xml2lpc.c \ endif +ifeq ($(BUILD_SQLITE),1) +LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED +LOCAL_STATIC_LIBRARIES += liblinsqlite +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../externals/sqlite3/ +endif + LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) From 1d144769f8a88edfc9253ed058b066f62fae8abd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 8 Aug 2013 13:05:05 +0200 Subject: [PATCH 577/909] update oRTP to fix errors with telephone-event and srtp. fix sal to get Referred-by header set in INVITEs consecutive to an incoming REFER request. --- coreapi/bellesip_sal/sal_op_call.c | 6 +++--- oRTP | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index b9ee908ee..1a7b191a8 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -545,10 +545,10 @@ int sal_call(SalOp *op, const char *from, const char *to){ 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)); } - + 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); } diff --git a/oRTP b/oRTP index 679d0d325..bfc4e00cd 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 679d0d325f22ab3670eeee19b3f09d494efe3056 +Subproject commit bfc4e00cd6b6dd3e6d834ba17c6d0048cc46c280 From 389922acce2412e6e4f57a74d3e7ea41e8e58771 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 8 Aug 2013 16:23:07 +0200 Subject: [PATCH 578/909] Started the JNI binding of the message_storage functions --- coreapi/linphonecore_jni.cc | 30 +++++++++++++++++-- .../org/linphone/core/LinphoneChatRoom.java | 6 ++++ .../org/linphone/core/LinphoneCore.java | 9 +++++- .../linphone/core/LinphoneChatRoomImpl.java | 13 ++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 6 +++- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 74fdf1b99..808bc19fd 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -535,7 +535,7 @@ public: ,lcData->messageReceivedId ,lcData->core ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) - ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); + ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); } static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) { JNIEnv *env = 0; @@ -718,6 +718,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_sendInfoMessage(J return linphone_call_send_info_message((LinphoneCall*)callptr,(LinphoneInfoMessage*)infoptr); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIEnv* env, jobject thiz, jlong lc, jstring jpath) { + const char* path = env->GetStringUTFChars(jpath, NULL); + linphone_core_set_chat_database_path((LinphoneCore*)lc, path); + env->ReleaseStringUTFChars(jpath, path); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) { const char* displayname = env->GetStringUTFChars(jdisplayname, NULL); const char* username = env->GetStringUTFChars(jusername, NULL); @@ -753,7 +759,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig( } extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigList(JNIEnv* env, jobject thiz, jlong lc) { - const MSList* proxies = linphone_core_get_proxy_config_list((LinphoneCore*)lc); + const MSList* proxies = linphone_core_get_proxy_config_list((LinphoneCore*)lc); int proxyCount = ms_list_size(proxies); jlongArray jProxies = env->NewLongArray(proxyCount); jlong *jInternalArray = env->GetLongArrayElements(jProxies, NULL); @@ -1009,7 +1015,7 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTy codecs = codecs->next; } - env->ReleaseLongArrayElements(jCodecs, jInternalArray, 0); + env->ReleaseLongArrayElements(jCodecs, jInternalArray, 0); return jCodecs; } @@ -2038,6 +2044,23 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIE return (jlong) lf; } //LinphoneChatRoom +extern "C" jlongArray Java_org_linphone_core_LinphoneChatRoomImpl_getHistory(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, 20); + int historySize = ms_list_size(history); + jlongArray jHistory = env->NewLongArray(historySize); + jlong *jInternalArray = env->GetLongArrayElements(jHistory, NULL); + + for (int i = 0; i < historySize; i++) { + jInternalArray[i] = (unsigned long) (history->data); + history = history->next; + } + + env->ReleaseLongArrayElements(jHistory, jInternalArray, 0); + + return jHistory; +} extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -2158,6 +2181,7 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* jobject listener = env->NewGlobalRef(jlistener); linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener); } + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env ,jobject thiz ,jlong lc diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index d6512f170..b6be85a83 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -48,4 +48,10 @@ 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(); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index eba0cea5a..81b11d721 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -20,9 +20,11 @@ package org.linphone.core; import java.util.Vector; -import org.linphone.core.LinphoneCall.State; +import org.linphone.mediastream.video.AndroidVideoWindowImpl; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; +import android.view.SurfaceView; + /** * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}. * @@ -1313,4 +1315,9 @@ public interface LinphoneCore { */ 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); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 83141ad1c..e3c96ba60 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -26,6 +26,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native long getPeerAddress(long ptr); private native void sendMessage(long ptr, String message); private native void sendMessage2(long ptr, long message, StateListener listener); + private native long[] getHistory(long ptr); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -49,4 +50,16 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public LinphoneChatMessage createLinphoneChatMessage(String message) { return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); } + + public LinphoneChatMessage[] getHistory() { + long[] typesPtr = getHistory(nativePtr); + 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; + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index a61bd1cc5..c822d6149 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. package org.linphone.core; import static android.media.AudioManager.MODE_IN_CALL; -import static android.media.AudioManager.MODE_RINGTONE; import java.io.File; import java.io.IOException; @@ -133,6 +132,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setIncomingTimeout(long nativePtr, int timeout); private native void setInCallTimeout(long nativePtr, int timeout); private native void setPrimaryContact(long nativePtr, String displayName, String username); + private native void setChatDatabasePath(long nativePtr, String path); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { mListener=listener; @@ -980,4 +980,8 @@ class LinphoneCoreImpl implements LinphoneCore { return (LinphoneEvent)publish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getDataAsString() : null); } + + public void setChatDatabasePath(String path) { + setChatDatabasePath(nativePtr, path); + } } From 952adab4f85dec18fbe980296c2c5462def1fc92 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 9 Aug 2013 11:04:50 +0200 Subject: [PATCH 579/909] Added more JNI bindings for ChatMessages + few fixes in messaeg_storage (some properties weren't set when read from database) --- coreapi/chat.c | 17 ++++++++++++++++ coreapi/linphonecore.h | 2 ++ coreapi/linphonecore_jni.cc | 20 ++++++++++++++++++- coreapi/message_storage.c | 3 +++ .../linphone/core/LinphoneChatMessage.java | 18 +++++++++++++++++ .../core/LinphoneChatMessageImpl.java | 15 ++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 8dbd60f75..80d00a08e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -181,6 +181,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->time=sal_msg->time; 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); @@ -401,6 +402,22 @@ const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* messag return sal_custom_header_find(message->custom_headers,header_name); } +/** + * Returns TRUE if the message has been read, otherwise returns FALSE. + * @param message the message +**/ +bool_t linphone_chat_message_is_read(LinphoneChatMessage* message) { + return message->is_read; +} + +/** + * Returns TRUE if the message has been sent, returns FALSE if the message has been received. + * @param message the message +**/ +bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message) { + return message->dir == LinphoneChatMessageOutgoing; +} + /** * Duplicate a LinphoneChatMessage **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 54391842c..7fb60b6aa 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -884,6 +884,8 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(Li LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); +LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); +LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); /** * @} diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 808bc19fd..436e1983e 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -523,7 +523,7 @@ public: ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from) ,message ? env->NewStringUTF(message) : NULL); } - static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { + static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { @@ -2140,6 +2140,24 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getTime(JNIEnv* return (jlong) linphone_chat_message_get_time((LinphoneChatMessage*)ptr); } +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStatus(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_message_get_state((LinphoneChatMessage*)ptr); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isRead(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jboolean) linphone_chat_message_is_read((LinphoneChatMessage*)ptr); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isOutgoing(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jboolean) linphone_chat_message_is_outgoing((LinphoneChatMessage*)ptr); +} + extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env ,jobject thiz ,jlong ptr diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 765543f7a..13e46e147 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -48,8 +48,10 @@ static void create_chat_message(char **argv, void *data){ char tmp2[80]={0}; if(atoi(argv[3])==LinphoneChatMessageIncoming){ + new_message->dir=LinphoneChatMessageIncoming; from=linphone_address_new(argv[2]); } else { + new_message->dir=LinphoneChatMessageOutgoing; from=linphone_address_new(argv[1]); } linphone_chat_message_set_from(new_message,from); @@ -69,6 +71,7 @@ static void create_chat_message(char **argv, void *data){ ret.tm_isdst=-1; } new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); + new_message->is_read=atoi(argv[6]); new_message->state=atoi(argv[7]); cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index b6b6c30ec..6a539d740 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -112,4 +112,22 @@ public interface LinphoneChatMessage { * @return the time in milliseconds */ long getTime(); + + /** + * Gets the status of the message + * @return the status of the message + */ + LinphoneChatMessage.State getStatus(); + + /** + * Returns wether or not the message has been read + * @return true if it has been read, flase otherwise + */ + boolean isRead(); + + /** + * Returns wether the message has been sent or received + * @return true if the message has been sent, false if it has been received + */ + boolean isOutgoing(); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 8162f67bf..ac308aa92 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -9,6 +9,9 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native void setExternalBodyUrl(long ptr, String url); private native long getFrom(long ptr); private native long getTime(long ptr); + private native int getStatus(long ptr); + private native boolean isRead(long ptr); + private native boolean isOutgoing(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -69,4 +72,16 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public long getTime() { return getTime(nativePtr) * 1000; // Need milliseconds, not seconds } + + public LinphoneChatMessage.State getStatus() { + return LinphoneChatMessage.State.fromInt(getStatus(nativePtr)); + } + + public boolean isRead() { + return isRead(nativePtr); + } + + public boolean isOutgoing() { + return isOutgoing(nativePtr); + } } From 1ccf89e4fbd6618a9d4a77b54d62c1ce8bb4fa0d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 9 Aug 2013 17:06:39 +0200 Subject: [PATCH 580/909] Init chatrooms at storage startup using sotred conversations + JNI glue to get chatrooms list --- coreapi/chat.c | 9 +++++ coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 18 ++++++++++ coreapi/message_storage.c | 34 ++++++++++++++++++- coreapi/private.h | 1 + .../org/linphone/core/LinphoneCore.java | 6 ++++ .../org/linphone/core/LinphoneCoreImpl.java | 14 ++++++++ 7 files changed, 82 insertions(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 80d00a08e..f94b87862 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -31,6 +31,15 @@ * @{ */ +/** + * Returns an array of chat rooms + * @param lc #LinphoneCore object + * @return An array of #LinpĥoneChatRoom +**/ +MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) { + return lc->chatrooms; +} + /** * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org * @param lc #LinphoneCore object diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7fb60b6aa..6f7af4e5d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -865,6 +865,7 @@ LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoo LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); +LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc); LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 436e1983e..526bd9459 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2158,6 +2158,24 @@ extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isOutgoing(JN return (jboolean) linphone_chat_message_is_outgoing((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 diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 13e46e147..c556e267e 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -76,6 +76,14 @@ static void create_chat_message(char **argv, void *data){ cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } +// Called when fetching all conversations from database +static int callback_all(void *data, int argc, char **argv, char **colName){ + LinphoneCore* lc = (LinphoneCore*) data; + char* address = argv[0]; + linphone_core_create_chat_room(lc, address); + return 0; +} + static int callback(void *data, int argc, char **argv, char **colName){ create_chat_message(argv,data); return 0; @@ -94,13 +102,24 @@ void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom void linphone_sql_request(sqlite3* db,const char *stmt){ char* errmsg=NULL; int ret; - ret=sqlite3_exec(db,stmt,0,0,&errmsg); + ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); if(ret != SQLITE_OK) { ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); sqlite3_free(errmsg); } } +// Process the request to fetch all chat contacts +void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + void linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); if (lc->db){ @@ -205,6 +224,13 @@ void linphone_create_table(sqlite3* db){ } } +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { + if (lc->db==NULL) return NULL; + char *buf=sqlite3_mprintf("SELECT remoteContact FROM history Group By remoteContact;"); + linphone_sql_request_all(lc->db,buf,lc); + sqlite3_free(buf); +} + void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; const char *errmsg; @@ -217,6 +243,9 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ } linphone_create_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){ @@ -244,6 +273,9 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ 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){ } diff --git a/coreapi/private.h b/coreapi/private.h index cae6254b0..e5e7113aa 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -730,6 +730,7 @@ void linphone_upnp_destroy(LinphoneCore *lc); #ifdef MSG_STORAGE_ENABLED sqlite3 * linphone_message_storage_init(); +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif void linphone_chat_message_store(LinphoneChatMessage *msg); void linphone_chat_message_store_state(LinphoneChatMessage *msg); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 81b11d721..b763107d7 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1320,4 +1320,10 @@ public interface LinphoneCore { * @param path the database where the chat messages will be stored. */ public void setChatDatabasePath(String path); + + /** + * Gets the chat rooms + * @return an array of LinphoneChatRoom + */ + public LinphoneChatRoom[] getChatRooms(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index c822d6149..bc9d3d1ba 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -133,6 +133,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setInCallTimeout(long nativePtr, int timeout); private native void setPrimaryContact(long nativePtr, String displayName, String username); private native void setChatDatabasePath(long nativePtr, String path); + private native long[] getChatRooms(long nativePtr); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { mListener=listener; @@ -984,4 +985,17 @@ class LinphoneCoreImpl implements LinphoneCore { public void setChatDatabasePath(String path) { setChatDatabasePath(nativePtr, path); } + + public synchronized LinphoneChatRoom[] getChatRooms() { + long[] typesPtr = getChatRooms(nativePtr); + if (typesPtr == null) return null; + + LinphoneChatRoom[] proxies = new LinphoneChatRoom[typesPtr.length]; + + for (int i=0; i < proxies.length; i++) { + proxies[i] = new LinphoneChatRoomImpl(typesPtr[i]); + } + + return proxies; + } } From 2db0e99c547779ffd34c08fa61e64f0a967ef6d6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 9 Aug 2013 17:13:27 +0200 Subject: [PATCH 581/909] fix bug in condition for doing echo calibration update ms2 because of Nexus S bug. --- coreapi/linphonecore_jni.cc | 4 +++- mediastreamer2 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 526bd9459..c468db92b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1216,7 +1216,9 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration ms_error("Could not get soundcard."); return TRUE; } - return (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) || (ms_snd_card_get_minimal_latency(sndcard)>0); + if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return FALSE; + if (ms_snd_card_get_minimal_latency(sndcard)==0) return TRUE; + return FALSE; } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env diff --git a/mediastreamer2 b/mediastreamer2 index 6c2a60880..6a35ffc77 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6c2a608800a221942f2a827e0abb60346e7d065f +Subproject commit 6a35ffc7745d6748a43cebd7347f6af89a913593 From 3e2f306e361fce90b05da1cfc7d6c16bc592df69 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 12 Aug 2013 09:39:38 +0200 Subject: [PATCH 582/909] Added JNI glue for destroy method of LinphoneChatRoom --- coreapi/linphonecore_jni.cc | 6 ++++++ java/common/org/linphone/core/LinphoneChatRoom.java | 5 +++++ java/impl/org/linphone/core/LinphoneChatRoomImpl.java | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index c468db92b..cfac60c85 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2078,6 +2078,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM return (jlong) chatMessage; } +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_room_destroy((LinphoneChatRoom*)ptr); +} + extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index b6be85a83..9e48d6598 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -54,4 +54,9 @@ public interface LinphoneChatRoom { * @return an array of LinphoneChatMessage */ LinphoneChatMessage[] getHistory(); + + /** + * Destroys a LinphoneChatRoom. + */ + void destroy(); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index e3c96ba60..abe2c52d8 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -27,6 +27,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void sendMessage(long ptr, String message); private native void sendMessage2(long ptr, long message, StateListener listener); private native long[] getHistory(long ptr); + private native void destroy(long ptr); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -62,4 +63,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { return messages; } + + public void destroy() { + destroy(nativePtr); + } } From 8fbe7ee1d47c7957f35ca9268c4072df7921cec1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 12 Aug 2013 10:52:15 +0200 Subject: [PATCH 583/909] Added JNI glue for deleteHistory and getUnreadMessagesCount methods of LinphoneChatRoom --- coreapi/linphonecore_jni.cc | 10 ++++++++++ java/common/org/linphone/core/LinphoneChatRoom.java | 11 +++++++++++ java/impl/org/linphone/core/LinphoneChatRoomImpl.java | 10 ++++++++++ 3 files changed, 31 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index cfac60c85..55ea828bd 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2078,6 +2078,16 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM return (jlong) chatMessage; } +extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getUnreadMessagesCount(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_room_get_unread_messages_count((LinphoneChatRoom*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); +} extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index 9e48d6598..cfea18f9f 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -59,4 +59,15 @@ public interface LinphoneChatRoom { * Destroys a LinphoneChatRoom. */ void destroy(); + + /** + * Returns the amount of unread messages associated with the peer of this chatRoom. + * @return the amount of unread messages + */ + int getUnreadMessagesCount(); + + /** + * Deletes all the messages associated with the peer of this chat room + */ + void deleteHistory(); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index abe2c52d8..faead77ca 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -28,6 +28,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void sendMessage2(long ptr, long message, StateListener listener); private native long[] getHistory(long ptr); private native void destroy(long ptr); + private native int getUnreadMessagesCount(long ptr); + private native void deleteHistory(long ptr); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -67,4 +69,12 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void destroy() { destroy(nativePtr); } + + public int getUnreadMessagesCount() { + return getUnreadMessagesCount(nativePtr); + } + + public void deleteHistory() { + deleteHistory(nativePtr); + } } From 55b640b0d733ea88885d438c7888cf021269510e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 12 Aug 2013 11:20:44 +0200 Subject: [PATCH 584/909] Added a method that returns the existing chatroom if possible instead of always creating a new one + added JNI binding for this method --- coreapi/chat.c | 22 +++++++++++++++++++ .../core/tutorials/TutorialChatRoom.java | 2 +- coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 4 ++-- .../org/linphone/core/LinphoneCore.java | 2 +- .../org/linphone/core/LinphoneCoreImpl.java | 6 ++--- 6 files changed, 30 insertions(+), 7 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index f94b87862..537a4b7ae 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -59,6 +59,28 @@ LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char * } return NULL; } + +static int chat_room_compare(LinphoneChatRoom* room, const char* to) { + return strcmp(linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room)), to); /*return 0 if equals*/ +} + +/** + * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org if not already existing, else return exisiting one + * @param lc #LinphoneCore object + * @param to destination address for messages + * @return #LinphoneChatRoom where messaging can take place. + */ +LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) { + if (ms_list_size(lc->chatrooms) == 0) + return linphone_core_create_chat_room(lc, to); + + MSList* found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) chat_room_compare, to); + if (found != NULL) { + return (LinphoneChatRoom*)found->data; + } else { + return linphone_core_create_chat_room(lc, to); + } +} /** * Destroy a LinphoneChatRoom. diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 276d291e5..e3594970b 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -119,7 +119,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa try { // Next step is to create a chat room - LinphoneChatRoom chatRoom = lc.createChatRoom(destinationSipAddress); + LinphoneChatRoom chatRoom = lc.getOrCreateChatRoom(destinationSipAddress); // Send message LinphoneChatMessage chatMessage = chatRoom.createLinphoneChatMessage("Hello world"); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6f7af4e5d..2397ec293 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -852,6 +852,7 @@ typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,Linpho LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path); LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to); LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 55ea828bd..b1b93d152 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1123,13 +1123,13 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_getPresenceMod RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model) } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv* env +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; } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index b763107d7..cf587e370 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -705,7 +705,7 @@ public interface LinphoneCore { * * @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} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index bc9d3d1ba..b28646c7b 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -83,7 +83,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native int getPresenceInfo(long nativePtr); private native void setPresenceModel(long nativePtr, long presencePtr); private native Object getPresenceModel(long nativePtr); - private native long createChatRoom(long nativePtr,String to); + 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 void setFirewallPolicy(long nativePtr, int enum_value); @@ -385,8 +385,8 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized PresenceModel getPresenceModel() { return (PresenceModel)getPresenceModel(nativePtr); } - public synchronized LinphoneChatRoom createChatRoom(String to) { - return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to)); + public synchronized LinphoneChatRoom getOrCreateChatRoom(String to) { + return new LinphoneChatRoomImpl(getOrCreateChatRoom(nativePtr,to)); } public synchronized void setPreviewWindow(Object w) { setPreviewWindowId(nativePtr,w); From 679624223898212549d46757e52646a95b9ab8b8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 12 Aug 2013 14:32:25 +0200 Subject: [PATCH 585/909] Added JNI glue for markAsRead LinphoneChatRoom method + get all the messages with getHistory method if limit <= 0 --- coreapi/linphonecore_jni.cc | 8 +++++++- coreapi/message_storage.c | 11 ++++++++--- java/common/org/linphone/core/LinphoneChatRoom.java | 5 +++++ java/impl/org/linphone/core/LinphoneChatRoomImpl.java | 5 +++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b1b93d152..b877a1f1b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2049,7 +2049,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIE extern "C" jlongArray Java_org_linphone_core_LinphoneChatRoomImpl_getHistory(JNIEnv* env ,jobject thiz ,jlong ptr) { - MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, 20); + MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, 0); int historySize = ms_list_size(history); jlongArray jHistory = env->NewLongArray(historySize); jlong *jInternalArray = env->GetLongArrayElements(jHistory, NULL); @@ -2088,6 +2088,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv ,jlong ptr) { linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); } +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) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index c556e267e..c276cd58e 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -196,11 +196,16 @@ void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); MSList *ret; + char *buf; + char *peer; if (lc->db==NULL) return NULL; - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); cr->messages_hist = NULL; - char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",peer,nb_message); + if (nb_message > 0) + buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",peer,nb_message); + else + buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC;",peer); linphone_sql_request_message(lc->db,buf,cr); sqlite3_free(buf); ret=cr->messages_hist; @@ -225,7 +230,7 @@ void linphone_create_table(sqlite3* db){ } void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { - if (lc->db==NULL) return NULL; + if (lc->db==NULL) return; char *buf=sqlite3_mprintf("SELECT remoteContact FROM history Group By remoteContact;"); linphone_sql_request_all(lc->db,buf,lc); sqlite3_free(buf); diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index cfea18f9f..9b1c4d289 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -70,4 +70,9 @@ public interface LinphoneChatRoom { * Deletes all the messages associated with the peer of this chat room */ void deleteHistory(); + + /** + * Marks all the messages in this conversation as read + */ + void markAsRead(); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index faead77ca..8885dbac2 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -30,6 +30,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void destroy(long ptr); private native int getUnreadMessagesCount(long ptr); private native void deleteHistory(long ptr); + private native void markAsRead(long ptr); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -77,4 +78,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void deleteHistory() { deleteHistory(nativePtr); } + + public void markAsRead() { + markAsRead(nativePtr); + } } From cb7d8ff93135a00c693b72e8270ed4f0d9610b90 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 12 Aug 2013 15:45:07 +0200 Subject: [PATCH 586/909] Change API to access sent and received video size via call parameters. --- coreapi/linphonecall.c | 46 ++++++++++++++++++------------------------ coreapi/linphonecore.h | 29 +++++++++++++------------- coreapi/private.h | 2 ++ 3 files changed, 37 insertions(+), 40 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 89cc397ce..0fa8fc0d7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -815,6 +815,18 @@ void linphone_call_unref(LinphoneCall *obj){ * Returns current parameters associated to the call. **/ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ + VideoStream *vstream; + + MS_VIDEO_SIZE_ASSIGN(call->current_params.sent_vsize, UNKNOWN); + MS_VIDEO_SIZE_ASSIGN(call->current_params.recv_vsize, UNKNOWN); +#ifdef VIDEO_ENABLED + vstream = call->videostream; + if (vstream != NULL) { + call->current_params.sent_vsize = video_stream_get_sent_video_size(vstream); + call->current_params.recv_vsize = video_stream_get_received_video_size(vstream); + } +#endif + return &call->current_params; } @@ -1061,6 +1073,14 @@ const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallP return cp->video_codec; } +MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp) { + return cp->sent_vsize; +} + +MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp) { + return cp->recv_vsize; +} + /** * @ingroup call_control * Use to know if this call has been configured in low bandwidth mode. @@ -2508,32 +2528,6 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } -MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call) { - MSVideoSize vsize; - VideoStream *vstream; - MS_VIDEO_SIZE_ASSIGN(vsize, UNKNOWN); -#ifdef VIDEO_ENABLED - vstream = call->videostream; - if (vstream != NULL) { - vsize = video_stream_get_sent_video_size(vstream); - } -#endif - return vsize; -} - -MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call) { - MSVideoSize vsize; - VideoStream *vstream; - MS_VIDEO_SIZE_ASSIGN(vsize, UNKNOWN); -#ifdef VIDEO_ENABLED - vstream = call->videostream; - if (vstream != NULL) { - vsize = video_stream_get_received_video_size(vstream); - } -#endif - return vsize; -} - #ifndef USE_BELLESIP static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ #else diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2397ec293..2c9e46404 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -283,6 +283,21 @@ LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneC LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); +/** + * Gets the size of the video that is sent. + * @param[in] cp The call parameters for which to get the sent video size. + * @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); + +/** + * Gets the size of the video that is received. + * @param[in] cp The call paramaters for which to get the received video size. + * @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); + + /* * Note for developers: this enum must be kept synchronized with the SalPrivacy enum declared in sal.h */ @@ -592,20 +607,6 @@ LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_ **/ LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); -/** - * Gets the size of the video that is sent. - * @param[in] call The call for which to get the sent video size. - * @return The sent video size or MS_VIDEO_SIZE_UNKNOWN if not available. - */ -LINPHONE_PUBLIC MSVideoSize linphone_call_get_sent_video_size(const LinphoneCall *call); - -/** - * Gets the size of the video that is received. - * @param[in] call The call for which to get the received video size. - * @return The received video size or MS_VIDEO_SIZE_UNKNOWN if not available. - */ -LINPHONE_PUBLIC MSVideoSize linphone_call_get_received_video_size(const LinphoneCall *call); - /*keep this in sync with mediastreamer2/msvolume.h*/ /** diff --git a/coreapi/private.h b/coreapi/private.h index e5e7113aa..2cd0279ee 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -80,6 +80,8 @@ struct _LinphoneCallParams{ LinphoneMediaEncryption media_encryption; PayloadType *audio_codec; /*audio codec currently in use */ PayloadType *video_codec; /*video codec currently in use */ + MSVideoSize sent_vsize; /* Size of the video currently being sent */ + MSVideoSize recv_vsize; /* Size of the video currently being received */ int down_bw; int up_bw; int down_ptime; From c53e94d50444f801f04b71ffe4942cb42fc59a58 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 13 Aug 2013 09:44:14 +0200 Subject: [PATCH 587/909] update documentation for linphone-deps generation on windows fix compile errors with mingw --- README.mingw | 45 +++++++++++++++++++++++++++++++++++++-- configure.ac | 23 -------------------- coreapi/lpconfig.c | 15 +++++++------ coreapi/message_storage.c | 10 +++++---- linphone-deps.filelist | 6 +++--- 5 files changed, 61 insertions(+), 38 deletions(-) diff --git a/README.mingw b/README.mingw index be45614f2..e60a1e335 100644 --- a/README.mingw +++ b/README.mingw @@ -125,8 +125,10 @@ These notes are useful if you want to upgrade part of the software that is inclu linphone-deps packages. List of software included in linphone-deps: -libosip2 (compiled) -libeXosip2 (compiled) +antlr3c (compiled) +polarssl (compiled +belle-sip (compiled) +libsrtp (compiled) libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg) libtheora (from the web) libx264 (compiled from the version distributed from linphone's web site) @@ -142,6 +144,45 @@ Remarks: For every package compiled that goes into linphone-deps, .la files (libtool files) must be removed to avoid libtool errors. When running "make install DESTDIR=", somepath must be absolute and should not contain any ~ or space. +- building antlr3c + * download the sources with: + $ git clone -b linphone git://git.linphone.org/antlr3.git + * compile and install + $ cd runtime/C + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make + $ make install + $ make install DESTDIR=/home//antlr3c-install + $ cp + +- building polarssl + * download the sources with: + $ git clone -b linphone git://git.linphone.org/polarssl.git + * compile and install: + $ cd polarssl + $ make lib SHARED=1 WINDOWS=1 + $ make install DESTDIR=/usr + $ make install DESTDIR=/home//polarssl-install + +- building belle-sip + * download the sources with: + $ git clone git://git.linphone.org/belle-sip.git + * compile and install, assuming you have already compiled polarssl and antlr3c and installed in /. + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install && make install DESTDIR=/home//belle-sip-install + +- building libsrtp + * download the sources with + $ git clone git://git.linphone.org/srtp.git + * compile with + $ autoconf + $ ./configure --prefix=/usr + $ make libsrtp.a + $ make install + $ make install DESTDIR=/home//libsrtp-install + - building sqlite3 * download the sources on the following website: http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz) diff --git a/configure.ac b/configure.ac index 572a130cc..096e344f1 100644 --- a/configure.ac +++ b/configure.ac @@ -408,13 +408,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 @@ -445,22 +438,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 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 - if test "$console_ui" = "true" ; then dnl check gnu readline LP_CHECK_READLINE diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 8fbd094c8..d7a5d14f3 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -220,7 +220,7 @@ LpConfig * lp_config_new(const char *filename){ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); - struct stat fileStat; + if (config_filename!=NULL){ ms_message("Using (r/w) config information from %s", config_filename); lpconfig->filename=ortp_strdup(config_filename); @@ -229,11 +229,14 @@ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *fa lp_config_parse(lpconfig,lpconfig->file); fclose(lpconfig->file); #if !defined(WIN32) - if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { - /* make existing configuration files non-group/world-accessible */ - if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) { - ms_warning("unable to correct permissions on " - "configuration file: %s", strerror(errno)); + { + struct stat fileStat; + if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { + /* make existing configuration files non-group/world-accessible */ + if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) { + ms_warning("unable to correct permissions on " + "configuration file: %s", strerror(errno)); + } } } #endif /*WIN32*/ diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index c276cd58e..d9195166d 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -81,12 +81,12 @@ static int callback_all(void *data, int argc, char **argv, char **colName){ LinphoneCore* lc = (LinphoneCore*) data; char* address = argv[0]; linphone_core_create_chat_room(lc, address); - return 0; + return 0; } static int callback(void *data, int argc, char **argv, char **colName){ - create_chat_message(argv,data); - return 0; + create_chat_message(argv,data); + return 0; } void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ @@ -230,8 +230,10 @@ void linphone_create_table(sqlite3* db){ } void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { + char *buf; + if (lc->db==NULL) return; - char *buf=sqlite3_mprintf("SELECT remoteContact FROM history Group By remoteContact;"); + buf=sqlite3_mprintf("SELECT remoteContact FROM history Group By remoteContact;"); linphone_sql_request_all(lc->db,buf,lc); sqlite3_free(buf); } diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 98d759b14..0d3949825 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -2,12 +2,12 @@ ./bin/avutil-51.dll ./bin/libeay32.dll ./bin/ssleay32.dll -./bin/libeXosip2-7.dll +./bin/libbellesip-0.dll +./bin/libantlr3c.dll +./lib/libpolarssl.dll ./bin/libogg-0.dll ./bin/libtheora-0.dll ./bin/libxml2-2.dll -./bin/libosip2-7.dll -./bin/libosipparser2-7.dll ./bin/swscale-2.dll ./bin/libsoup-2.4-1.dll ./bin/libgcrypt-11.dll From 2260c829467c58926e7f401880a35f6181c6d9ff Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 13 Aug 2013 10:29:45 +0200 Subject: [PATCH 588/909] Fix linphonecsh manpage (Debian patch) --- share/C/linphonecsh.1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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) From 16a577f93f780e92bdfe6c18eab8910c779fc261 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 13 Aug 2013 10:30:33 +0200 Subject: [PATCH 589/909] Add config parameter (still uses main linphonerc for LANG). --- gtk/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gtk/main.c b/gtk/main.c index b7505dd87..7b0bbe9b1 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -82,6 +82,7 @@ static gchar *workingdir=NULL; static char *progpath=NULL; gchar *linphone_logfile=NULL; static gboolean workaround_gtk_entry_chinese_bug=FALSE; +static gchar *custom_config_file=NULL; static GOptionEntry linphone_options[]={ { @@ -133,6 +134,13 @@ static GOptionEntry linphone_options[]={ .arg_data = (gpointer) & workingdir, .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)") }, + { + .long_name = "config", + .short_name = '\0', + .arg = G_OPTION_ARG_STRING, + .arg_data = (gpointer) &custom_config_file, + .description = N_("Configuration file") + }, {0} }; @@ -1925,6 +1933,8 @@ int main(int argc, char *argv[]){ gdk_threads_leave(); return -1; } + if (config_file) free(config_file); + config_file=linphone_gtk_get_config_file(custom_config_file); settings=gtk_settings_get_default(); g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM)); From 88a0da21c15c3ac031e55b40e219aebee85e82b0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 13 Aug 2013 15:08:11 +0200 Subject: [PATCH 590/909] Added storage_id field to LinphoneChatMessage struct + method to delete a single message in message_storage API + JNI glue for this method --- coreapi/chat.c | 5 +++-- coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 6 ++++++ coreapi/message_storage.c | 21 +++++++++++++++++-- coreapi/private.h | 3 ++- .../org/linphone/core/LinphoneChatRoom.java | 6 ++++++ .../linphone/core/LinphoneChatRoomImpl.java | 6 ++++++ 7 files changed, 43 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 537a4b7ae..0be6b0bbd 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -136,7 +136,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); - linphone_chat_message_store(msg); + msg->storage_id=linphone_chat_message_store(msg); } /** @@ -220,7 +220,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_chat_message_set_external_body_url(msg, sal_msg->url); } linphone_address_destroy(addr); - linphone_chat_message_store(msg); + msg->storage_id=linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); ms_free(from); @@ -473,6 +473,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) new_message->cb=msg->cb; new_message->time=msg->time; new_message->state=msg->state; + new_message->storage_id=msg->storage_id; if (msg->from) new_message->from=linphone_address_clone(msg->from); return new_message; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2c9e46404..0e5963bf5 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -862,6 +862,7 @@ LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); +LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b877a1f1b..19be90590 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2088,6 +2088,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv ,jlong ptr) { linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); } +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env + ,jobject thiz + ,jlong room + ,jlong msg) { + linphone_chat_room_delete_message((LinphoneChatRoom*)room, (LinphoneChatMessage*)msg); +} extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_markAsRead(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index d9195166d..016188d6b 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -73,6 +73,7 @@ static void create_chat_message(char **argv, void *data){ new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); new_message->is_read=atoi(argv[6]); new_message->state=atoi(argv[7]); + new_message->storage_id=atoi(argv[0]); cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } @@ -120,8 +121,9 @@ void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ } } -void linphone_chat_message_store(LinphoneChatMessage *msg){ +unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); + int id=0; if (lc->db){ char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); @@ -132,7 +134,9 @@ void linphone_chat_message_store(LinphoneChatMessage *msg){ 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){ @@ -181,6 +185,16 @@ int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ return numrows; } +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=cr->lc; + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("delete from history where id = %i;", msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ LinphoneCore *lc=cr->lc; @@ -264,7 +278,7 @@ void linphone_core_message_storage_close(LinphoneCore *lc){ #else -void linphone_chat_message_store(LinphoneChatMessage *cr){ +unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ } void linphone_chat_message_store_state(LinphoneChatMessage *cr){ @@ -277,6 +291,9 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ return NULL; } +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ } diff --git a/coreapi/private.h b/coreapi/private.h index 2cd0279ee..c61344b40 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -141,6 +141,7 @@ struct _LinphoneChatMessage { SalCustomHeader *custom_headers; LinphoneChatMessageState state; bool_t is_read; + unsigned int storage_id; }; typedef struct StunCandidate{ @@ -734,7 +735,7 @@ void linphone_upnp_destroy(LinphoneCore *lc); sqlite3 * linphone_message_storage_init(); void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif -void linphone_chat_message_store(LinphoneChatMessage *msg); +unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index 9b1c4d289..c55d495a8 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -75,4 +75,10 @@ public interface LinphoneChatRoom { * Marks all the messages in this conversation as read */ void markAsRead(); + + /** + * Deletes a message + * @param message the message to delete + */ + void deleteMessage(LinphoneChatMessage message); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 8885dbac2..e576fad0b 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -31,6 +31,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native int getUnreadMessagesCount(long ptr); private native void deleteHistory(long ptr); private native void markAsRead(long ptr); + private native void deleteMessage(long room, long message); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -82,4 +83,9 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void markAsRead() { markAsRead(nativePtr); } + + public void deleteMessage(LinphoneChatMessage message) { + if (message != null) + deleteMessage(nativePtr, message.getNativePtr()); + } } From 33b271f06f02bcc987c56da0db70bad4428356cc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 13 Aug 2013 15:25:42 +0200 Subject: [PATCH 591/909] Remove "min" from the bitrate column of codecs configuration. --- gtk/propertybox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index f30b55d05..fc260d0b2 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -399,7 +399,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){ "foreground",CODEC_COLOR, NULL); gtk_tree_view_append_column (listview, column); - column = gtk_tree_view_column_new_with_attributes (_("Min bitrate (kbit/s)"), + column = gtk_tree_view_column_new_with_attributes (_("Bitrate (kbit/s)"), renderer, "text", CODEC_BITRATE, "foreground",CODEC_COLOR, From 96b4affccf6575708dc7d3939bc35b1cf157181a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 13 Aug 2013 15:26:08 +0200 Subject: [PATCH 592/909] Update ms2 submodule for video bandwidth limit. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6a35ffc77..fc727716f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6a35ffc7745d6748a43cebd7347f6af89a913593 +Subproject commit fc727716f2cbfe9e654a772713a87f0c4c9fec5c From d56d927caf4c22554e333ff3227628da2d370a65 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 13 Aug 2013 16:41:59 +0200 Subject: [PATCH 593/909] Added external_body_url column in chat storage --- coreapi/message_storage.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 016188d6b..73d781a88 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -74,6 +74,7 @@ static void create_chat_message(char **argv, void *data){ new_message->is_read=atoi(argv[6]); new_message->state=atoi(argv[7]); new_message->storage_id=atoi(argv[0]); + new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL; cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } @@ -128,8 +129,8 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); char datebuf[26]; - char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", - local_contact,peer,msg->dir,msg->message,my_ctime_r(&msg->time,datebuf),msg->is_read,msg->state); + char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q);", + local_contact,peer,msg->dir,msg->message,my_ctime_r(&msg->time,datebuf),msg->is_read,msg->state,msg->external_body_url); linphone_sql_request(lc->db,buf); sqlite3_free(buf); ms_free(local_contact); @@ -243,6 +244,18 @@ void linphone_create_table(sqlite3* db){ } } +void linphone_update_table(sqlite3* db) { + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_warning("Table already up to date: %s.\n", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table updated successfuly."); + } +} + void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { char *buf; @@ -263,6 +276,7 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ sqlite3_close(db); } linphone_create_table(db); + linphone_update_table(db); lc->db=db; // Create a chatroom for each contact in the chat history From d16f15f1ede12976507625ac28cb2b0376027818 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 13 Aug 2013 18:04:04 +0200 Subject: [PATCH 594/909] do not send 501 to out of dialog BYE, but rather 481. --- NEWS | 5 +++-- coreapi/bellesip_sal/sal_impl.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a85eae026..8797315b0 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,5 @@ linphone-3.7...?? + Liblinphone level improvements thanks to belle-sip new SIP stack: * multiple SIP transports simualtaneously now allowed * IP dual stack: can use IPv6 and IPv4 simultaneously * fully asynchronous behavior: no more lengthly DNS or connections @@ -7,8 +8,8 @@ linphone-3.7...?? * better management of network disconnections * SIP/TLS handled through lightweighted polarssl library (instead of openssl) * SIP transaction state machines improved (RFC6026) - * Privacy API - * Full support of rich presence + * Privacy API (RFC3323, RFC3325) + * Full support of rich presence in (RFC4480) linphone-3.6.1 -- June 17, 2013 diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index e8ff58595..ab943db49 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -208,6 +208,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ belle_sip_provider_send_response(((Sal*)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*)sal)->prov,resp); + return; }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,501); From b3c08e5d7ebbc30b1448f7a288f667c86904e6e2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 14 Aug 2013 11:17:18 +0200 Subject: [PATCH 595/909] Added method to update message's url field in database in case of changes --- coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 7 +++++++ coreapi/message_storage.c | 13 +++++++++++++ java/common/org/linphone/core/LinphoneChatRoom.java | 6 ++++++ .../org/linphone/core/LinphoneChatRoomImpl.java | 6 ++++++ 5 files changed, 33 insertions(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0e5963bf5..6fe0fc7c4 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -860,6 +860,7 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneC LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); +LINPHONE_PUBLIC void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg); LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 19be90590..677b45b8a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2100,6 +2100,13 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_markAsRead(JNIEnv* linphone_chat_room_mark_as_read((LinphoneChatRoom*)ptr); } +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_updateUrl(JNIEnv* env + ,jobject thiz + ,jlong room + ,jlong msg) { + linphone_chat_room_update_url((LinphoneChatRoom*)room, (LinphoneChatMessage*)msg); +} + extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 73d781a88..62d0c3a54 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -165,6 +165,16 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ ms_free(peer); } +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("update history set url=%Q where id=%i;",msg->external_body_url,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); int numrows=0; @@ -320,6 +330,9 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ void linphone_core_message_storage_close(LinphoneCore *lc){ } +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ return 0; } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index c55d495a8..f6708d0f4 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -81,4 +81,10 @@ public interface LinphoneChatRoom { * @param message the message to delete */ void deleteMessage(LinphoneChatMessage message); + + /** + * Update the value stored in the database for the external_body_url field + * @param message to update + */ + void updateUrl(LinphoneChatMessage message); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index e576fad0b..f93c428c3 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -32,6 +32,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void deleteHistory(long ptr); private native void markAsRead(long ptr); private native void deleteMessage(long room, long message); + private native void updateUrl(long room, long message); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -88,4 +89,9 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { if (message != null) deleteMessage(nativePtr, message.getNativePtr()); } + + public void updateUrl(LinphoneChatMessage message) { + if (message != null) + updateUrl(nativePtr, message.getNativePtr()); + } } From 86ade2174cb4342b312654f3063b5687d472cf7f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 14 Aug 2013 15:32:18 +0200 Subject: [PATCH 596/909] add two new methods to access pointers to transferer call and transfer target call. --- coreapi/linphonecall.c | 34 +++++++++++++++++++++++++++++ coreapi/linphonecore.c | 49 ++++++++++++++++++++++++++---------------- coreapi/linphonecore.h | 23 +++++++++++--------- coreapi/private.h | 2 ++ tester/call_tester.c | 11 ++++++++++ 5 files changed, 91 insertions(+), 28 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0fa8fc0d7..46daca009 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -743,6 +743,15 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const sal_op_release(call->op); call->op=NULL; } + /*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/ + if (call->transferer){ + linphone_call_unref(call->transferer); + call->transferer=NULL; + } + if (call->transfer_target){ + linphone_call_unref(call->transfer_target); + call->transfer_target=NULL; + } linphone_call_unref(call); } } @@ -773,6 +782,12 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->refer_to){ ms_free(obj->refer_to); } + if (obj->transferer){ + linphone_call_unref(obj->transferer); + } + if (obj->transfer_target){ + linphone_call_unref(obj->transfer_target); + } if (obj->owns_call_log) linphone_call_log_destroy(obj->log); if (obj->auth_token) { @@ -940,6 +955,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->transferer; +} + +/** + * 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). **/ @@ -2468,6 +2498,10 @@ void linphone_call_log_completed(LinphoneCall *call){ call_logs_write_to_config_file(lc); } +/** + * Returns the current transfer state, if a transfer has been initiated from this call. + * @see linphone_core_transfer_call() , linphone_core_transfer_call_to_another() +**/ LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { return call->transfer_state; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 426c85c3e..0184afab0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2333,7 +2333,10 @@ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ call->refer_pending=FALSE; newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); linphone_call_params_destroy(cp); - if (newcall) linphone_core_notify_refer_state(lc,call,newcall); + if (newcall) { + call->transfer_target=linphone_call_ref(newcall); + linphone_core_notify_refer_state(lc,call,newcall); + } } } @@ -2670,6 +2673,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_unref(call); return NULL; } + if (params && params->referer){ + call->transferer=linphone_call_ref(params->referer); + } + /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); @@ -2728,6 +2735,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { @@ -2764,6 +2775,10 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * This method will send a transfer request to the transfered person. The phone of the transfered is then * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically * close the call with us (the 'dest' call). + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ int result = sal_call_refer_with_replaces (call->op,dest->op); @@ -3312,25 +3327,23 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) call = the_call; } 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; + 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; - } - - default: - sal_call_terminate(call->op); - break; } - terminate_call(lc,call); return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6fe0fc7c4..97f94fc83 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -121,7 +121,9 @@ struct _LinphoneCall; typedef struct _LinphoneCall LinphoneCall; /** - * Enum describing failure reasons. + * Enum describing various failure reasons or contextual information for some events. + * @see linphone_call_get_reason() + * @see linphone_proxy_config_get_error() * @ingroup misc **/ enum _LinphoneReason{ @@ -134,8 +136,7 @@ enum _LinphoneReason{ LinphoneReasonBusy, /**identity); MSList* lcs=ms_list_append(NULL,marie->lc); @@ -946,6 +948,7 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(call(marie,pauline)); + marie_calling_pauline=linphone_core_get_current_call(marie->lc); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); reset_counters(&marie->stat); @@ -961,6 +964,9 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); @@ -970,6 +976,11 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + + marie_calling_laure=linphone_core_get_current_call(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure); + CU_ASSERT_TRUE(linphone_call_get_transferer_call(marie_calling_laure)==marie_calling_pauline); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); /*terminate marie to pauline call*/ From 01d35e5b53fca8358e2b9b8dc67d47b4cca4327f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 14 Aug 2013 16:08:26 +0200 Subject: [PATCH 597/909] wrap new methods --- coreapi/linphonecore_jni.cc | 26 +++++++++++++++++++ .../org/linphone/core/LinphoneCall.java | 12 +++++++++ .../org/linphone/core/LinphoneCallImpl.java | 10 +++++++ 3 files changed, 48 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 677b45b8a..91a5ec19d 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1911,6 +1911,32 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransferState( return linphone_call_get_transfer_state(call); } +/* + * Class: org_linphone_core_LinphoneCallImpl + * Method: getTransfererCall + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransfererCall(JNIEnv *env, jobject jCall, jlong callptr){ + LinphoneCall *call=(LinphoneCall*)callptr; + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCall *ret=linphone_call_get_transferer_call(call); + return lcdata->getCall(env,ret); +} + +/* + * Class: org_linphone_core_LinphoneCallImpl + * Method: getTransferTargetCall + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransferTargetCall(JNIEnv *env, jobject jCall, jlong callptr){ + LinphoneCall *call=(LinphoneCall*)callptr; + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCall *ret=linphone_call_get_transfer_target_call(call); + return lcdata->getCall(env,ret); +} + extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoCancellation( JNIEnv* env ,jobject thiz ,jlong ptr diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 35dc9008b..62be0d638 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -303,4 +303,16 @@ public interface LinphoneCall { * Send an info message to remote peer. */ void sendInfoMessage(LinphoneInfoMessage msg); + + /** + * Returns the transferer if this call was started automatically as a result of an incoming transfer request. + * The call in which the transfer request was received is returned in this case. + **/ + LinphoneCall getTransfererCall(); + + /** + * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. + **/ + LinphoneCall getTransferTargetCall(); + } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 5c681506f..e55ac22b0 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -217,4 +217,14 @@ class LinphoneCallImpl implements LinphoneCall { 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); + } } From 90b6aa36f2982cb7cce7ebd50d9dfafd20d4274e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 14 Aug 2013 16:48:22 +0200 Subject: [PATCH 598/909] Added some methods to allow to create a chat message completely and to store a chat message in database + JNI bindings for these methods --- coreapi/chat.c | 38 +++++++++++++++++++ coreapi/linphonecore.h | 3 ++ coreapi/linphonecore_jni.cc | 28 ++++++++++++++ coreapi/message_storage.c | 1 + coreapi/private.h | 1 - .../linphone/core/LinphoneChatMessage.java | 5 +++ .../org/linphone/core/LinphoneChatRoom.java | 9 +++++ .../core/LinphoneChatMessageImpl.java | 5 +++ .../linphone/core/LinphoneChatRoomImpl.java | 12 +++++- 9 files changed, 100 insertions(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 0be6b0bbd..94177c07a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -270,6 +270,34 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con return msg; } +/** + * Create a message attached to a dedicated chat room; + * @param cr the chat room. + * @param message text message, NULL if absent. + * @return a new #LinphoneChatMessage + */ +LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + + LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); + msg->chat_room=(LinphoneChatRoom*)cr; + msg->message=message?ms_strdup(message):NULL; + msg->external_body_url=external_body_url?ms_strdup(external_body_url):NULL; + msg->time=time; + msg->state=state; + msg->is_read=is_read; + if (is_incoming) { + msg->dir=LinphoneChatMessageIncoming; + linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_to(msg, linphone_address_new(linphone_core_get_identity(lc))); + } else { + msg->dir=LinphoneChatMessageOutgoing; + linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(lc))); + } + return msg; +} + /** * Send a message to peer member of this chat room. * @param cr #LinphoneChatRoom object @@ -368,6 +396,16 @@ const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* return message->from; } +/** + * Set destination of the message + *@param message #LinphoneChatMessage obj + *@param to #LinphoneAddress destination of this message (copied) + */ +void linphone_chat_message_set_to(LinphoneChatMessage* message, const LinphoneAddress* to) { + if(message->to) linphone_address_destroy(message->to); + message->to=linphone_address_clone(to); +} + /** * Get destination of the message *@param message #LinphoneChatMessage obj diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 97f94fc83..c9a4e0d8e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -860,6 +860,7 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(Linphon LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); +LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); @@ -873,6 +874,7 @@ LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc); +LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); @@ -880,6 +882,7 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneC LINPHONE_PUBLIC void linphone_chat_message_destroy(LinphoneChatMessage* msg); LINPHONE_PUBLIC void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_set_to(LinphoneChatMessage* message, const LinphoneAddress* from); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 91a5ec19d..9ece97c30 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2104,6 +2104,27 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM return (jlong) chatMessage; } +extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatMessage2(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jmessage + ,jstring jurl + ,jint state + ,jlong time + ,jboolean read + ,jboolean incoming) { + const char* message = jmessage?env->GetStringUTFChars(jmessage, NULL):NULL; + const char* url = jurl?env->GetStringUTFChars(jurl, NULL):NULL; + + LinphoneChatMessage *chatMessage = linphone_chat_room_create_message_2((LinphoneChatRoom *)ptr, message, url, (LinphoneChatMessageState)state, (time_t)time, read, incoming); + + if (jmessage != NULL) + env->ReleaseStringUTFChars(jmessage, message); + if (jurl != NULL) + env->ReleaseStringUTFChars(jurl, url); + + return (jlong) chatMessage; +} extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getUnreadMessagesCount(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -2145,6 +2166,13 @@ extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEn jobject ud = env->NewGlobalRef(thiz); linphone_chat_message_set_user_data((LinphoneChatMessage*)ptr,(void*) ud); } + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_store(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_store((LinphoneChatMessage*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 62d0c3a54..0aca430dd 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -125,6 +125,7 @@ void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); int id=0; + if (lc->db){ char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); diff --git a/coreapi/private.h b/coreapi/private.h index 261145364..c0e112716 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -737,7 +737,6 @@ void linphone_upnp_destroy(LinphoneCore *lc); sqlite3 * linphone_message_storage_init(); void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif -unsigned int linphone_chat_message_store(LinphoneChatMessage *msg); void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 6a539d740..f44997d5e 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -130,4 +130,9 @@ public interface LinphoneChatMessage { * @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(); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index f6708d0f4..44ed0b38d 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; + +import org.linphone.core.LinphoneChatMessage.State; + /** * * A chat room is the place where text messages are exchanged. @@ -87,4 +90,10 @@ public interface LinphoneChatRoom { * @param message to update */ void updateUrl(LinphoneChatMessage message); + + /** + * Create a LinphoneChatMessage + * @return LinphoneChatMessage object + */ + LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index ac308aa92..670d6f9a7 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -12,6 +12,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native int getStatus(long ptr); private native boolean isRead(long ptr); private native boolean isOutgoing(long ptr); + private native void store(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -84,4 +85,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public boolean isOutgoing() { return isOutgoing(nativePtr); } + + public void store() { + store(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index f93c428c3..d8e425b04 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; +import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneChatMessage.StateListener; class LinphoneChatRoomImpl implements LinphoneChatRoom { @@ -33,6 +34,9 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void markAsRead(long ptr); private native void deleteMessage(long room, long message); private native void updateUrl(long room, long message); + private native long createLinphoneChatMessage2(long ptr, String message, + String url, int state, long timestamp, boolean isRead, + boolean isIncoming); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -49,7 +53,6 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { @Override public void sendMessage(LinphoneChatMessage message, StateListener listener) { sendMessage2(nativePtr, message.getNativePtr(), listener); - } @Override @@ -94,4 +97,11 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { if (message != null) updateUrl(nativePtr, message.getNativePtr()); } + + @Override + public LinphoneChatMessage createLinphoneChatMessage(String message, + String url, State state, long timestamp, boolean isRead, + boolean isIncoming) { + return new LinphoneChatMessageImpl(createLinphoneChatMessage2(nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + } } From 42261f4900f6ab42c9ce62f0f6ed18829c584bb8 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 14 Aug 2013 14:50:36 +0200 Subject: [PATCH 599/909] Make the call transfer even if the call ends --- README | 2 +- console/shell.c | 2 +- coreapi/bellesip_sal/sal_op_call_transfer.c | 3 ++ coreapi/callbacks.c | 3 ++ gtk/main.c | 1 + tester/call_tester.c | 53 +++++++++++++++++++-- 6 files changed, 59 insertions(+), 5 deletions(-) diff --git a/README b/README index 4a658cb17..0efd14949 100644 --- a/README +++ b/README @@ -32,7 +32,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. Here is the command line to get these dependencies installed for Ubuntu && Debian - $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libvxl1-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev + $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libvx-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev + for optional library $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev diff --git a/console/shell.c b/console/shell.c index e61a6e514..bfc758bf8 100644 --- a/console/shell.c +++ b/console/shell.c @@ -25,9 +25,9 @@ #ifdef WIN32 +#include #include #include -#include #include #include #else diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index c7fca7241..c996ab723 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -148,6 +148,9 @@ static int send_notify_for_refer(SalOp* op, const char *sipfrag){ } int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ + if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){ + return 0; + } belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; switch(state) { case BELLE_SIP_DIALOG_NULL: diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 534b488d0..16fa1ed1f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -540,6 +540,9 @@ static void call_terminated(SalOp *op, const char *from){ break; } ms_message("Current call terminated..."); + if (call->refer_pending){ + linphone_core_start_refered_call(lc,call); + } //we stop the call only if we have this current call or if we are in call if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) { linphone_core_stop_ringing(lc); diff --git a/gtk/main.c b/gtk/main.c index 7b0bbe9b1..65a7859e9 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef WIN32 #define chdir _chdir +#include "direct.h" #endif #if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4) diff --git a/tester/call_tester.c b/tester/call_tester.c index c57954843..8486d003f 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -80,6 +80,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, } } +#ifdef VIDEO_ENABLED static void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); @@ -91,8 +92,7 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { counters = (stats*)get_stats(lc); counters->number_of_IframeDecoded++; } - - +#endif bool_t call_with_params(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr @@ -870,10 +870,10 @@ static void call_with_declined_srtp(void) { } #ifdef VIDEO_ENABLED static void srtp_video_ice_call(void) { + int i=0; #else static void srtp_ice_call(void) { #endif - int i=0; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -993,6 +993,52 @@ static void simple_call_transfer(void) { ms_list_free(lcs); } +static void mean_call_transfer(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + LinphoneCall* pauline_called_by_marie; + + char* laure_identity=linphone_address_as_string(laure->identity); + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_called_by_marie=linphone_core_get_current_call(marie->lc); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + + linphone_core_transfer_call(marie->lc,pauline_called_by_marie,laure_identity); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*marie ends the call */ + linphone_core_terminate_call(marie->lc,pauline_called_by_marie); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + + /*Pauline starts the transfer*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + static void call_transfer_existing_call_outgoing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1097,6 +1143,7 @@ test_t call_tests[] = { { "Call with privacy", call_with_privacy }, { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, + { "Mean call transfer", mean_call_transfer }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, { "Call with ICE", call_with_ice }, { "Call with custom headers",call_with_custom_headers} From 440fabd247fbbb5865754951fa8ed3834fa92d5c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 19 Aug 2013 11:15:26 +0200 Subject: [PATCH 600/909] Fix for chat message importing --- coreapi/chat.c | 9 ++++++++- coreapi/linphonecore_jni.cc | 4 +++- java/impl/org/linphone/core/LinphoneChatRoomImpl.java | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 94177c07a..a0dc0a27e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -274,9 +274,16 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con * Create a message attached to a dedicated chat room; * @param cr the chat room. * @param message text message, NULL if absent. + * @param external_body_url the URL given in external body or NULL. + * @param state the LinphoneChatMessage.State of the message. + * @param time the time_t at which the message has been received/sent. + * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. + * @param is_incoming TRUE if the message has been received, FALSE otherwise. * @return a new #LinphoneChatMessage */ -LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) { +LinphoneChatMessage* linphone_chat_room_create_message_2( + LinphoneChatRoom *cr, const char* message, const char* external_body_url, + LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) { LinphoneCore *lc=linphone_chat_room_get_lc(cr); LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 9ece97c30..d179c043e 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2116,7 +2116,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM 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); + 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); diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index d8e425b04..48fad0220 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -102,6 +102,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming) { - return new LinphoneChatMessageImpl(createLinphoneChatMessage2(nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + return new LinphoneChatMessageImpl(createLinphoneChatMessage2( + nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); } } From 959334d7423c144c73094ca6fd4700e117ff3818 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 14 Aug 2013 13:53:18 +0200 Subject: [PATCH 601/909] Enable HD video on Android. --- build/android/common.mk | 3 +++ coreapi/linphonecore.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index adb73ff42..235030d13 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -79,6 +79,9 @@ LOCAL_CFLAGS += -DVIDEO_ENABLED ifeq ($(BUILD_X264),1) LOCAL_CFLAGS += -DHAVE_X264 endif +ifeq ($(LINPHONE_HD_VIDEO),1) +LOCAL_CFLAGS += -DENABLE_HD +endif endif ifeq ($(USE_JAVAH),1) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0184afab0..3a29eac4c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4954,10 +4954,10 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { static MSVideoSizeDef supported_resolutions[]={ #ifdef ENABLE_HD - { {MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H} , "1080p" }, - { {MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H} , "720p" }, + { { MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H } , "1080p" }, + { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, - { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H , "sxga-" }, + { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, #endif { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, From c852b3f8f708fcd80198ad39568034083b77a880 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 14 Aug 2013 16:17:02 +0200 Subject: [PATCH 602/909] Add the setPreferredVideoSizeByName() method to LinphoneCore. --- coreapi/linphonecore_jni.cc | 6 ++++++ java/common/org/linphone/core/LinphoneCore.java | 8 ++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d179c043e..c5ac65843 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2493,6 +2493,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JN linphone_core_set_preferred_video_size((LinphoneCore *)lc, vsize); } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSizeByName(JNIEnv *env, jobject thiz, jlong lc, jstring jName) { + const char* cName = env->GetStringUTFChars(jName, NULL); + linphone_core_set_preferred_video_size_by_name((LinphoneCore *)lc, cName); + env->ReleaseStringUTFChars(jName, cName); +} + extern "C" jintArray Java_org_linphone_core_LinphoneCoreImpl_getPreferredVideoSize(JNIEnv *env, jobject thiz, jlong lc){ MSVideoSize vsize = linphone_core_get_preferred_video_size((LinphoneCore *)lc); jintArray arr = env->NewIntArray(2); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index cf587e370..70097d014 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -863,6 +863,14 @@ public interface LinphoneCore { * **/ void setPreferredVideoSize(VideoSize vSize); + /** + * Sets the preferred video size giving a known size name. + * + * This applies only to the stream that is captured and sent to the remote party, + * since we accept all standard video size on the receive path. + * @param name A known video name (eg. vga or 720p) + **/ + void setPreferredVideoSizeByName(String name); /** * get current preferred video size for sending. * @return video size diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index b28646c7b..44632218d 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -95,6 +95,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setUploadBandwidth(long nativePtr, int bw); private native void setDownloadBandwidth(long nativePtr, int bw); private native void setPreferredVideoSize(long nativePtr, int width, int heigth); + private native void setPreferredVideoSizeByName(long nativePtr, String name); private native int[] getPreferredVideoSize(long nativePtr); private native void setRing(long nativePtr, String path); private native String getRing(long nativePtr); @@ -451,6 +452,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); From e033f0ed6991a28bce4309b4480a50a38d52f79c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 19 Aug 2013 11:41:19 +0200 Subject: [PATCH 603/909] Update ms2 submodule for HD video on Android. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index fc727716f..ded8abef2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit fc727716f2cbfe9e654a772713a87f0c4c9fec5c +Subproject commit ded8abef29f22d41f24a80ad5e19d2a0a5fa4cde From 4462b0aed0518af4fbe4f71c0db06f4afa4bc547 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 19 Aug 2013 15:42:30 +0200 Subject: [PATCH 604/909] Fix compilation error when MSG_STORAGE_ENABLED is not defined. --- coreapi/message_storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 0aca430dd..360f28f0a 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -304,6 +304,7 @@ void linphone_core_message_storage_close(LinphoneCore *lc){ #else unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ + return 0; } void linphone_chat_message_store_state(LinphoneChatMessage *cr){ From 34f405894cca981328688eb435d414552b2b345c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 20 Aug 2013 12:12:39 +0200 Subject: [PATCH 605/909] Added JNI binding to get message storage id + added possibility to limit the number of messages to fetch --- coreapi/chat.c | 9 +++++++++ coreapi/linphonecore.h | 2 +- coreapi/linphonecore_jni.cc | 11 +++++++++-- .../common/org/linphone/core/LinphoneChatMessage.java | 6 ++++++ java/common/org/linphone/core/LinphoneChatRoom.java | 7 +++++++ .../org/linphone/core/LinphoneChatMessageImpl.java | 5 +++++ java/impl/org/linphone/core/LinphoneChatRoomImpl.java | 8 ++++++-- 7 files changed, 43 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index a0dc0a27e..0bf27b12b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -494,6 +494,15 @@ bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message) { return message->dir == LinphoneChatMessageOutgoing; } +/** + * Returns the id used to identify this message in the storage database + * @param message the message + * @return the id + */ +unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message) { + return message->storage_id; +} + /** * Duplicate a LinphoneChatMessage **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c9a4e0d8e..f632bf66d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -897,7 +897,7 @@ LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name); LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); - +LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message); /** * @} */ diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index c5ac65843..b3f47f016 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2074,8 +2074,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIE //LinphoneChatRoom extern "C" jlongArray Java_org_linphone_core_LinphoneChatRoomImpl_getHistory(JNIEnv* env ,jobject thiz - ,jlong ptr) { - MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, 0); + ,jlong ptr + ,jint limit) { + MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, limit); int historySize = ms_list_size(history); jlongArray jHistory = env->NewLongArray(historySize); jlong *jInternalArray = env->GetLongArrayElements(jHistory, NULL); @@ -2251,6 +2252,12 @@ extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isOutgoing(JN return (jboolean) linphone_chat_message_is_outgoing((LinphoneChatMessage*)ptr); } +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStorageId(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_message_get_storage_id((LinphoneChatMessage*)ptr); +} + extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNIEnv* env ,jobject thiz ,jlong ptr) { diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index f44997d5e..8345df382 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -135,4 +135,10 @@ public interface LinphoneChatMessage { * THIS METHOD IS ONLY USED TO IMPORT OLD MESSAGES, DON'T USE IT FOR ANY OTHER USAGE! */ void store(); + + /** + * Returns the id used to id this message in the database + * @return the id used to id this message in the database + */ + int getStorageId(); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index 44ed0b38d..5c87f5647 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -58,6 +58,13 @@ public interface LinphoneChatRoom { */ LinphoneChatMessage[] getHistory(); + /** + * Returns the chat history associated with the peer address associated with this chat room + * @param limit the maximum number of messages to fetch + * @return an array of LinphoneChatMessage + */ + LinphoneChatMessage[] getHistory(int limit); + /** * Destroys a LinphoneChatRoom. */ diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 670d6f9a7..e86ab24b1 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -13,6 +13,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native boolean isRead(long ptr); private native boolean isOutgoing(long ptr); private native void store(long ptr); + private native int getStorageId(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -89,4 +90,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public void store() { store(nativePtr); } + + public int getStorageId() { + return getStorageId(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 48fad0220..b756c0b6d 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -27,7 +27,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native long getPeerAddress(long ptr); private native void sendMessage(long ptr, String message); private native void sendMessage2(long ptr, long message, StateListener listener); - private native long[] getHistory(long ptr); + private native long[] getHistory(long ptr, int limit); private native void destroy(long ptr); private native int getUnreadMessagesCount(long ptr); private native void deleteHistory(long ptr); @@ -61,7 +61,11 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { } public LinphoneChatMessage[] getHistory() { - long[] typesPtr = getHistory(nativePtr); + return getHistory(0); + } + + public LinphoneChatMessage[] getHistory(int limit) { + long[] typesPtr = getHistory(nativePtr, limit); if (typesPtr == null) return null; LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length]; From 641888f910dc819787509caa524c377c36ec5f33 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 Aug 2013 16:18:08 +0200 Subject: [PATCH 606/909] migrate rpm spec to belle sip --- Makefile.am | 2 +- configure.ac | 3 ++- coreapi/Makefile.am | 4 ++-- coreapi/linphonecall.c | 3 ++- linphone.spec.in | 19 ++++++++++--------- 5 files changed, 17 insertions(+), 14 deletions(-) mode change 100644 => 100755 Makefile.am mode change 100644 => 100755 configure.ac mode change 100644 => 100755 coreapi/Makefile.am mode change 100644 => 100755 coreapi/linphonecall.c mode change 100644 => 100755 linphone.spec.in diff --git a/Makefile.am b/Makefile.am old mode 100644 new mode 100755 index 44ed0c07b..02accc6ad --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts tools tester + coreapi console gtk share scripts tools tester include diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 096e344f1..046ad2c40 --- a/configure.ac +++ b/configure.ac @@ -696,7 +696,7 @@ AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes ) dnl for external use of linphone libs LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone" -LINPHONE_LIBS="-L${libdir} -llinphone" +LINPHONE_LIBS="-L${libdir} -llinphone -llpc2xml -lxml2lpc" AC_SUBST(LINPHONE_CFLAGS) AC_SUBST(LINPHONE_LIBS) @@ -796,6 +796,7 @@ AC_CONFIG_FILES([ m4/Makefile po/Makefile.in pixmaps/Makefile + include/Makefile coreapi/Makefile coreapi/help/Makefile coreapi/help/Doxyfile diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am old mode 100644 new mode 100755 index 69eff144e..65a6fef70 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -27,7 +27,7 @@ lib_LTLIBRARIES=liblinphone.la liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ offeranswer.c offeranswer.h\ - sal.c sal.h \ + sal.c \ callbacks.c \ misc.c \ address.c \ @@ -54,7 +54,7 @@ liblinphone_la_SOURCES+=upnp.c upnp.h endif liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ - bellesip_sal/sal_impl.c \ + bellesip_sal/sal_impl.c bellesip_sal/sal_impl.h \ bellesip_sal/sal_op_impl.c \ bellesip_sal/sal_op_call.c \ bellesip_sal/sal_op_registration.c \ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c old mode 100644 new mode 100755 index 46daca009..606d073e1 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -830,8 +830,9 @@ void linphone_call_unref(LinphoneCall *obj){ * Returns current parameters associated to the call. **/ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ +#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 diff --git a/linphone.spec.in b/linphone.spec.in old mode 100644 new mode 100755 index 86929b575..ca4654d9c --- a/linphone.spec.in +++ b/linphone.spec.in @@ -11,7 +11,7 @@ Name: linphone Version: @VERSION@ -Release: %(git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p' || echo '1')%{?dist} +Release: %(version=`git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p'` && if test -z "$version" ; then echo 0 ; else echo $version ; fi)%{?dist} Summary: Phone anywhere in the whole world by using the Internet Group: Applications/Communications @@ -24,7 +24,7 @@ BuildArch: i686 %endif BuildRequires: gtk2-devel -BuildRequires: libeXosip2-devel speex-devel gettext +BuildRequires: belle-sip-devel speex-devel gettext BuildRequires: intltool gettext-devel %if %{video} BuildRequires: ffmpeg-devel SDL-devel @@ -47,9 +47,6 @@ 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 \ @@ -85,7 +82,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root) %doc AUTHORS ChangeLog COPYING NEWS README TODO %{_bindir}/* -%{_libdir}/liblinphone.so.* +%{_libdir}/*.so.* %{_mandir}/* %{_datadir}/applications/%{name}.desktop %{_datadir}/pixmaps/linphone @@ -96,13 +93,17 @@ rm -rf $RPM_BUILD_ROOT %files devel %defattr(-,root,root) %{_includedir}/linphone -%{_libdir}/liblinphone.a -%{_libdir}/liblinphone.la -%{_libdir}/liblinphone.so +%{_libdir}/*.a +%{_libdir}/*.la +%{_libdir}/*.so %{_libdir}/pkgconfig/linphone.pc +%{_datadir}/tutorials/linphone/*.c %{_docdir} %changelog +* Mon Aug 19 2013 Jehan Monnier - 3.6.99 +- belle sip migration + * Wed Sep 28 2005 Francois-Xavier 'FiX' KOWALSKI - 1.2.0pre3 - Updated to latests Simon's work From d71d22a50743618ceef5c8df2233b27c340c40a5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 Aug 2013 16:18:53 +0200 Subject: [PATCH 607/909] fix file permision --- Makefile.am | 0 configure.ac | 0 coreapi/Makefile.am | 0 coreapi/linphonecall.c | 0 linphone.spec.in | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Makefile.am mode change 100755 => 100644 configure.ac mode change 100755 => 100644 coreapi/Makefile.am mode change 100755 => 100644 coreapi/linphonecall.c mode change 100755 => 100644 linphone.spec.in diff --git a/Makefile.am b/Makefile.am old mode 100755 new mode 100644 diff --git a/configure.ac b/configure.ac old mode 100755 new mode 100644 diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am old mode 100755 new mode 100644 diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c old mode 100755 new mode 100644 diff --git a/linphone.spec.in b/linphone.spec.in old mode 100755 new mode 100644 From c820f3f059ba711bf92981e17a2fdb92c061e506 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 Aug 2013 16:58:17 +0200 Subject: [PATCH 608/909] add missing makedile file --- include/Makefile.am | 1 + 1 file changed, 1 insertion(+) create mode 100755 include/Makefile.am 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 From 61226d36af11c05c7cf7e7593b837ce37f1cb209 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 Aug 2013 17:09:01 +0200 Subject: [PATCH 609/909] fix wrong prototype --- gtk/propertybox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 gtk/propertybox.c diff --git a/gtk/propertybox.c b/gtk/propertybox.c old mode 100644 new mode 100755 index fc260d0b2..f3179f2c9 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1100,7 +1100,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")); } From 6bf8c5c9fe65084f3779e1bcdeecf19d8c8e6c05 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 Aug 2013 17:09:18 +0200 Subject: [PATCH 610/909] fix wrong mode --- gtk/propertybox.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 gtk/propertybox.c diff --git a/gtk/propertybox.c b/gtk/propertybox.c old mode 100755 new mode 100644 From 42654a327cb81973f5aa6a0a3c2c40dd9b2662ef Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 21 Aug 2013 11:29:32 +0200 Subject: [PATCH 611/909] add LinphoneReasonUnauthorized --- coreapi/bellesip_sal/sal_op_impl.c | 8 ++++++++ coreapi/linphonecore.c | 2 ++ coreapi/linphonecore.h | 6 ++++-- coreapi/misc.c | 5 +++++ include/sal/sal.h | 3 ++- java/common/org/linphone/core/Reason.java | 4 ++++ tester/register_tester.c | 4 +++- 7 files changed, 28 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 5fe48f8c3..54a3b56dd 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -334,6 +334,9 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonRequestPending: ret=491; break; + case SalReasonUnauthorized: + ret=401; + break; } return ret; } @@ -343,6 +346,11 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal case 400: *sal_err=SalErrorUnknown; break; + case 401: + case 407: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonUnauthorized; + break; case 403: *sal_err=SalErrorFailure; *sal_reason=SalReasonForbidden; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3a29eac4c..6a47a8ca5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5787,6 +5787,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "IO error"; case LinphoneReasonDoNotDisturb: return "Do not distrub"; + case LinphoneReasonUnauthorized: + return "Unauthorized"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f632bf66d..3399402d3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -129,14 +129,16 @@ typedef struct _LinphoneCall LinphoneCall; enum _LinphoneReason{ LinphoneReasonNone, LinphoneReasonNoResponse, /**number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { linphone_core_iterate(lc); - if (counters->number_of_auth_info_requested>0 && late_auth_info) { + if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { + if (!linphone_core_get_auth_info_list(lc)) + CU_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized); info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } From 097a1c4ea88a5184dea467361050b7ae65644efd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 15:41:41 +0200 Subject: [PATCH 612/909] Fix HTTPS_CA_DIR in case of cross-compilation. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 046ad2c40..bc50e9bf3 100644 --- a/configure.ac +++ b/configure.ac @@ -77,7 +77,7 @@ AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) -case $host in +case $build in *-apple-darwin*) HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; From 44ab77ba7e9c2c672e80162fd43f989c12ecf164 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 16:30:15 +0200 Subject: [PATCH 613/909] An other try at fixing HTTPS_CA_DIR for cross-compilation. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index bc50e9bf3..b6a80b0c8 100644 --- a/configure.ac +++ b/configure.ac @@ -77,8 +77,8 @@ AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) -case $build in - *-apple-darwin*) +case $build_os in + darwin*) HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; esac From 3d0af970047214681b837e153121dff0603d787e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 16:41:15 +0200 Subject: [PATCH 614/909] Yet an other try. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b6a80b0c8..d589485d8 100644 --- a/configure.ac +++ b/configure.ac @@ -78,7 +78,7 @@ AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) case $build_os in - darwin*) + darwin|darwin*) HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; esac From 8e088948995befdd12d4302d8ac36fa03140064c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 16:50:10 +0200 Subject: [PATCH 615/909] One more time. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d589485d8..b6a91244e 100644 --- a/configure.ac +++ b/configure.ac @@ -77,8 +77,8 @@ AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) -case $build_os in - darwin|darwin*) +case "$build_os" in + *darwin*) HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; esac From 1edccc54af20d5090b2b8937a785e3d3330517b1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 16:59:12 +0200 Subject: [PATCH 616/909] Add some debug messages. --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index b6a91244e..5e3670161 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,10 @@ AC_SUBST(GUI_FLAGS) case "$build_os" in *darwin*) + echo "Defining HTTPS_CA_DIR" + echo `which openssl` + echo `openssl version -d` + echo `openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; esac From f000ec142fc731fc34f17eb1c5b5216591f3d195 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 Aug 2013 17:14:17 +0200 Subject: [PATCH 617/909] Revert "Add some debug messages." This reverts commit 1edccc54af20d5090b2b8937a785e3d3330517b1. --- configure.ac | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure.ac b/configure.ac index 5e3670161..b6a91244e 100644 --- a/configure.ac +++ b/configure.ac @@ -79,10 +79,6 @@ AC_SUBST(GUI_FLAGS) case "$build_os" in *darwin*) - echo "Defining HTTPS_CA_DIR" - echo `which openssl` - echo `openssl version -d` - echo `openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` ;; esac From f59ff446361c2f3ae80fb8fd3552b138b1c7aec6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 22 Aug 2013 15:28:37 +0200 Subject: [PATCH 618/909] Disable tests for RPM package build. --- linphone.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linphone.spec.in b/linphone.spec.in index ca4654d9c..e8e7b68a6 100644 --- a/linphone.spec.in +++ b/linphone.spec.in @@ -53,7 +53,7 @@ Libraries and headers required to develop software with linphone. %if !%{video} --disable-video \ %endif - --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp + --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp %__make %{?_smp_mflags} From 6d0e4f3525a56577cd3b0d2b48856e81227c7529 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 22 Aug 2013 15:49:56 +0200 Subject: [PATCH 619/909] Tutorials have nothing to do with tests. --- coreapi/help/Makefile.am | 3 --- 1 file changed, 3 deletions(-) diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 8beceab22..6ba24a9b1 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -31,7 +31,6 @@ endif clean-local: rm -rf doc -if ENABLE_TESTS #tutorials noinst_PROGRAMS=helloworld registration buddy_status chatroom notify @@ -63,8 +62,6 @@ LINPHONE_TUTOS+=$(notify_SOURCES) notify_LDADD=$(helloworld_LDADD) -endif - AM_CFLAGS=\ -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ From 92cfc41bf416c83f96a6cbf841c651bd849b0a3a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 26 Aug 2013 16:43:42 +0200 Subject: [PATCH 620/909] Update oRTP submodule for inline fix. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index bfc4e00cd..706f0b59f 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit bfc4e00cd6b6dd3e6d834ba17c6d0048cc46c280 +Subproject commit 706f0b59f818a69c673053e831fa1f19a855f80b From f03a9b38dd191227106a8a4e4ed5220366a1081e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 26 Aug 2013 16:57:44 +0200 Subject: [PATCH 621/909] add isVideoSupported java binding --- coreapi/linphonecore_jni.cc | 8 ++++++++ java/common/org/linphone/core/LinphoneCore.java | 7 +++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b3f47f016..e6c810766 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1147,6 +1147,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 diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 70097d014..ccadcd35e 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -738,6 +738,13 @@ public interface LinphoneCore { **/ int getVideoDevice(); + + /** + * Teturns true if the underlying sdk support video + * + * */ + boolean isVideoSupported(); + /** * Enables video globally. * diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 44632218d..141f887fa 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -86,6 +86,7 @@ class LinphoneCoreImpl implements LinphoneCore { 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); @@ -405,6 +406,9 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized boolean isVideoEnabled() { return isVideoEnabled(nativePtr); } + public synchronized boolean isVideoSupported() { + return isVideoSupported(nativePtr); + } public synchronized FirewallPolicy getFirewallPolicy() { return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr)); } From e400e38954e06a3f8bcc654bdc3ca5f98556f886 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 26 Aug 2013 17:07:29 +0200 Subject: [PATCH 622/909] update ms2 for fix --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ded8abef2..174725a01 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ded8abef29f22d41f24a80ad5e19d2a0a5fa4cde +Subproject commit 174725a01af56ff402abaf1041e0731f2aa97ecc From 88add42eb56c4c01d708720773e3b484f9c2a346 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 27 Aug 2013 17:40:47 +0200 Subject: [PATCH 623/909] add --disable-tutorials --- configure.ac | 11 +++++++++++ coreapi/help/Makefile.am | 3 +++ 2 files changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index b6a91244e..7954f08c5 100644 --- a/configure.ac +++ b/configure.ac @@ -740,6 +740,17 @@ AC_SUBST(ORTP_LIBS) AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) +AC_ARG_ENABLE(tutorials, + [AS_HELP_STRING([--disable-tutorials], [Disable compilation of tutorials])], + [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 diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 6ba24a9b1..d9320afd3 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -33,6 +33,8 @@ clean-local: #tutorials +if ENABLE_TUTORIALS + noinst_PROGRAMS=helloworld registration buddy_status chatroom notify helloworld_SOURCES=helloworld.c @@ -78,3 +80,4 @@ AM_CFLAGS=\ tutodir=$(datadir)/tutorials/linphone tuto_DATA=$(LINPHONE_TUTOS) +endif From bd95305d7febcba46a5509304cbbd8bb3bc6cab2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 27 Aug 2013 21:06:18 +0200 Subject: [PATCH 624/909] add reference counting to LinphoneAddress and SalAddress --- coreapi/address.c | 18 +++++++++++++++-- coreapi/bellesip_sal/sal_address_impl.c | 26 ++++++++++++++++++++----- coreapi/linphonecore.h | 6 ++++-- include/sal/sal.h | 2 ++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/coreapi/address.c b/coreapi/address.c index ad07819bc..4151765e4 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -43,6 +43,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". **/ @@ -153,10 +167,10 @@ bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddr } /** - * Destroys a LinphoneAddress object. + * Destroys a LinphoneAddress object (actually calls linphone_address_unref()). **/ void linphone_address_destroy(LinphoneAddress *u){ - sal_address_destroy(u); + sal_address_unref(u); } int linphone_address_get_port_int(const LinphoneAddress *u) { diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index c7f004bef..63f587173 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -103,18 +103,23 @@ void sal_address_set_display_name(SalAddress *addr, const char *display_name){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_header_address_set_displayname(header_addr,display_name); } + void sal_address_set_username(SalAddress *addr, const char *username){ SAL_ADDRESS_SET(addr,user,username); } + void sal_address_set_domain(SalAddress *addr, const char *host){ SAL_ADDRESS_SET(addr,host,host); } + void sal_address_set_port(SalAddress *addr, const char *port){ SAL_ADDRESS_SET(addr,port,atoi(port)); } + void sal_address_set_port_int(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); @@ -122,19 +127,17 @@ void sal_address_clean(SalAddress *addr){ belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr)); return ; } + char *sal_address_as_string(const SalAddress *addr){ return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); } + char *sal_address_as_string_uri_only(const SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); } -void sal_address_destroy(SalAddress *addr){ - belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); - belle_sip_object_unref(header_addr); - return ; -} + 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); @@ -148,3 +151,16 @@ void sal_address_set_transport(SalAddress* addr,SalTransport transport){ void sal_address_set_transport_name(SalAddress* addr,const char *transport){ SAL_ADDRESS_SET(addr,transport_param,transport); } + +SalAddress *sal_address_ref(SalAddress *addr){ + return (SalAddress*)belle_sip_object_ref(BELLE_SIP_HEADER_ADDRESS(addr)); +} + +void sal_address_unref(SalAddress *addr){ + belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr)); +} + +void sal_address_destroy(SalAddress *addr){ + sal_address_unref(addr); +} + diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 3399402d3..ac272eb47 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -161,8 +161,10 @@ const char *linphone_reason_to_string(LinphoneReason err); #include "linphone/event.h" #endif -LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *uri); -LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri); +LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr); +LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr); +LinphoneAddress * linphone_address_ref(LinphoneAddress *addr); +void linphone_address_unref(LinphoneAddress *addr); const char *linphone_address_get_scheme(const LinphoneAddress *u); LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u); LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u); diff --git a/include/sal/sal.h b/include/sal/sal.h index 43ecce862..427234f57 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -76,6 +76,8 @@ SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ SalAddress * sal_address_new(const char *uri); SalAddress * sal_address_clone(const SalAddress *addr); +SalAddress * sal_address_ref(SalAddress *addr); +void sal_address_unref(SalAddress *addr); const char *sal_address_get_scheme(const SalAddress *addr); const char *sal_address_get_display_name(const SalAddress* addr); const char *sal_address_get_display_name_unquoted(const SalAddress *addr); From 90ff3d477ae8aa2e42b6b6fca62137783e7c3fb8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 27 Aug 2013 22:11:53 +0200 Subject: [PATCH 625/909] better management of LinphoneAddress in java. Indeed there was some risk of getting into a situation where a java LinphoneAddress would point to a destroyed C LinphoneAddress (typically with call-logs). To prevent that, the java object can either refcount or clone the C object, depending on the constness of the C object. --- coreapi/linphonecore_jni.cc | 17 +++++++-- .../linphone/core/LinphoneAddressImpl.java | 36 ++++++++++++++----- .../org/linphone/core/LinphoneCallImpl.java | 3 +- .../linphone/core/LinphoneCallLogImpl.java | 4 +-- .../core/LinphoneChatMessageImpl.java | 4 +-- .../linphone/core/LinphoneChatRoomImpl.java | 2 +- .../org/linphone/core/LinphoneCoreImpl.java | 4 +-- .../org/linphone/core/LinphoneFriendImpl.java | 2 +- 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index e6c810766..b12eacaa6 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1566,10 +1566,23 @@ extern "C" jlong Java_org_linphone_core_LinphoneAddressImpl_newLinphoneAddressIm 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 diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index 54e7a408e..9eee7ff4f 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -21,10 +21,16 @@ 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); @@ -46,16 +52,28 @@ public class LinphoneAddressImpl implements LinphoneAddress { 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); diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index e55ac22b0..af79eb725 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -18,7 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - class LinphoneCallImpl implements LinphoneCall { protected final long nativePtr; @@ -81,7 +80,7 @@ class LinphoneCallImpl implements LinphoneCall { public LinphoneAddress getRemoteAddress() { long lNativePtr = getRemoteAddress(nativePtr); if (lNativePtr!=0) { - return new LinphoneAddressImpl(lNativePtr); + return new LinphoneAddressImpl(lNativePtr,LinphoneAddressImpl.WrapMode.FromConst); } else { return null; } 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/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index e86ab24b1..8ce49c747 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -42,7 +42,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { @Override public LinphoneAddress getPeerAddress() { - return new LinphoneAddressImpl(getPeerAddress(nativePtr)); + return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } @Override @@ -57,7 +57,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { @Override public LinphoneAddress getFrom() { - return new LinphoneAddressImpl(getFrom(nativePtr)); + return new LinphoneAddressImpl(getFrom(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } private native void addCustomHeader(long nativePtr, String name, String value); diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index b756c0b6d..7f4d684ee 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -43,7 +43,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { } public LinphoneAddress getPeerAddress() { - return new LinphoneAddressImpl(getPeerAddress(nativePtr)); + return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } public void sendMessage(String message) { diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 141f887fa..d5314b479 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -216,7 +216,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() { @@ -267,7 +267,7 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException { long lAddress = interpretUrl(nativePtr,destination); if (lAddress != 0) { - return new LinphoneAddressImpl(lAddress,true); + return new LinphoneAddressImpl(lAddress,LinphoneAddressImpl.WrapMode.FromNew); } else { throw new LinphoneCoreException("Cannot interpret ["+destination+"]"); } diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index 3b116f8ae..843170ce2 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -54,7 +54,7 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { this.setAddress(nativePtr, ((LinphoneAddressImpl)anAddress).nativePtr); } public LinphoneAddress getAddress() { - return new LinphoneAddressImpl(getAddress(nativePtr)); + return new LinphoneAddressImpl(getAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } public void setIncSubscribePolicy(SubscribePolicy policy) { setIncSubscribePolicy(nativePtr,policy.mValue); From 798bd06597f50870567c4828ce2cec5dcb081341 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 28 Aug 2013 11:23:47 +0200 Subject: [PATCH 626/909] prevent double notification of network reachable true or false. --- coreapi/bellesip_sal/sal_op_registration.c | 6 ++++++ coreapi/linphonecore.c | 7 ++++--- coreapi/proxy.c | 8 ++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 7c70bf18f..11a503bdd 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -76,6 +76,12 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_request_t *req; belle_sip_uri_t* req_uri; + if (op->refresher){ + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + op->type=SalOpRegister; sal_op_set_from(op,from); sal_op_set_to(op,from); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6a47a8ca5..6cb08c276 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5554,6 +5554,8 @@ static void linphone_core_uninit(LinphoneCore *lc) 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. ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); for(;elem!=NULL;elem=elem->next){ @@ -5569,9 +5571,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu lc->netup_time=curtime; lc->network_reachable=isReachable; - if (!lc->network_reachable) linphone_core_invalidate_friend_subscriptions(lc); - - if(!isReachable) { + if (!lc->network_reachable){ + linphone_core_invalidate_friend_subscriptions(lc); sal_reset_transports(lc->sal); } #ifdef BUILD_UPNP diff --git a/coreapi/proxy.c b/coreapi/proxy.c index aacde9920..a6fa96274 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1312,10 +1312,10 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat LinphoneCore *lc=cfg->lc; - 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)); + ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg, + linphone_proxy_config_get_identity(cfg), + linphone_registration_state_to_string(cfg->state), + linphone_registration_state_to_string(state)); if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ cfg->state=state; if (lc && lc->vtable.registration_state_changed){ From 50469413f014b67c8bc0c667070d7d0a5b8fd98d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 27 Aug 2013 16:57:58 +0200 Subject: [PATCH 627/909] fix crash when presence request is declined by an error sip message --- coreapi/bellesip_sal/sal_op_presence.c | 4 ++-- coreapi/presence.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index b88af986d..24ea3aefc 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -98,8 +98,8 @@ static void presence_response_event(void *op_base, const belle_sip_response_even belle_sip_header_expires_t* expires; if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { - ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); - op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); + ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); + op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ return; } set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); diff --git a/coreapi/presence.c b/coreapi/presence.c index 4b5f8425a..9f85d8af4 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1587,7 +1587,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; - LinphonePresenceModel *presence = (LinphonePresenceModel *)model; + 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)){ From 0b6d1df9c9150924fa7993613fc64c62dfd85e2b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 Aug 2013 17:28:26 +0200 Subject: [PATCH 628/909] allow compilation without network access --- share/Makefile.am | 15 +- share/archived-rootca.pem | 3895 +++++++++++++++++++++++++++++++++++++ 2 files changed, 3907 insertions(+), 3 deletions(-) create mode 100644 share/archived-rootca.pem diff --git a/share/Makefile.am b/share/Makefile.am index 391bc7053..3de8e2a43 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -31,13 +31,22 @@ pkgconfig_DATA=linphone.pc linphonedir=$(datadir)/linphone linphone_DATA=rootca.pem -rootca.pem: - HTTPS_CA_DIR=$(HTTPS_CA_DIR) $(top_srcdir)/scripts/mk-ca-bundle.pl rootca.pem + +#download root ca from mozilla using script from curl (mk-ca-bundle.pl). +#if that fails (no connection, no perl SSL...) , then a rootca bundle archived in the source tree is taken instead. +rootca.pem: + rm -f $(builddir)/fresh-rootca.pem + - HTTPS_CA_DIR=$(HTTPS_CA_DIR) $(top_srcdir)/scripts/mk-ca-bundle.pl $(builddir)/fresh-rootca.pem + if test -f $(builddir)/fresh-rootca.pem ; then \ + cp -f $(builddir)/fresh-rootca.pem $(builddir)/rootca.pem ; \ + else \ + cp -f $(srcdir)/archived-rootca.pem $(builddir)/rootca.pem ; \ + fi EXTRA_DIST = $(LINPHONE_SOUNDS) \ $(LINPHONE_RINGS) \ linphone.desktop.in \ linphone.pc.in \ Makefile.inc \ - rootca.pem + archived-rootca.pem 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----- +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 +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +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 +-----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----- +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 +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----- +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 +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +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 +-----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----- +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 +-----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----- +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 +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----- +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 +-----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----- +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 +-----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----- +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 +-----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----- From ca448eca016933c3fe864e1c4ca8918643c6e53b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 30 Aug 2013 12:33:58 +0200 Subject: [PATCH 629/909] fix make distcheck --- po/POTFILES.in | 1 - share/Makefile.am | 2 ++ tester/Makefile.am | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 4a4497cbd..8f1c5d3a6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -33,6 +33,5 @@ coreapi/presence.c coreapi/friend.c coreapi/proxy.c coreapi/callbacks.c -coreapi/sal_eXosip2.c coreapi/linphonecall.c diff --git a/share/Makefile.am b/share/Makefile.am index 3de8e2a43..85c1ab11b 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -50,3 +50,5 @@ EXTRA_DIST = $(LINPHONE_SOUNDS) \ Makefile.inc \ archived-rootca.pem +CLEANFILES=rootca.pem + diff --git a/tester/Makefile.am b/tester/Makefile.am index 25ac64865..b501f15fb 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -6,7 +6,7 @@ if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester TESTS=$(noinst_PROGRAMS) -liblinphone_tester_SOURCES= liblinphone_tester.c \ +liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ setup_tester.c \ register_tester.c \ message_tester.c \ From aeb78764822d1cc0fbf701fec80c02f4ac9c663e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 30 Aug 2013 21:29:29 +0200 Subject: [PATCH 630/909] transition to belle-sip automatic contact and new nat-helper. --- configure.ac | 2 +- coreapi/bellesip_sal/sal_impl.c | 72 +++------------------- coreapi/bellesip_sal/sal_impl.h | 3 +- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/bellesip_sal/sal_op_presence.c | 1 - coreapi/bellesip_sal/sal_op_registration.c | 7 +-- coreapi/linphonecore.c | 4 +- include/sal/sal.h | 1 + 8 files changed, 18 insertions(+), 74 deletions(-) diff --git a/configure.ac b/configure.ac index 7954f08c5..c4042828a 100644 --- a/configure.ac +++ b/configure.ac @@ -681,7 +681,7 @@ if test x$enable_msg_storage != xfalse; then fi -PKG_CHECK_MODULES(BELLESIP, [belle-sip]) +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.1.0]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" SIPSTACK_LIBS="$BELLESIP_LIBS" diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ab943db49..7930a0f04 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -271,15 +271,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } else { SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_header_contact_t* original_contact; - belle_sip_header_address_t* contact_address=NULL; - belle_sip_header_via_t* via_header; - belle_sip_uri_t* contact_uri; - unsigned int contact_port; - const char* received; - int rport; - bool_t contact_updated=FALSE; - char* new_contact; if (op->state == SalOpStateTerminated) { belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); @@ -295,59 +286,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); if (op->callbacks.process_response_event) { - - if (op->base.root->nat_helper_enabled) { - /*Fix contact if needed*/ - via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); - received = belle_sip_header_via_get_received(via_header); - rport = belle_sip_header_via_get_rport(via_header); - if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { - /*update contact with sent values in any cases*/ - contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_object_unref(contact_address); - } - if (sal_op_get_contact(op)){ - if (received!=NULL || rport>0) { - contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } - - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) - ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; - } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); - } - } - if (contact_updated) { - char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_free(new_contact); - belle_sip_free(old_contact); - } - if (contact_address)belle_sip_object_unref(contact_address); - } - } - } /*handle authorization*/ switch (response_code) { @@ -422,7 +360,7 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event Sal * sal_init(){ belle_sip_listener_callbacks_t listener_callbacks; Sal * sal=ms_new0(Sal,1); - sal->nat_helper_enabled=TRUE; + sal->auto_contacts=TRUE; sal->user_agent=belle_sip_header_user_agent_new(); #if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION) belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); @@ -432,6 +370,7 @@ Sal * sal_init(){ belle_sip_set_log_handler(_belle_sip_log); sal->stack = belle_sip_stack_new(NULL); sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); + sal_nat_helper_enable(sal,TRUE); memset(&listener_callbacks,0,sizeof(listener_callbacks)); listener_callbacks.process_dialog_terminated=process_dialog_terminated; listener_callbacks.process_io_error=process_io_error; @@ -727,6 +666,7 @@ void sal_set_recv_error(Sal *sal,int 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) { @@ -878,9 +818,15 @@ belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_req belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); 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; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 3989ee54a..096aa0598 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -38,13 +38,14 @@ struct Sal{ unsigned int keep_alive; char *root_ca; char *uuid; + int refresher_retry_after; /*retry after value for refresher*/ bool_t one_matching_codec; bool_t use_tcp_tls_keep_alive; bool_t nat_helper_enabled; bool_t tls_verify; bool_t tls_verify_cn; bool_t use_dates; - int refresher_retry_after; /*retry after value for refresher*/ + bool_t auto_contacts; }; typedef enum SalOpState { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 54a3b56dd..29aa88729 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -92,6 +92,7 @@ belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ } else { contact_header= belle_sip_header_contact_new(); } + 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); @@ -463,7 +464,6 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp belle_sip_object_unref(op->refresher); } if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { - belle_sip_refresher_enable_nat_helper(op->refresher,op->base.root->nat_helper_enabled); belle_sip_refresher_set_listener(op->refresher,listener,op); belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); return 0; diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 24ea3aefc..ca6b86cab 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -125,7 +125,6 @@ static void presence_response_event(void *op_base, const belle_sip_response_even } if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); - belle_sip_refresher_enable_nat_helper(op->refresher,op->base.root->nat_helper_enabled); belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); } } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 11a503bdd..cfdedc9e5 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -28,12 +28,7 @@ static void register_refresher_listener ( const belle_sip_refresher_t* refresher SalReason sal_reason; belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))); ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); - /*fix contact if needed*/ - if (op->base.root->nat_helper_enabled && belle_sip_refresher_get_nated_contact(refresher)) { - belle_sip_header_address_t* contact_address = BELLE_SIP_HEADER_ADDRESS(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_refresher_get_nated_contact(refresher)))); - sal_op_set_contact_address(op,(SalAddress*)contact_address); - belle_sip_object_unref(contact_address); - } + 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*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6cb08c276..eaebda6fe 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4484,10 +4484,12 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy 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; + 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; } diff --git a/include/sal/sal.h b/include/sal/sal.h index 427234f57..239bd949c 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -443,6 +443,7 @@ void sal_reuse_authorization(Sal *ctx, bool_t enabled); void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec); void sal_use_rport(Sal *ctx, bool_t use_rports); void sal_use_101(Sal *ctx, bool_t use_101); +void sal_enable_auto_contacts(Sal *ctx, bool_t enabled); void sal_set_root_ca(Sal* ctx, const char* rootCa); const char *sal_get_root_ca(Sal* ctx); void sal_verify_server_certificates(Sal *ctx, bool_t verify); From e1c0e1aa4fefcdd1d4099f6bc87edea397fb5885 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 2 Sep 2013 16:33:36 +0200 Subject: [PATCH 631/909] bugfix when adding body to request: previous body, content-type and content-lenght must first be removed. --- coreapi/bellesip_sal/sal_op_impl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 29aa88729..de08eb2b4 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -514,6 +514,9 @@ const char *sal_op_get_remote_contact(const SalOp *op){ } 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_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)); From 7c16a6d9db09346fe5f4050a7593160ae782584c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 2 Sep 2013 17:42:08 +0200 Subject: [PATCH 632/909] do not put contact_params (from proxy config) into calls, message or subscribes. They are only valid for REGISTERs. --- coreapi/linphonecall.c | 15 +++++---------- coreapi/linphonecore.c | 13 ++++++++++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 606d073e1..db5af1ba7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2628,11 +2628,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , } void linphone_call_set_contact_op(LinphoneCall* call) { -#ifndef USE_BELLESIP - char *contact; -#else LinphoneAddress *contact; -#endif 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 */ @@ -2641,11 +2637,10 @@ void linphone_call_set_contact_op(LinphoneCall* call) { contact=get_fixed_contact(call->core,call,call->dest_proxy); if (contact){ + SalTransport tport=sal_address_get_transport((SalAddress*)contact); + sal_address_clean((SalAddress*)contact); /* clean out contact_params that come from proxy config*/ + sal_address_set_transport((SalAddress*)contact,tport); sal_op_set_contact(call->op, contact); -#ifndef USE_BELLESIP - ms_free(contact); -#else - linphone_address_destroy(contact); -#endif -} + linphone_address_destroy(contact); + } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eaebda6fe..111354375 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2615,10 +2615,17 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d sal_op_set_to_address(op,dest); sal_op_set_from(op,identity); sal_op_set_sent_custom_header(op,headers); - if (with_contact && proxy && proxy->op && sal_op_get_contact(proxy->op)){ - sal_op_set_contact(op,sal_op_get_contact(proxy->op)); + if (with_contact && proxy && proxy->op){ + const SalAddress *contact; + if ((contact=sal_op_get_contact(proxy->op))){ + SalTransport tport=sal_address_get_transport((SalAddress*)contact); + SalAddress *new_contact=sal_address_clone(contact); + sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/ + sal_address_set_transport(new_contact,tport); + sal_op_set_contact(op,new_contact); + sal_address_destroy(new_contact); + } } - } /** From b9d374d8f607611e504b2b8d59658237db551420 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Sep 2013 17:51:49 +0200 Subject: [PATCH 633/909] Store firewall policy in linphonerc as a string. --- coreapi/linphonecore.c | 57 +++++++++++++++++++++++++++++++++--------- coreapi/private.h | 1 - 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 111354375..6aa9fb015 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -490,14 +490,15 @@ static void net_config_read (LinphoneCore *lc) tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL); if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL; linphone_core_set_nat_address(lc,tmpstr); - tmp=lp_config_get_int(lc->config,"net","firewall_policy",0); - linphone_core_set_firewall_policy(lc,tmp); tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0); lc->net_conf.nat_sdp_only=tmp; tmp=lp_config_get_int(lc->config,"net","mtu",1300); linphone_core_set_mtu(lc,tmp); tmp=lp_config_get_int(lc->config,"net","download_ptime",0); linphone_core_set_download_ptime(lc,tmp); + + /* 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){ @@ -4468,13 +4469,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) { @@ -4502,11 +4522,24 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy } if (lc->sip_conf.contact) update_primary_contact(lc); if (linphone_core_ready(lc)) - lp_config_set_int(lc->config,"net","firewall_policy",pol); + lp_config_set_string(lc->config,"net","firewall_policy",policy); } LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ - return lc->net_conf.firewall_policy; + const char *policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL); + + if ((policy == NULL) || (strcmp(policy, "0") == 0)) + return LinphonePolicyNoFirewall; + else if ((strcmp(policy, "nat_address") == 0) || (strcmp(policy, "1") == 0)) + return LinphonePolicyUseNatAddress; + else if ((strcmp(policy, "stun") == 0) || (strcmp(policy, "2") == 0)) + return LinphonePolicyUseStun; + else if ((strcmp(policy, "ice") == 0) || (strcmp(policy, "3") == 0)) + return LinphonePolicyUseIce; + else if ((strcmp(policy, "upnp") == 0) || (strcmp(policy, "4") == 0)) + return LinphonePolicyUseUpnp; + else + return LinphonePolicyNoFirewall; } /** @@ -5586,11 +5619,11 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu } #ifdef BUILD_UPNP if(lc->upnp == NULL) { - if(isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + if(isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { lc->upnp = linphone_upnp_context_new(lc); } } else { - if(!isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + if(!isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { linphone_upnp_context_destroy(lc->upnp); lc->upnp = NULL; } diff --git a/coreapi/private.h b/coreapi/private.h index c0e112716..b508f366a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -497,7 +497,6 @@ typedef struct net_config char *relay; int download_bw; int upload_bw; - int firewall_policy; int mtu; bool_t nat_sdp_only; }net_config_t; From 6437055903d6d5d21a10f0ed4fde3c126ad4e4b4 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 3 Sep 2013 10:07:24 +0200 Subject: [PATCH 634/909] Set contact params in gtk UI --- gtk/main.c | 2 +- gtk/propertybox.c | 4 ++++ gtk/sip_account.ui | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 65a7859e9..60c6931ae 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -138,7 +138,7 @@ static GOptionEntry linphone_options[]={ { .long_name = "config", .short_name = '\0', - .arg = G_OPTION_ARG_STRING, + .arg = G_OPTION_ARG_FILENAME, .arg_data = (gpointer) &custom_config_file, .description = N_("Configuration file") }, diff --git a/gtk/propertybox.c b/gtk/propertybox.c index f3179f2c9..a6cee3d48 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -678,6 +678,8 @@ void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ linphone_proxy_config_get_addr(cfg)); tmp=linphone_proxy_config_get_route(cfg); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")),tmp); + tmp=linphone_proxy_config_get_contact_parameters(cfg); + if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")),tmp); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")), linphone_proxy_config_get_expires(cfg)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")), @@ -710,6 +712,8 @@ void linphone_gtk_proxy_ok(GtkButton *button){ gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")))); linphone_proxy_config_set_route(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); + linphone_proxy_config_set_contact_parameters(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")))); linphone_proxy_config_expires(cfg, (int)gtk_spin_button_get_value( GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")))); diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui index 60b751cfa..9c23c806d 100644 --- a/gtk/sip_account.ui +++ b/gtk/sip_account.ui @@ -91,7 +91,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 4 + 5 2 @@ -193,7 +193,7 @@ True True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False adjustment1 @@ -205,6 +205,38 @@ 4 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Contact params: + right + + + 4 + 5 + + + + + 275 + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True + False + False + + + 1 + 2 + 4 + 5 + + + True From bcfc3d9d9e81794070576ace79decd3944ca4231 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 3 Sep 2013 16:01:03 +0200 Subject: [PATCH 635/909] make sure proxyconfig with late credential move from state Failed to Progress --- coreapi/authentication.c | 8 +++++ tester/register_tester.c | 63 ++++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 1d0eaf15c..4682325e9 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -308,11 +308,19 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); 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++; } diff --git a/tester/register_tester.c b/tester/register_tester.c index f41f4863e..b84e1aec1 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -59,7 +59,13 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c } -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) { +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; @@ -98,22 +104,36 @@ static void register_with_refresh_base_2(LinphoneCore* lc, bool_t refresh,const while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { linphone_core_iterate(lc); if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { - if (!linphone_core_get_auth_info_list(lc)) + if (!linphone_core_get_auth_info_list(lc)) { CU_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized); - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + } } + if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials) + break; /*no need to continue*/ ms_usleep(100000); } - CU_ASSERT_TRUE(linphone_proxy_config_is_registered(proxy_cfg)); + CU_ASSERT_EQUAL(linphone_proxy_config_is_registered(proxy_cfg),(expected_final_state == LinphoneRegistrationOk)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); - CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,late_auth_info?1:0); + CU_ASSERT_TRUE(counters->number_of_LinphoneRegistrationProgress>=1); + if (expected_final_state == LinphoneRegistrationOk) { + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,late_auth_info?1:0); + } else + /*checking to be done outside this functions*/ CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); } +static void register_with_refresh_base_2(LinphoneCore* lc + , bool_t refresh + ,const char* domain + ,const char* route + ,bool_t late_auth_info + ,LCSipTransports transport) { + register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk ); +} static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { LCSipTransports transport = {5070,5070,0,5071}; register_with_refresh_base_2(lc,refresh,domain,route,FALSE,transport); @@ -275,6 +295,30 @@ static void authenticated_register_with_late_credentials(){ linphone_core_manager_destroy(mgr); } +static void authenticated_register_with_wrong_late_credentials(){ + LinphoneCoreManager *mgr; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + char route[256]; + const char* saved_test_passwd=test_password; + char* wrong_passwd="mot de pass tout pourrit"; + + test_password=wrong_passwd; + + sprintf(route,"sip:%s",test_route); + + mgr = linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + counters = get_stats(mgr->lc); + register_with_refresh_base_3(mgr->lc,FALSE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); + test_password=saved_test_passwd; + + linphone_core_manager_destroy(mgr); +} + static void authenticated_register_with_wrong_credentials(){ LinphoneCoreManager *mgr; stats* counters; @@ -289,7 +333,7 @@ static void authenticated_register_with_wrong_credentials(){ linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/ counters = get_stats(mgr->lc); - register_with_refresh_base_2(mgr->lc,TRUE,auth_domain,route,TRUE,transport); + register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_manager_destroy(mgr); } @@ -569,6 +613,7 @@ test_t register_tests[] = { { "Ha1 authenticated register", ha1_authenticated_register }, { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, { "Digest auth with wrong credentials", authenticated_register_with_wrong_credentials }, + { "Authenticated register with wrong late credentials", authenticated_register_with_wrong_late_credentials}, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, { "Register with refresh", simple_register_with_refresh }, { "Authenticated register with refresh", simple_auth_register_with_refresh }, From 9a671657c6edb30c188450ff257cb3dd88d839ee Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 3 Sep 2013 22:31:30 +0200 Subject: [PATCH 636/909] make use of bellesip's new dialog's request queue to fix bugs around transfer notification add notification of failed transfers (new test in call suite for that) In case of failed transfer, referer call is resumed (if necessary) and notified of the failure. remove deprecated code. --- configure.ac | 2 +- coreapi/bellesip_sal/sal_impl.c | 18 +------- coreapi/bellesip_sal/sal_op_call.c | 4 +- coreapi/bellesip_sal/sal_op_call_transfer.c | 46 +++++++++++++-------- coreapi/bellesip_sal/sal_op_events.c | 8 +++- coreapi/bellesip_sal/sal_op_info.c | 2 +- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/callbacks.c | 24 ++++++++--- coreapi/linphonecall.c | 19 ++++----- coreapi/linphonecore.c | 9 +--- coreapi/private.h | 3 +- include/sal/sal.h | 4 -- tester/call_tester.c | 37 ++++++++++++++++- tester/liblinphone_tester.h | 1 + 14 files changed, 105 insertions(+), 74 deletions(-) diff --git a/configure.ac b/configure.ac index c4042828a..90191ab53 100644 --- a/configure.ac +++ b/configure.ac @@ -681,7 +681,7 @@ if test x$enable_msg_storage != xfalse; then fi -PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.1.0]) +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.2.0]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" SIPSTACK_LIBS="$BELLESIP_LIBS" diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7930a0f04..f6f99cd93 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -565,26 +565,16 @@ void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; return ; } -void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ms_warning("sal_use_double_registrations is deprecated"); - return ; -} -void sal_reuse_authorization(Sal *ctx, bool_t enabled){ - ms_warning("sal_reuse_authorization is deprecated"); - 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 ; } -void sal_use_101(Sal *ctx, bool_t use_101){ - ms_warning("sal_use_101 is deprecated"); - return ; -} static void set_tls_properties(Sal *ctx){ belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS"); @@ -705,10 +695,6 @@ const char* sal_op_type_to_string(const SalOpType type) { } } -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ - ms_warning("sal_expire_old_registration_contacts not implemented "); -} - void sal_use_dates(Sal *ctx, bool_t enabled){ ctx->use_dates=enabled; } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 1a7b191a8..ce3595cdc 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -710,7 +710,7 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ int sal_call_send_dtmf(SalOp *h, char dtmf){ if (h->dialog){ - belle_sip_request_t *req=belle_sip_dialog_create_request(h->dialog,"INFO"); + belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO"); if (req){ int bodylen; char dtmf_body[128]={0}; @@ -789,7 +789,7 @@ void sal_call_send_vfu_request(SalOp *op){ 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_request(op->dialog,"INFO"); + 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"))); diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index c996ab723..964a02cf2 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -133,39 +133,49 @@ SalOp *sal_call_get_replaces(SalOp *op){ return NULL; } -static int send_notify_for_refer(SalOp* op, const char *sipfrag){ - belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); +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_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_set_body(BELLE_SIP_MESSAGE(notify),sipfrag,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){ if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){ return 0; } belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; switch(state) { - case BELLE_SIP_DIALOG_NULL: - case BELLE_SIP_DIALOG_EARLY: - send_notify_for_refer(op,"SIP/2.0 100 Trying\r\n"); - break; - case BELLE_SIP_DIALOG_CONFIRMED: - if(send_notify_for_refer(op,"SIP/2.0 200 Ok\r\n")) { - /* we need previous notify transaction to complete, so buffer the request for later*/ - /*op->sipfrag_pending="SIP/2.0 200 Ok\r\n";*/ - ms_error("Cannot notify 200 ok frag to [%p] for new op [%p]",op,newcall); - } - break; - default: - break; + 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; } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 2c490ce6b..cf67c992d 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -248,6 +248,10 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event belle_sip_transaction_t *last=belle_sip_dialog_get_last_transaction(op->dialog); belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last)); req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); + if (!req) { + ms_error("Cannot create subscribe refresh."); + return -1; + } if (expires==-1){ belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t); expires=belle_sip_header_expires_get_expires(eh); @@ -293,7 +297,7 @@ int sal_notify(SalOp *op, const SalBody *body){ if (!op->dialog) return -1; - if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1; + if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; if (set_event_name(op,(belle_sip_message_t*)notify)==-1){ belle_sip_object_unref(notify); @@ -310,7 +314,7 @@ int sal_notify(SalOp *op, const SalBody *body){ int sal_notify_close(SalOp *op){ belle_sip_request_t* notify; if (!op->dialog) return -1; - if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1; + if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; set_event_name(op,(belle_sip_message_t*)notify); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index 3b329515f..9abc73818 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ if (op->dialog){ - belle_sip_request_t *req=belle_sip_dialog_create_request(op->dialog,"INFO"); + belle_sip_request_t *req=belle_sip_dialog_create_queued_request(op->dialog,"INFO"); sal_op_add_body(op,(belle_sip_message_t*)req,body); return sal_op_send_request(op,req); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index ca6b86cab..5ea4cfe7b 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -306,7 +306,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi static belle_sip_request_t *create_presence_notify(SalOp *op){ - belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"); + 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")); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 16fa1ed1f..cba47183e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -467,7 +467,6 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We have been resumed.")); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); - linphone_call_set_transfer_state(call, LinphoneCallIdle); } static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ @@ -569,6 +568,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de char *msg603=_("Call declined."); const char *msg=details; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCall *referer=call->referer; if (call==NULL){ ms_warning("Call faillure reported on already terminated call."); @@ -650,11 +650,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } linphone_core_stop_ringing(lc); - 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); - } + linphone_call_stop_media_streams(call); #ifdef BUILD_UPNP linphone_call_delete_upnp_session(call); @@ -673,6 +669,22 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } else { linphone_call_set_state(call,LinphoneCallError,msg); } + + if (referer){ + /* + * 1- resume call automatically if we had to pause it before to execute the transfer + * 2- notify other party of the transfer faillure + * This must be done at the end because transferer call can't be resumed until transfer-target call is changed to error state. + * This must be done in this order because if the notify transaction will prevent the resume transaction to take place. + * On the contrary, the notify transaction is queued and then executed after the resume completes. + **/ + if (linphone_call_get_state(referer)==LinphoneCallPaused && referer->was_automatically_paused){ + /*resume to the call that send us the refer automatically*/ + linphone_core_resume_call(lc,referer); + referer->was_automatically_paused=FALSE; + } + linphone_core_notify_refer_state(lc,referer,call); + } } static void call_released(SalOp *op){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index db5af1ba7..ae2ff5f01 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -642,10 +642,6 @@ static void linphone_call_set_terminated(LinphoneCall *call){ 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){ @@ -727,7 +723,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const default: break; } - linphone_call_set_terminated (call); + linphone_call_set_terminated(call); } if (cstate == LinphoneCallConnected) { call->log->status=LinphoneCallSuccess; @@ -744,9 +740,9 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const 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->transferer){ - linphone_call_unref(call->transferer); - call->transferer=NULL; + if (call->referer){ + linphone_call_unref(call->referer); + call->referer=NULL; } if (call->transfer_target){ linphone_call_unref(call->transfer_target); @@ -782,8 +778,9 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->refer_to){ ms_free(obj->refer_to); } - if (obj->transferer){ - linphone_call_unref(obj->transferer); + if (obj->referer){ + linphone_call_unref(obj->referer); + obj->referer=NULL; } if (obj->transfer_target){ linphone_call_unref(obj->transfer_target); @@ -961,7 +958,7 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call){ * 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->transferer; + return call->referer; } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6aa9fb015..ee9585728 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -617,9 +617,6 @@ static void sip_config_read(LinphoneCore *lc) } sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1)); - sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1)); - sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0)); - sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0)); ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); if (ipv6==-1){ @@ -733,7 +730,6 @@ static void sip_config_read(LinphoneCore *lc) lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); - sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1)); sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); } @@ -2328,7 +2324,7 @@ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ if (call->refer_pending){ LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); LinphoneCall *newcall; - cp->has_video &= !!lc->video_policy.automatically_initiate; + cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/ cp->referer=call; ms_message("Starting new call to refered address %s",call->refer_to); call->refer_pending=FALSE; @@ -2681,9 +2677,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_unref(call); return NULL; } - if (params && params->referer){ - call->transferer=linphone_call_ref(params->referer); - } /* this call becomes now the current one*/ lc->current_call=call; diff --git a/coreapi/private.h b/coreapi/private.h index b508f366a..7c8dd1667 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -157,7 +157,6 @@ struct _LinphoneCall SalMediaDescription *localdesc; SalMediaDescription *resultdesc; LinphoneCallDir dir; - LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; @@ -198,7 +197,7 @@ struct _LinphoneCall int ping_time; unsigned int remote_session_id; unsigned int remote_session_ver; - LinphoneCall *transferer; /*if this call is the result of a transfer, transferer points to the call from which the transfer request was received.*/ + LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ bool_t refer_pending; bool_t media_pending; diff --git a/include/sal/sal.h b/include/sal/sal.h index 239bd949c..4305e4df0 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -436,13 +436,9 @@ void sal_disable_tunnel(Sal *ctx); * */ unsigned int sal_get_keepalive_period(Sal *ctx); void sal_use_session_timers(Sal *ctx, int expires); -void sal_use_double_registrations(Sal *ctx, bool_t enabled); -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled); void sal_use_dates(Sal *ctx, bool_t enabled); -void sal_reuse_authorization(Sal *ctx, bool_t enabled); void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec); void sal_use_rport(Sal *ctx, bool_t use_rports); -void sal_use_101(Sal *ctx, bool_t use_101); void sal_enable_auto_contacts(Sal *ctx, bool_t enabled); void sal_set_root_ca(Sal* ctx, const char* rootCa); const char *sal_get_root_ca(Sal* ctx); diff --git a/tester/call_tester.c b/tester/call_tester.c index 8486d003f..74364fb66 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -75,6 +75,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneTransferCallOutgoingEarlyMedia++;break; case LinphoneCallConnected :counters->number_of_LinphoneTransferCallConnected++;break; case LinphoneCallStreamsRunning :counters->number_of_LinphoneTransferCallStreamsRunning++;break; + case LinphoneCallError :counters->number_of_LinphoneTransferCallError++;break; default: CU_FAIL("unexpected event");break; } @@ -993,7 +994,7 @@ static void simple_call_transfer(void) { ms_list_free(lcs); } -static void mean_call_transfer(void) { +static void unattended_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); @@ -1039,6 +1040,37 @@ static void mean_call_transfer(void) { ms_list_free(lcs); } +static void unattended_call_transfer_with_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* pauline_called_by_marie; + + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_called_by_marie=linphone_core_get_current_call(marie->lc); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user"); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*Pauline starts the transfer*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + /* and immediately get an error*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); + + /*the error must be reported back to marie*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + + static void call_transfer_existing_call_outgoing_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1143,7 +1175,8 @@ test_t call_tests[] = { { "Call with privacy", call_with_privacy }, { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, - { "Mean call transfer", mean_call_transfer }, + { "Unattended call transfer", unattended_call_transfer }, + { "Unattended call transfer with error", unattended_call_transfer_with_error }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, { "Call with ICE", call_with_ice }, { "Call with custom headers",call_with_custom_headers} diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 36dc323af..70aeaf83e 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -109,6 +109,7 @@ typedef struct _stats { int number_of_LinphoneTransferCallOutgoingEarlyMedia; int number_of_LinphoneTransferCallConnected; int number_of_LinphoneTransferCallStreamsRunning; + int number_of_LinphoneTransferCallError; int number_of_LinphoneMessageReceived; int number_of_LinphoneMessageReceivedLegacy; From d5bd17079f39777b3fa77516e4bf6b68532b4e42 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Sep 2013 11:11:42 +0200 Subject: [PATCH 637/909] add LC_SIP_TRANSPORT_RANDOM value to better enable random sip port --- coreapi/linphonecore.c | 60 ++++++++++++++++++++++++------------------ coreapi/linphonecore.h | 13 +++++++++ tester/setup_tester.c | 34 ++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ee9585728..3ba4a5d54 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -610,7 +610,6 @@ static void sip_config_read(LinphoneCore *lc) LCSipTransports tr; int i,tmp; int ipv6; - int random_port; if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); @@ -629,24 +628,6 @@ static void sip_config_read(LinphoneCore *lc) tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",0); tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",0); - if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) - random_port=(0xDFFF&random())+1024; - else random_port=0; - - if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){ - tr.udp_port=5060; - } - - if (tr.udp_port>0 && random_port){ - tr.udp_port=random_port; - tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tcp_port>0 && random_port){ - tr.tcp_port=random_port; - tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tls_port>0 && random_port){ - tr.tls_port=random_port; - tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - } #ifdef __linux sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs")); @@ -1903,16 +1884,45 @@ static int apply_transports(LinphoneCore *lc){ * * @ingroup network_parameters **/ -int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * tr){ +int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * tr_config /*config to be saved*/){ + LCSipTransports tr=*tr_config; + int random_port=(0xDFFF&random())+1024; - if (transports_unchanged(tr,&lc->sip_conf.transports)) + if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) { + /*legacy random mode*/ + if (tr.udp_port>0 && 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*/ + } + } + if (tr.udp_port == LC_SIP_TRANSPORT_RANDOM) { + tr.udp_port=random_port; + } + if (tr.tcp_port == LC_SIP_TRANSPORT_RANDOM) { + tr.tcp_port=random_port; + } + if (tr.tls_port == LC_SIP_TRANSPORT_RANDOM) { + tr.tls_port=random_port+1; + } + + if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){ + tr.udp_port=5060; + } + + if (transports_unchanged(&tr,&lc->sip_conf.transports)) return 0; - memcpy(&lc->sip_conf.transports,tr,sizeof(*tr)); + memcpy(&lc->sip_conf.transports,&tr,sizeof(tr)); if (linphone_core_ready(lc)){ - lp_config_set_int(lc->config,"sip","sip_port",tr->udp_port); - lp_config_set_int(lc->config,"sip","sip_tcp_port",tr->tcp_port); - lp_config_set_int(lc->config,"sip","sip_tls_port",tr->tls_port); + lp_config_set_int(lc->config,"sip","sip_port",tr_config->udp_port); + lp_config_set_int(lc->config,"sip","sip_tcp_port",tr_config->tcp_port); + lp_config_set_int(lc->config,"sip","sip_tls_port",tr_config->tls_port); } if (lc->sal==NULL) return 0; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ac272eb47..8ef4192c0 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -51,6 +51,19 @@ typedef struct _LinphoneCore LinphoneCore; struct _LpConfig; +/** + * Disable a sip transport + * Use with #LCSipTransports + * @ingroup initializing + */ +#define LC_SIP_TRANSPORT_DISABLED 0 +/** + * Randomly chose a sip port for this transport + * Use with #LCSipTransports + * @ingroup initializing + */ +#define LC_SIP_TRANSPORT_RANDOM -1 + /** * Linphone core SIP transport ports. * Use with #linphone_core_set_sip_transports diff --git a/tester/setup_tester.c b/tester/setup_tester.c index d14dca0b8..06949f82c 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -19,9 +19,8 @@ #include #include "CUnit/Basic.h" #include "linphonecore.h" - #include "liblinphone_tester.h" - +#include "lpconfig.h" static void core_init_test(void) { @@ -39,10 +38,41 @@ static void linphone_address_test(void) { linphone_address_destroy(create_linphone_address(NULL)); } +static void core_sip_transport_test(void) { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + LCSipTransports tr; + memset (&v_table,0,sizeof(v_table)); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_get_sip_transports(lc,&tr); + CU_ASSERT_EQUAL(tr.udp_port,5060); /*default config*/ + CU_ASSERT_EQUAL(tr.tcp_port,0); /*default config*/ + CU_ASSERT_EQUAL(tr.tls_port,0); /*default config*/ + + tr.udp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tls_port=LC_SIP_TRANSPORT_RANDOM; + + linphone_core_set_sip_transports(lc,&tr); + linphone_core_get_sip_transports(lc,&tr); + + CU_ASSERT_NOT_EQUAL(tr.udp_port,5060); /*default config*/ + CU_ASSERT_NOT_EQUAL(tr.tcp_port,0); /*default config*/ + CU_ASSERT_NOT_EQUAL(tr.tls_port,0); /*default config*/ + + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_port",-2),LC_SIP_TRANSPORT_RANDOM); + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tcp_port",-2),LC_SIP_TRANSPORT_RANDOM); + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tls_port",-2),LC_SIP_TRANSPORT_RANDOM); + + linphone_core_destroy(lc); +} + test_t setup_tests[] = { { "Linphone Address", linphone_address_test }, { "Linphone core init/uninit", core_init_test }, + { "Linphone random transport port",core_sip_transport_test} }; test_suite_t setup_test_suite = { From 807129e269c9ce8db6b6044e7a41857b54b26634 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 4 Sep 2013 11:24:48 +0200 Subject: [PATCH 638/909] Fix defCallMethod warning --- tools/my_jni.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; \ From a9eaffb1b274f7752593ab2b9fd025aa604cb84f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Sep 2013 16:42:19 +0200 Subject: [PATCH 639/909] Remove multiple declarations of lp_config_read_file(). --- coreapi/lpconfig.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index b3d2aa892..aa65fb38f 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -89,6 +89,7 @@ LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); LINPHONE_PUBLIC LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_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. * @@ -96,7 +97,7 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * The default value string is returned if the config item isn't found. **/ LINPHONE_PUBLIC 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); + /** * Retrieves a configuration item as a range, given its section, key, and default min and max values. * @@ -105,6 +106,7 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * If FALSE is returned, min and max are filled respectively with default_min and default_max values. */ 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. * @@ -121,8 +123,6 @@ LINPHONE_PUBLIC int lp_config_get_int(const LpConfig *lpconfig,const char *secti **/ 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. * @@ -130,18 +130,21 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * The default float value is returned if the config item isn't found. **/ LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); + /** * Sets a string config item * * @ingroup misc **/ 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 */ 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 * @@ -169,30 +172,35 @@ LINPHONE_PUBLIC void lp_config_set_int64(LpConfig *lpconfig,const char *section, * @ingroup misc **/ LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); + /** * Writes the config file to disk. * * @ingroup misc **/ 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); + /** * 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); + /** * 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. * From 2123fcf383538ea8af0378008405e1c1a9c0014c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Sep 2013 11:26:51 +0200 Subject: [PATCH 640/909] Public API to set basic status, clear activities and add activities to a presence model. --- coreapi/linphonepresence.h | 28 ++++++++++ coreapi/presence.c | 108 ++++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index f275d59d4..d4cf6cfd0 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -243,6 +243,14 @@ void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); */ LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); +/** + * @brief 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); + /** * @brief Gets the timestamp of a presence model. * @param[in] model The #LinphonePresenceModel object to get the timestamp from. @@ -294,9 +302,29 @@ LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_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); +/** + * @brief Adds an activity to a presence model. + * @param[in] model The #LinphonePresenceModel object for which to add an activity. + * @param[in] activity The #LinphonePresenceActivityType to add to the model. + * @param[in] description An additional description of the activity to add to the model. 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_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); + +/** + * @brief 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); + /** * @brief Gets the first note of a presence model (there is usually only one). * @param[in] model The #LinphonePresenceModel object to get the note from. diff --git a/coreapi/presence.c b/coreapi/presence.c index 9f85d8af4..becf3afaf 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -306,51 +306,6 @@ static void presence_model_add_note(LinphonePresenceModel *model, struct _Linpho model->notes = ms_list_append(model->notes, note); } -static int presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { - struct _LinphonePresenceService *service; - char *id; - if (ms_list_size(model->services) > 0) { - ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); - ms_list_free(model->services); - model->services = NULL; - } - id = generate_presence_id(); - service = presence_service_new(id, basic_status); - ms_free(id); - if (service == NULL) return -1; - presence_model_add_service(model, service); - return 0; -} - -static void presence_model_clear_activities(LinphonePresenceModel *model) { - ms_list_for_each(model->persons, (MSIterateFunc)presence_person_clear_activities); -} - -static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { - char *id = NULL; - struct _LinphonePresencePerson *person = NULL; - struct _LinphonePresenceActivity *act = NULL; - - 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 = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); - } - act = presence_activity_new(acttype, description); - if (act == NULL) - return -1; - presence_person_add_activity(person, act); - - return 0; -} - static void presence_model_find_open_basic_status(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { if (service->status == LinphonePresenceBasicStatusOpen) { *status = LinphonePresenceBasicStatusOpen; @@ -423,6 +378,26 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph return status; } +int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { + struct _LinphonePresenceService *service; + char *id; + + if (model == NULL) return -1; + + if (ms_list_size(model->services) > 0) { + ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); + ms_list_free(model->services); + model->services = NULL; + } + id = generate_presence_id(); + service = presence_service_new(id, basic_status); + ms_free(id); + if (service == NULL) return -1; + + presence_model_add_service(model, service); + return 0; +} + static void presence_service_find_newer_timestamp(struct _LinphonePresenceService *service, time_t *timestamp) { if (service->timestamp > *timestamp) *timestamp = service->timestamp; @@ -532,15 +507,50 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP basic_status = LinphonePresenceBasicStatusOpen; break; } - if (presence_model_set_basic_status(model, basic_status) < 0) + if (linphone_presence_model_set_basic_status(model, basic_status) < 0) return -1; - presence_model_clear_activities(model); - if (presence_model_add_activity(model, acttype, description) < 0) + linphone_presence_model_clear_activities(model); + if (linphone_presence_model_add_activity(model, acttype, description) < 0) return -1; return 0; } +int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { + char *id = NULL; + struct _LinphonePresencePerson *person = NULL; + struct _LinphonePresenceActivity *act = NULL; + + if (model == 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 = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); + } + act = presence_activity_new(acttype, description); + if (act == NULL) + return -1; + + presence_person_add_activity(person, act); + return 0; +} + +int linphone_presence_model_clear_activities(LinphonePresenceModel *model) { + if (model == NULL) return -1; + + ms_list_for_each(model->persons, (MSIterateFunc)presence_person_clear_activities); + return 0; +} + struct _find_note_st { const char *lang; struct _LinphonePresenceNote *note; @@ -1292,7 +1302,7 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c acttype = LinphonePresenceActivityOffline; break; } - presence_model_add_activity(model, acttype, NULL); + linphone_presence_model_add_activity(model, acttype, NULL); } } From d9684b0c3b4511f1a8c491ba62ec725a16fe430b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Sep 2013 11:27:40 +0200 Subject: [PATCH 641/909] Fix wrong warning being output when a friend is offline. --- coreapi/friend.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 36743699d..158317612 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -355,9 +355,11 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ /* Rely on the basic status information. */ break; case LinphonePresenceActivityOnline: - case LinphonePresenceActivityOffline: /* Should not happen! */ - ms_warning("LinphonePresenceActivityOnline or LinphonePresenceActivityOffline should not happen here!"); + ms_warning("LinphonePresenceActivityOnline should not happen here!"); + break; + case LinphonePresenceActivityOffline: + online_status = LinphoneStatusOffline; break; } } From 9e9be3e05f6972d519ed144bfd246944ff078492 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Sep 2013 12:14:03 +0200 Subject: [PATCH 642/909] Java API to set basic status, clear activities and add activities to a presence model. --- coreapi/linphonecore_jni.cc | 34 +++++++++++++++++++ .../org/linphone/core/PresenceModel.java | 24 +++++++++++++ .../org/linphone/core/PresenceModelImpl.java | 18 ++++++++++ 3 files changed, 76 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b12eacaa6..a3acc1ec2 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3307,6 +3307,17 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_getBasicStatus(J 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 @@ -3389,6 +3400,29 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_setActivity(JNIE return res; } +/* + * 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, jint acttype, jstring description) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + jint res = (jint)linphone_presence_model_add_activity(model, (LinphonePresenceActivityType)acttype, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return res; +} + +/* + * 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 diff --git a/java/common/org/linphone/core/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java index 5a6a9bf93..8f4d3716d 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -27,6 +27,13 @@ public interface PresenceModel { */ 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. @@ -69,9 +76,26 @@ public interface PresenceModel { * @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 Adds an activity to a presence model. + * @param[in] activity The #PresenceActivityType to add to the model. + * @param[in] description An additional description of the activity to add to the model. Can be null if no additional description is to be added. + * @return 0 if successful, a value < 0 in case of error. + */ + int addActivity(PresenceActivityType activity, String description); + + /** + * @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. diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java index 0a7173036..3cafe3cd7 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -41,6 +41,12 @@ public class PresenceModelImpl implements PresenceModel { 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() { @@ -83,6 +89,18 @@ public class PresenceModelImpl implements PresenceModel { return setActivity(mNativePtr, activity.toInt(), description); } + private native int addActivity(long nativePtr, int activity, String description); + @Override + public int addActivity(PresenceActivityType activity, String description) { + return addActivity(mNativePtr, activity.toInt(), description); + } + + 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) { From 77b06af7a12f046acf46f2cfd592fd0070485d98 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 5 Sep 2013 17:19:24 +0200 Subject: [PATCH 643/909] fix crash and update ms2 --- coreapi/bellesip_sal/sal_impl.c | 7 ++++++- mediastreamer2 | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f6f99cd93..c86064e24 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -114,12 +114,17 @@ void sal_process_authentication(SalOp *op) { sal_add_pending_auth(op->base.root,op); if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { - request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)request); + request = belle_sip_dialog_create_queued_request_from(op->dialog,(const belle_sip_request_t *)request); is_within_dialog=TRUE; } else { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); } + if (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,request,response,&auth_list)) { if (is_within_dialog) { sal_op_send_request(op,request); diff --git a/mediastreamer2 b/mediastreamer2 index 174725a01..c516f225b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 174725a01af56ff402abaf1041e0731f2aa97ecc +Subproject commit c516f225bea6ac2132f3468235138e2dde6cfcda From 8f186adebbe8b2aef62ec27e1156a241becfdb4e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 9 Sep 2013 11:57:43 +0200 Subject: [PATCH 644/909] Fix compilation for WP --- coreapi/bellesip_sal/sal_op_call_transfer.c | 3 ++- coreapi/chat.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 964a02cf2..0fad03e83 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -161,10 +161,11 @@ static void notify_last_response(SalOp *op, SalOp *newcall){ } 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; } - belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; + 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"); diff --git a/coreapi/chat.c b/coreapi/chat.c index 0bf27b12b..539e552cd 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -71,10 +71,11 @@ static int chat_room_compare(LinphoneChatRoom* room, const char* to) { * @return #LinphoneChatRoom where messaging can take place. */ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) { - if (ms_list_size(lc->chatrooms) == 0) + MSList* found; +if (ms_list_size(lc->chatrooms) == 0) return linphone_core_create_chat_room(lc, to); - MSList* found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) chat_room_compare, to); + found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) chat_room_compare, to); if (found != NULL) { return (LinphoneChatRoom*)found->data; } else { From 92abb3d3e51e7d1fb996d39992295e101703d1a7 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 9 Sep 2013 12:41:12 +0200 Subject: [PATCH 645/909] an op is considered as secure if both from and to uri are sips --- coreapi/bellesip_sal/sal_impl.h | 5 +++++ coreapi/bellesip_sal/sal_op_call.c | 3 +-- coreapi/bellesip_sal/sal_op_impl.c | 20 +++++++++++++++++++- coreapi/bellesip_sal/sal_op_message.c | 1 + coreapi/proxy.c | 11 +++-------- gtk/chat.c | 2 +- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 096aa0598..d99235c4f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -119,6 +119,11 @@ 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) ; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index ce3595cdc..186195c73 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -612,7 +612,6 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){ /*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_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(h); belle_sip_header_contact_t* contact_header; if (!h->pending_server_trans) { @@ -634,7 +633,7 @@ int sal_call_accept(SalOp*h){ } } - if (contact && (contact_header=belle_sip_header_contact_create(contact))) { + if ((contact_header=sal_op_create_contact(h))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index de08eb2b4..b3e6dc12e 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -87,11 +87,19 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ belle_sip_header_contact_t* contact_header; + belle_sip_uri_t* contact_uri; if (sal_op_get_contact_address(op)) { contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); } else { contact_header= belle_sip_header_contact_new(); } + if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { + /*no uri, just creating a new one*/ + contact_uri=belle_sip_uri_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); + } + belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); + belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts); if (op->base.root->uuid){ if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ @@ -121,6 +129,9 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + + belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op)); + req=belle_sip_request_create( req_uri, method, @@ -240,7 +251,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req 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); } - belle_sip_uri_fix(next_hop_uri); + /* not really usefull belle_sip_uri_fix(next_hop_uri);*/ } if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ @@ -554,3 +565,10 @@ void sal_op_set_privacy(SalOp* op,SalPrivacyMask 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; +} diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 9cece2659..1e3dc12f0 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -143,6 +143,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co if (to) sal_op_set_to(op,to); op->dir=SalOpDirOutgoing; + req=sal_op_build_request(op,"MESSAGE"); if (sal_op_get_contact(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a6fa96274..3247f5086 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -114,7 +114,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * obj->reg_proxy=NULL; if (server_addr!=NULL && strlen(server_addr)>0){ - if (strstr(server_addr,"sip:")==NULL){ + if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){ modified=ms_strdup_printf("sip:%s",server_addr); addr=linphone_address_new(modified); ms_free(modified); @@ -182,11 +182,11 @@ int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) ms_free(obj->reg_route); obj->reg_route=NULL; } - if (route!=NULL){ + if (route!=NULL && route[0] !='\0'){ SalAddress *addr; char *tmp; /*try to prepend 'sip:' */ - if (strstr(route,"sip:")==NULL){ + if (strstr(route,"sip:")==NULL && strstr(route,"sips:")==NULL){ tmp=ms_strdup_printf("sip:%s",route); }else tmp=ms_strdup(route); addr=sal_address_new(tmp); @@ -259,13 +259,8 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) obj->lc=lc; linphone_proxy_config_done(obj); } -#ifndef USE_BELLESIP -static char *guess_contact_for_register(LinphoneProxyConfig *obj){ - char *ret=NULL; - #else LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *ret=NULL; -#endif LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); const char *host; diff --git a/gtk/chat.c b/gtk/chat.c index c1bb46713..40ad17252 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -466,7 +466,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, GtkWidget *w; gboolean send=TRUE; /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ - char *from=linphone_address_as_string ( linphone_chat_message_get_from ( msg ) ); + char *from=linphone_address_as_string_uri_only( linphone_chat_message_get_from ( msg ) ); w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); if ( w!=NULL ) { From 746b521cde009f08cc43fbc03a91fca2fd01ac94 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Sep 2013 12:48:40 +0200 Subject: [PATCH 646/909] fix zrtp compilation bug. --- build/android/common.mk | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index 235030d13..09cf9545a 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -188,9 +188,9 @@ 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 + LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto + LOCAL_SHARED_LIBRARIES += libzrtpcpp endif ifeq ($(BUILD_SRTP),1) @@ -199,10 +199,11 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 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 + LOCAL_STATIC_LIBRARIES += \ + libssl-static libcrypto-static endif ifeq ($(BUILD_SRTP),1) From 358516fd6809c797af015ab8a2dd62b0667195a6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Sep 2013 14:14:27 +0200 Subject: [PATCH 647/909] prevent publish to be sent while client is registering on the same proxy. --- coreapi/bellesip_sal/sal_impl.c | 6 ++++-- coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/callbacks.c | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c86064e24..4f88c257d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -114,7 +114,9 @@ void sal_process_authentication(SalOp *op) { sal_add_pending_auth(op->base.root,op); if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { - request = belle_sip_dialog_create_queued_request_from(op->dialog,(const belle_sip_request_t *)request); + request = belle_sip_dialog_create_request_from(op->dialog,request); + if (!request) + request = belle_sip_dialog_create_queued_request_from(op->dialog,request); is_within_dialog=TRUE; } else { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); @@ -346,7 +348,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans if (op && op->callbacks.process_transaction_terminated) { op->callbacks.process_transaction_terminated(op,event); } else { - ms_error("Unhandled transaction terminated [%p]",trans); + ms_message("Unhandled transaction terminated [%p]",trans); } if (op && client_transaction) sal_op_unref(op); /*because every client transaction ref op*/ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 186195c73..69aefd556 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -764,7 +764,7 @@ int sal_call_terminate(SalOp *op){ break; } default: { - ms_fatal("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); return -1; } } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cba47183e..6d0083ea0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -807,6 +807,12 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const } else { linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } + 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; + } if (error== SalErrorFailure && reason == SalReasonForbidden) { const char *realm=NULL,*username=NULL; if (sal_op_get_auth_requested(op,&realm,&username)==0){ From 88f9e557bb93bdc4badc75b0ee8bf72c4dbfc2d9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Sep 2013 15:26:08 +0200 Subject: [PATCH 648/909] force git tag and configure.ac to say the same thing --- coreapi/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 65a6fef70..ca91dd7c0 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,6 +1,7 @@ GITVERSION_FILE=liblinphone_gitversion.h GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp GITDESCRIBE=`git describe --always` +GIT_TAG=`git describe --abbrev=0` GITREVISION=`git rev-parse HEAD` ECHO=/bin/echo @@ -135,6 +136,10 @@ AM_CXXFLAGS=$(AM_CFLAGS) make_gitversion_h: if test "$(GITDESCRIBE)" != "" ; then \ + if test "$(GIT_TAG)" != $(PACKAGE_VERSION) ; then \ + echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ + exit 1; \ + fi ; \ $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ elif test "$(GITREVISION)" != "" ; then \ $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ From 263c07a75dc815793898a1f5f54c248b98751e67 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Sep 2013 15:37:08 +0200 Subject: [PATCH 649/909] Complete presence API to be able to add multiple presence services. --- coreapi/linphonepresence.h | 360 ++++++++++++++++++++++++++----------- coreapi/presence.c | 262 +++++++++++++++++---------- 2 files changed, 422 insertions(+), 200 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index d4cf6cfd0..563206b5a 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -150,6 +150,26 @@ struct _LinphonePresenceModel; */ 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. */ @@ -172,15 +192,9 @@ typedef struct _LinphonePresenceNote LinphonePresenceNote; -/** - * @brief Creates a default presence model. - * @returns The created presence model, NULL on error. - * @see linphone_presence_model_new_with_activity - * @see linphone_presence_model_new_with_activity_and_note - * - * The created presence model is considered 'offline'. - */ -LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); +/***************************************************************************** + * HELPER FUNCTIONS TO EASE ACCESS IN MOST SIMPLER CASES * + ****************************************************************************/ /** * @brief Creates a presence model specifying an activity. @@ -208,34 +222,6 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activit */ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType activity, const char *description, const char *note, const char *lang); -/** - * Increase the reference count of the #LinphonePresenceModel object. - * @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased. - * @return The #LinphonePresenceModel object with the increased reference count. - */ -LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); - -/** - * Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0. - * @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased. - * @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed. - */ -LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); - -/** - * Sets the user data of a #LinphonePresenceModel object. - * @param[in] model The #LinphonePresenceModel object for which to set the user data. - * @param[in] user_data A pointer to the user data to set. - */ -void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); - -/** - * Gets the user data of a #LinphonePresenceModel object. - * @param[in] model The #LinphonePresenceModel object for which to get the user data. - * @return A pointer to the user data. - */ -void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); - /** * @brief Gets the basic status of a presence model. * @param[in] model The #LinphonePresenceModel object to get the basic status from. @@ -271,23 +257,9 @@ LINPHONE_PUBLIC char * linphone_presence_model_get_contact(const LinphonePresenc * @brief 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 void linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact); - -/** - * @brief 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_nb_activities(const LinphonePresenceModel *model); - -/** - * @brief 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); +LINPHONE_PUBLIC int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact); /** * @brief Gets the first activity of a presence model (there is usually only one). @@ -309,22 +281,6 @@ LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_activity( */ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); -/** - * @brief Adds an activity to a presence model. - * @param[in] model The #LinphonePresenceModel object for which to add an activity. - * @param[in] activity The #LinphonePresenceActivityType to add to the model. - * @param[in] description An additional description of the activity to add to the model. 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_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); - -/** - * @brief 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); - /** * @brief Gets the first note of a presence model (there is usually only one). * @param[in] model The #LinphonePresenceModel object to get the note from. @@ -351,6 +307,235 @@ LINPHONE_PUBLIC int linphone_presence_model_add_note(LinphonePresenceModel *mode */ LINPHONE_PUBLIC int linphone_presence_model_clear_notes(LinphonePresenceModel *model); + +/***************************************************************************** + * PRESENCE MODEL FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * @brief Creates a default presence model. + * @returns The created presence model, NULL on error. + * @see linphone_presence_model_new_with_activity + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model is considered 'offline'. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); + +/** + * @brief 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_nb_services(const LinphonePresenceModel *model); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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_nb_activities(const LinphonePresenceModel *model); + +/** + * @brief 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); + +/** + * @brief Adds an activity to a presence model. + * @param[in] model The #LinphonePresenceModel object for which to add an activity. + * @param[in] activity The #LinphonePresenceActivityType to add to the model. + * @param[in] description An additional description of the activity to add to the model. 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_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); + +/** + * @brief 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); + + +/***************************************************************************** + * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * @brief Creates a presence service. + * @returns The created presence service, NULL on error. + * + * The created presence service has the basic status 'closed'. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(void); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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_service_set_contact(LinphonePresenceService *service, const char *contact); + + +/***************************************************************************** + * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + + +/***************************************************************************** + * PRESENCE NOTE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * @brief 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); + +/** + * @brief 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); + + +/***************************************************************************** + * PRESENCE INTERNAL FUNCTIONS FOR WRAPPERS IN OTHER PROGRAMMING LANGUAGES * + ****************************************************************************/ + +/** + * Increase the reference count of the #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased. + * @return The #LinphonePresenceModel object with the increased reference count. + */ +LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); + +/** + * Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0. + * @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased. + * @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); + +/** + * Sets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceModel object. + * @param[in] model The #LinphonePresenceModel object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); + +/** + * Increase the reference count of the #LinphonePresenceService object. + * @param[in] service The #LinphonePresenceService object for which the reference count is to be increased. + * @return The #LinphonePresenceService object with the increased reference count. + */ +LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service); + +/** + * Decrease the reference count of the #LinphonePresenceService object and destroy it if it reaches 0. + * @param[in] service The #LinphonePresenceService object for which the reference count is to be decreased. + * @return The #LinphonePresenceService object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service); + +/** + * Sets the user data of a #LinphonePresenceService object. + * @param[in] service The #LinphonePresenceService object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data); + +/** + * Gets the user data of a #LinphonePresenceService object. + * @param[in] service The #LinphonePresenceService object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_service_get_user_data(LinphonePresenceService *service); + /** * Increase the reference count of the #LinphonePresenceActivity object. * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be increased. @@ -379,29 +564,6 @@ void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity */ void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity); -/** - * @brief 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); - -/** - * @brief 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); - -/** - * @brief 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); - /** * Increase the reference count of the #LinphonePresenceNote object. * @param[in] note The #LinphonePresenceNote object for which the reference count is to be increased. @@ -430,20 +592,6 @@ void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user */ void * linphone_presence_note_get_user_data(LinphonePresenceNote *note); -/** - * @brief 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); - -/** - * @brief 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); - /** * @} diff --git a/coreapi/presence.c b/coreapi/presence.c index becf3afaf..1e5a13146 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" #include "lpconfig.h" +#include "linphonepresence.h" #include #include @@ -44,6 +45,8 @@ struct _LinphonePresenceNote { }; struct _LinphonePresenceService { + void *user_data; + int refcnt; char *id; LinphonePresenceBasicStatus status; char *contact; @@ -143,8 +146,8 @@ static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus } } -static struct _LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { - struct _LinphonePresenceNote * note = ms_new0(struct _LinphonePresenceNote, 1); +static LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { + LinphonePresenceNote * note = ms_new0(LinphonePresenceNote, 1); note->refcnt = 1; note->content = ms_strdup(content); if (lang != NULL) { @@ -153,7 +156,7 @@ static struct _LinphonePresenceNote * presence_note_new(const char *content, con return note; } -static void presence_note_delete(struct _LinphonePresenceNote *note) { +static void presence_note_delete(LinphonePresenceNote *note) { ms_free(note->content); if (note->lang != NULL) { ms_free(note->lang); @@ -161,15 +164,16 @@ static void presence_note_delete(struct _LinphonePresenceNote *note) { ms_free(note); } -static void presence_note_set_content(struct _LinphonePresenceNote *note, const char *content) { +static void presence_note_set_content(LinphonePresenceNote *note, const char *content) { if (note->content != NULL) { ms_free(note->content); } note->content = ms_strdup(content); } -static struct _LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) { - struct _LinphonePresenceService *service = ms_new0(struct _LinphonePresenceService, 1); +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); } @@ -178,7 +182,7 @@ static struct _LinphonePresenceService * presence_service_new(const char *id, Li return service; } -static void presence_service_delete(struct _LinphonePresenceService *service) { +static void presence_service_delete(LinphonePresenceService *service) { if (service->id != NULL) { ms_free(service->id); } @@ -190,20 +194,27 @@ static void presence_service_delete(struct _LinphonePresenceService *service) { ms_free(service); }; -static void presence_service_set_timestamp(struct _LinphonePresenceService *service, time_t timestamp) { +static void presence_service_set_timestamp(LinphonePresenceService *service, time_t timestamp) { service->timestamp = timestamp; } -static void presence_service_set_contact(struct _LinphonePresenceService *service, const char *contact) { - service->contact = ms_strdup(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; } -static void presence_service_add_note(struct _LinphonePresenceService *service, struct _LinphonePresenceNote *note) { +static void presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { service->notes = ms_list_append(service->notes, note); } -static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { - struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1); +static LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { + LinphonePresenceActivity *act = ms_new0(LinphonePresenceActivity, 1); act->refcnt = 1; act->type = acttype; if (description != NULL) { @@ -212,7 +223,7 @@ static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresence return act; } -static void presence_activity_delete(struct _LinphonePresenceActivity *activity) { +static void presence_activity_delete(LinphonePresenceActivity *activity) { if (activity->description != NULL) { ms_free(activity->description); } @@ -251,8 +262,8 @@ static char * timestamp_to_string(time_t timestamp) { return ms_strdup(timestamp_str); } -static struct _LinphonePresencePerson * presence_person_new(const char *id, time_t timestamp) { - struct _LinphonePresencePerson *person = ms_new0(struct _LinphonePresencePerson, 1); +static LinphonePresencePerson * presence_person_new(const char *id, time_t timestamp) { + LinphonePresencePerson *person = ms_new0(LinphonePresencePerson, 1); if (id != NULL) { person->id = ms_strdup(id); } @@ -263,7 +274,7 @@ static struct _LinphonePresencePerson * presence_person_new(const char *id, tim return person; } -static void presence_person_delete(struct _LinphonePresencePerson *person) { +static void presence_person_delete(LinphonePresencePerson *person) { if (person->id != NULL) { ms_free(person->id); } @@ -276,37 +287,39 @@ static void presence_person_delete(struct _LinphonePresencePerson *person) { ms_free(person); } -static void presence_person_add_activity(struct _LinphonePresencePerson *person, struct _LinphonePresenceActivity *activity) { +static void presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) { person->activities = ms_list_append(person->activities, activity); } -static void presence_person_add_activities_note(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) { +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(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) { +static void presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { person->notes = ms_list_append(person->notes, note); } -static void presence_person_clear_activities(struct _LinphonePresencePerson *person) { +static void presence_person_clear_activities(LinphonePresencePerson *person) { ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); ms_list_free(person->activities); person->activities = NULL; } -static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) { +int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) { + if ((model == NULL) || (service == NULL)) return -1; model->services = ms_list_append(model->services, service); + return 0; } -static void presence_model_add_person(LinphonePresenceModel *model, struct _LinphonePresencePerson *person) { +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, struct _LinphonePresenceNote *note) { +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(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { +static void presence_model_find_open_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { if (service->status == LinphonePresenceBasicStatusOpen) { *status = LinphonePresenceBasicStatusOpen; } @@ -338,7 +351,7 @@ LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(Linph static void presence_model_delete(LinphonePresenceModel *model) { if (model == NULL) return; - ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); + ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref); ms_list_free(model->services); ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); ms_list_free(model->persons); @@ -379,31 +392,25 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph } int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { - struct _LinphonePresenceService *service; - char *id; + LinphonePresenceService *service; if (model == NULL) return -1; - if (ms_list_size(model->services) > 0) { - ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete); - ms_list_free(model->services); - model->services = NULL; - } - id = generate_presence_id(); - service = presence_service_new(id, basic_status); - ms_free(id); + linphone_presence_model_clear_services(model); + service = linphone_presence_service_new(); if (service == NULL) return -1; - presence_model_add_service(model, service); + if (linphone_presence_service_set_basic_status(service, basic_status) < 0) return -1; + if (linphone_presence_model_add_service(model, service) < 0) return -1; return 0; } -static void presence_service_find_newer_timestamp(struct _LinphonePresenceService *service, time_t *timestamp) { +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(struct _LinphonePresencePerson *person, time_t *timestamp) { +static void presence_person_find_newer_timestamp(LinphonePresencePerson *person, time_t *timestamp) { if (person->timestamp > *timestamp) *timestamp = person->timestamp; } @@ -420,7 +427,7 @@ time_t linphone_presence_model_get_timestamp(const LinphonePresenceModel *model) return timestamp; } -static void presence_model_find_contact(struct _LinphonePresenceService *service, char **contact) { +static void presence_model_find_contact(LinphonePresenceService *service, char **contact) { if ((service->contact != NULL) && (*contact == NULL)) *contact = service->contact; } @@ -432,22 +439,41 @@ char * linphone_presence_model_get_contact(const LinphonePresenceModel *model) { return ms_strdup(contact); } -void linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact) { - struct _LinphonePresenceService *service; - if (model != NULL) { - service = (struct _LinphonePresenceService *)ms_list_nth_data(model->services, 0); - if (service != NULL) { - if (service->contact != NULL) - ms_free(service->contact); - if (contact != NULL) - service->contact = ms_strdup(contact); - else - service->contact = NULL; - } +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(); + 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 struct _LinphonePresencePerson *person, unsigned int *nb) { +unsigned int linphone_presence_model_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_nb_services(model))) + return NULL; + + return (LinphonePresenceService *)ms_list_nth_data(model->services, idx); +} + +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; +} + +static void presence_model_count_activities(const LinphonePresencePerson *person, unsigned int *nb) { *nb += ms_list_size(person->activities); } @@ -460,13 +486,13 @@ unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel * struct _get_activity_st { unsigned int requested_idx; unsigned int current_idx; - struct _LinphonePresenceActivity *activity; + LinphonePresenceActivity *activity; }; -static void presence_model_get_activity(const struct _LinphonePresencePerson *person, struct _get_activity_st *st) { +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 = (struct _LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); + st->activity = (LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); } else { st->current_idx += size; } @@ -518,8 +544,8 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { char *id = NULL; - struct _LinphonePresencePerson *person = NULL; - struct _LinphonePresenceActivity *act = NULL; + LinphonePresencePerson *person = NULL; + LinphonePresenceActivity *act = NULL; if (model == NULL) return -1; @@ -534,7 +560,7 @@ int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphoneP presence_model_add_person(model, person); } else { /* Add the activity to the first person in the model. */ - person = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); + person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); } act = presence_activity_new(acttype, description); if (act == NULL) @@ -553,16 +579,16 @@ int linphone_presence_model_clear_activities(LinphonePresenceModel *model) { struct _find_note_st { const char *lang; - struct _LinphonePresenceNote *note; + LinphonePresenceNote *note; }; -static struct _LinphonePresenceNote * find_presence_note_in_list(MSList *list, const char *lang) { +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++) { - struct _LinphonePresenceNote *note = (struct _LinphonePresenceNote *)ms_list_nth_data(list, i); + LinphonePresenceNote *note = (LinphonePresenceNote *)ms_list_nth_data(list, i); if (lang == NULL) { if (note->lang == NULL) { return note; @@ -577,7 +603,7 @@ static struct _LinphonePresenceNote * find_presence_note_in_list(MSList *list, c return NULL; } -static void find_presence_person_note(struct _LinphonePresencePerson *person, struct _find_note_st *st) { +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; @@ -586,21 +612,21 @@ static void find_presence_person_note(struct _LinphonePresencePerson *person, st st->note = find_presence_note_in_list(person->notes, st->lang); } -static void find_presence_service_note(struct _LinphonePresenceService *service, struct _find_note_st *st) { +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 struct _LinphonePresenceNote * get_first_presence_note_in_list(MSList *list) { - return (struct _LinphonePresenceNote *)ms_list_nth_data(list, 0); +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(struct _LinphonePresencePerson *person, struct _find_note_st *st) { +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(struct _LinphonePresenceService *service, struct _find_note_st *st) { +static void get_first_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) { st->note = get_first_presence_note_in_list(service->notes); } @@ -649,8 +675,8 @@ LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceMo } int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) { - struct _LinphonePresenceService *service; - struct _LinphonePresenceNote *note; + LinphonePresenceService *service; + LinphonePresenceNote *note; if ((model == NULL) || (note_content == NULL)) return -1; @@ -679,7 +705,7 @@ int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *n return 0; } -static void clear_presence_person_notes(struct _LinphonePresencePerson *person) { +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; @@ -688,7 +714,7 @@ static void clear_presence_person_notes(struct _LinphonePresencePerson *person) person->notes = NULL; } -static void clear_presence_service_notes(struct _LinphonePresenceService *service) { +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; @@ -748,10 +774,10 @@ static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t static const char *service_prefix = "/pidf:presence/pidf:tuple"; -static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresenceService *service, unsigned int service_idx) { +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; - struct _LinphonePresenceNote *note; + LinphonePresenceNote *note; const char *note_str; const char *lang; int i; @@ -780,7 +806,7 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr service_object; - struct _LinphonePresenceService *service; + LinphonePresenceService *service; const char *basic_status_str; const char *service_id_str; const char *timestamp_str; @@ -821,11 +847,11 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin free_xml_text_content(timestamp_str); } if (contact_str != NULL) { - presence_service_set_contact(service, contact_str); + linphone_presence_service_set_contact(service, contact_str); free_xml_text_content(contact_str); } process_pidf_xml_presence_service_notes(xml_ctx, service, i); - presence_model_add_service(model, service); + linphone_presence_model_add_service(model, service); } free_xml_text_content(basic_status_str); if (service_id_str != NULL) free_xml_text_content(service_id_str); @@ -836,6 +862,54 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin return 0; } + +LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) { + service->refcnt++; + return service; +} + +LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) { + service->refcnt--; + if (service->refcnt == 0) { + presence_service_delete(service); + return NULL; + } + return service; +} + +void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data) { + service->user_data = user_data; +} + +void * linphone_presence_service_get_user_data(LinphonePresenceService *service) { + return service->user_data; +} + +LinphonePresenceService * linphone_presence_service_new(void) { + LinphonePresenceService *service; + char *id = generate_presence_id(); + service = presence_service_new(id, LinphonePresenceBasicStatusClosed); + ms_free(id); + return service; +} + +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); +} + + static const char *person_prefix = "/pidf:presence/dm:person"; struct _presence_activity_name_map { @@ -989,12 +1063,12 @@ static bool_t is_valid_activity_name(const char *name) { return FALSE; } -static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { +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; - struct _LinphonePresenceActivity *activity; + LinphonePresenceActivity *activity; const char *description; int i, j; int err = 0; @@ -1032,10 +1106,10 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml return err; } -static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) { +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; - struct _LinphonePresenceNote *note; + LinphonePresenceNote *note; const char *note_str; const char *lang; int i; @@ -1082,7 +1156,7 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr person_object; - struct _LinphonePresencePerson *person; + LinphonePresencePerson *person; const char *person_id_str; const char *person_timestamp_str; time_t timestamp; @@ -1129,7 +1203,7 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { char xpath_str[MAX_XPATH_LENGTH]; xmlXPathObjectPtr note_object; - struct _LinphonePresenceNote *note; + LinphonePresenceNote *note; const char *note_str; const char *lang; int i; @@ -1331,7 +1405,7 @@ struct _presence_note_obj_st { int *err; }; -static int write_xml_presence_note(xmlTextWriterPtr writer, struct _LinphonePresenceNote *note, const char *ns) { +static int write_xml_presence_note(xmlTextWriterPtr writer, LinphonePresenceNote *note, const char *ns) { int err; if (ns == NULL) { err = xmlTextWriterStartElement(writer, (const xmlChar *)"note"); @@ -1350,7 +1424,7 @@ static int write_xml_presence_note(xmlTextWriterPtr writer, struct _LinphonePres return err; } -static void write_xml_presence_note_obj(struct _LinphonePresenceNote *note, struct _presence_note_obj_st *st) { +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; } @@ -1363,7 +1437,7 @@ static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestam return err; } -static int write_xml_presence_service(xmlTextWriterPtr writer, struct _LinphonePresenceService *service, const char *contact) { +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)) { @@ -1419,13 +1493,13 @@ static int write_xml_presence_service(xmlTextWriterPtr writer, struct _LinphoneP return err; } -static bool_t is_valid_activity(struct _LinphonePresenceActivity *activity) { +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, struct _LinphonePresenceActivity *activity) { +static int write_xml_presence_activity(xmlTextWriterPtr writer, LinphonePresenceActivity *activity) { int err; if (is_valid_activity(activity) == FALSE) return 0; @@ -1441,22 +1515,22 @@ static int write_xml_presence_activity(xmlTextWriterPtr writer, struct _Linphone return err; } -static void write_xml_presence_activity_obj(struct _LinphonePresenceActivity *activity, struct _presence_activity_obj_st *st) { +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(struct _LinphonePresenceActivity *activity, bool_t *has_valid_activities) { +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(struct _LinphonePresencePerson *person) { +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, struct _LinphonePresencePerson *person) { +static int write_xml_presence_person(xmlTextWriterPtr writer, LinphonePresencePerson *person) { int err; if ((person_has_valid_activities(person) == FALSE) && (person->notes == NULL)) return 0; @@ -1508,12 +1582,12 @@ static int write_xml_presence_person(xmlTextWriterPtr writer, struct _LinphonePr return err; } -static void write_xml_presence_service_obj(struct _LinphonePresenceService *service, struct _presence_service_obj_st *st) { +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(struct _LinphonePresencePerson *person, struct _presence_person_obj_st *st) { +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; } From 8c55b6e26019429b3371b9f145a73fa663b9be6a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Sep 2013 15:59:03 +0200 Subject: [PATCH 650/909] Some changes in the presence API so that it is more coherent. --- coreapi/linphonepresence.h | 29 ++++++++++++++++++++++--- coreapi/presence.c | 44 +++++++++++++++++++++++++------------- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 563206b5a..1b06791ad 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -370,11 +370,10 @@ LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_nth_activ /** * @brief Adds an activity to a presence model. * @param[in] model The #LinphonePresenceModel object for which to add an activity. - * @param[in] activity The #LinphonePresenceActivityType to add to the model. - * @param[in] description An additional description of the activity to add to the model. Can be NULL if no additional description is to be added. + * @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, LinphonePresenceActivityType activity, const char *description); +LINPHONE_PUBLIC int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity); /** * @brief Clears the activities of a presence model. @@ -433,6 +432,14 @@ LINPHONE_PUBLIC int linphone_presence_service_set_contact(LinphonePresenceServic * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ +/** + * @brief Creates a presence activity. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created presence activity, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description); + /** * @brief Gets the string representation of a presence activity. * @param[in] activity A pointer to the #LinphonePresenceActivity object for which to get a string representation. @@ -449,6 +456,14 @@ LINPHONE_PUBLIC char * linphone_presence_activity_to_string(const LinphonePresen */ LINPHONE_PUBLIC LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity); +/** + * @brief 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); + /** * @brief Gets the description of a presence activity. * @param[in] activity A pointer to the #LinphonePresenceActivity for which to get the description. @@ -456,6 +471,14 @@ LINPHONE_PUBLIC LinphonePresenceActivityType linphone_presence_activity_get_type */ LINPHONE_PUBLIC const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity); +/** + * @brief 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 * diff --git a/coreapi/presence.c b/coreapi/presence.c index 1e5a13146..1c8b6a23b 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -213,7 +213,7 @@ static void presence_service_add_note(LinphonePresenceService *service, Linphone service->notes = ms_list_append(service->notes, note); } -static LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { +LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { LinphonePresenceActivity *act = ms_new0(LinphonePresenceActivity, 1); act->refcnt = 1; act->type = acttype; @@ -517,6 +517,7 @@ LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePr int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen; + LinphonePresenceActivity *activity; if (model == NULL) return -1; @@ -533,21 +534,19 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP basic_status = LinphonePresenceBasicStatusOpen; break; } - if (linphone_presence_model_set_basic_status(model, basic_status) < 0) - return -1; + if (linphone_presence_model_set_basic_status(model, basic_status) < 0) return -1; linphone_presence_model_clear_activities(model); - if (linphone_presence_model_add_activity(model, acttype, description) < 0) - return -1; + activity = linphone_presence_activity_new(acttype, description); + if (activity == NULL) return -1; + return linphone_presence_model_add_activity(model, activity); - return 0; } -int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { +int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity) { char *id = NULL; LinphonePresencePerson *person = NULL; - LinphonePresenceActivity *act = NULL; - if (model == NULL) return -1; + if ((model == NULL) || (activity == NULL)) return -1; if (ms_list_size(model->persons) == 0) { /* There is no person in the presence model, add one. */ @@ -562,11 +561,8 @@ int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphoneP /* Add the activity to the first person in the model. */ person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); } - act = presence_activity_new(acttype, description); - if (act == NULL) - return -1; - presence_person_add_activity(person, act); + presence_person_add_activity(person, activity); return 0; } @@ -1013,12 +1009,29 @@ LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphoneP 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; +} + LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) { note->refcnt++; return note; @@ -1091,7 +1104,7 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml } err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); if (err < 0) break; - activity = presence_activity_new(acttype, description); + activity = linphone_presence_activity_new(acttype, description); presence_person_add_activity(person, activity); if (description != NULL) free_xml_text_content(description); } @@ -1376,7 +1389,8 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c acttype = LinphonePresenceActivityOffline; break; } - linphone_presence_model_add_activity(model, acttype, NULL); + activity = linphone_presence_activity_new(acttype, NULL); + linphone_presence_model_add_activity(model, activity); } } From c05a0f099c5f09a3e63f63c90b49124ad4d2d7ae Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Sep 2013 16:21:44 +0200 Subject: [PATCH 651/909] Reorder code to make it cleaner. --- coreapi/linphonepresence.h | 60 ++-- coreapi/presence.c | 668 ++++++++++++++++++++----------------- 2 files changed, 385 insertions(+), 343 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 1b06791ad..7a38e6b3d 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -281,6 +281,36 @@ LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_activity( */ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); +/** + * @brief 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_nb_activities(const LinphonePresenceModel *model); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + /** * @brief Gets the first note of a presence model (there is usually only one). * @param[in] model The #LinphonePresenceModel object to get the note from. @@ -352,36 +382,6 @@ LINPHONE_PUBLIC int linphone_presence_model_add_service(LinphonePresenceModel *m */ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel *model); -/** - * @brief 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_nb_activities(const LinphonePresenceModel *model); - -/** - * @brief 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); - -/** - * @brief 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); - -/** - * @brief 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); - /***************************************************************************** * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * diff --git a/coreapi/presence.c b/coreapi/presence.c index 1c8b6a23b..6e0e3ef11 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 @@ -89,6 +89,12 @@ typedef struct _xmlparsing_context { } xmlparsing_context_t; +static const char *person_prefix = "/pidf:presence/dm:person"; + + +/***************************************************************************** + * PRIVATE FUNCTIONS * + ****************************************************************************/ static xmlparsing_context_t * xmlparsing_context_new() { xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); @@ -198,31 +204,10 @@ static void presence_service_set_timestamp(LinphonePresenceService *service, tim service->timestamp = timestamp; } -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; -} - static void presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { service->notes = ms_list_append(service->notes, note); } -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; -} - static void presence_activity_delete(LinphonePresenceActivity *activity) { if (activity->description != NULL) { ms_free(activity->description); @@ -305,12 +290,6 @@ static void presence_person_clear_activities(LinphonePresencePerson *person) { person->activities = NULL; } -int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) { - if ((model == NULL) || (service == NULL)) return -1; - model->services = ms_list_append(model->services, service); - return 0; -} - static void presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { model->persons = ms_list_append(model->persons, person); } @@ -325,12 +304,24 @@ static void presence_model_find_open_basic_status(LinphonePresenceService *servi } } -LinphonePresenceModel * linphone_presence_model_new(void) { - LinphonePresenceModel *model = ms_new0(LinphonePresenceModel, 1); - model->refcnt = 1; - return model; +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)presence_person_delete); + 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) { @@ -348,40 +339,6 @@ LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(Linph return model; } -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)presence_person_delete); - ms_list_free(model->persons); - ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref); - ms_list_free(model->notes); - ms_free(model); -} - -LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) { - model->refcnt++; - return model; -} - -LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) { - model->refcnt--; - if (model->refcnt == 0) { - presence_model_delete(model); - return NULL; - } - return model; -} - -void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data) { - model->user_data = user_data; -} - -void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) { - return model->user_data; -} - /* 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; @@ -453,36 +410,10 @@ int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char return linphone_presence_service_set_contact(service, contact); } -unsigned int linphone_presence_model_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_nb_services(model))) - return NULL; - - return (LinphonePresenceService *)ms_list_nth_data(model->services, idx); -} - -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; -} - static void presence_model_count_activities(const LinphonePresencePerson *person, unsigned int *nb) { *nb += ms_list_size(person->activities); } -unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model) { - unsigned int nb = 0; - ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb); - return nb; -} - struct _get_activity_st { unsigned int requested_idx; unsigned int current_idx; @@ -498,19 +429,6 @@ static void presence_model_get_activity(const LinphonePresencePerson *person, st } } -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_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; -} - LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model) { return linphone_presence_model_get_nth_activity(model, 0); } @@ -542,6 +460,25 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP } +unsigned int linphone_presence_model_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_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; @@ -729,6 +666,319 @@ int linphone_presence_model_clear_notes(LinphonePresenceModel *model) { 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_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_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, 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; +} + + + +/***************************************************************************** + * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +LinphonePresenceService * linphone_presence_service_new(void) { + LinphonePresenceService *service; + char *id = generate_presence_id(); + service = presence_service_new(id, LinphonePresenceBasicStatusClosed); + ms_free(id); + return service; +} + +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; +} + + + +/***************************************************************************** + * 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 * + ****************************************************************************/ + +const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->content; +} + +const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->lang; +} + + + +/***************************************************************************** + * PRESENCE INTERNAL FUNCTIONS FOR WRAPPERS IN OTHER PROGRAMMING LANGUAGES * + ****************************************************************************/ + +LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) { + model->refcnt++; + return model; +} + +LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) { + model->refcnt--; + if (model->refcnt == 0) { + presence_model_delete(model); + return NULL; + } + return model; +} + +void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data) { + model->user_data = user_data; +} + +void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) { + return model->user_data; +} + +LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) { + service->refcnt++; + return service; +} + +LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) { + service->refcnt--; + if (service->refcnt == 0) { + presence_service_delete(service); + return NULL; + } + return service; +} + +void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data) { + service->user_data = user_data; +} + +void * linphone_presence_service_get_user_data(LinphonePresenceService *service) { + return service->user_data; +} + +LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity) { + activity->refcnt++; + return activity; +} + +LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) { + activity->refcnt--; + if (activity->refcnt == 0) { + presence_activity_delete(activity); + return NULL; + } + return activity; +} + +void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data) { + activity->user_data = user_data; +} + +void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity) { + return activity->user_data; +} + +LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) { + note->refcnt++; + return note; +} + +LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) { + note->refcnt--; + if (note->refcnt == 0) { + presence_note_delete(note); + return NULL; + } + return note; +} + +void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data) { + note->user_data = user_data; +} + +void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { + return note->user_data; +} + + + +/***************************************************************************** + * XML PRESENCE INTERNAL HANDLING * + ****************************************************************************/ + static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { if (xml_ctx->xpath_ctx != NULL) { xmlXPathFreeContext(xml_ctx->xpath_ctx); @@ -858,214 +1108,6 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin return 0; } - -LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) { - service->refcnt++; - return service; -} - -LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) { - service->refcnt--; - if (service->refcnt == 0) { - presence_service_delete(service); - return NULL; - } - return service; -} - -void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data) { - service->user_data = user_data; -} - -void * linphone_presence_service_get_user_data(LinphonePresenceService *service) { - return service->user_data; -} - -LinphonePresenceService * linphone_presence_service_new(void) { - LinphonePresenceService *service; - char *id = generate_presence_id(); - service = presence_service_new(id, LinphonePresenceBasicStatusClosed); - ms_free(id); - return service; -} - -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); -} - - -static const char *person_prefix = "/pidf:presence/dm:person"; - -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_ref(LinphonePresenceActivity *activity) { - activity->refcnt++; - return activity; -} - -LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) { - activity->refcnt--; - if (activity->refcnt == 0) { - presence_activity_delete(activity); - return NULL; - } - return activity; -} - -void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data) { - activity->user_data = user_data; -} - -void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity) { - return activity->user_data; -} - -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; -} - -LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) { - note->refcnt++; - return note; -} - -LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) { - note->refcnt--; - if (note->refcnt == 0) { - presence_note_delete(note); - return NULL; - } - return note; -} - -void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data) { - note->user_data = user_data; -} - -void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { - return note->user_data; -} - -const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) { - if (note == NULL) - return NULL; - return note->content; -} - -const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) { - if (note == NULL) - return NULL; - return note->lang; -} - 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++) { From 5dea3b42f09c3eb3b023a55a844c475576906bd6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Sep 2013 17:51:29 +0200 Subject: [PATCH 652/909] avoid crashing when no soundcard is present. update ms2 --- coreapi/bellesip_sal/sal_op_publish.c | 4 ++-- coreapi/linphonecore.c | 16 ++++++++++------ mediastreamer2 | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 9f23b849d..ec4ecc324 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -68,14 +68,14 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); - if (body) sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); + sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); } else { /*update status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); /*update body*/ - if (body) sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),body); + sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),body); return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3ba4a5d54..4c501c6fa 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2487,11 +2487,13 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_call_make_local_media_description(lc,call); if (lc->ringstream==NULL) { - /*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->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){ + /*give a chance a set card prefered sampling frequency*/ + if (call->localdesc->streams[0].max_rate>0) { + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + } + audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } - audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } if (!lc->sip_conf.sdp_200_ack){ @@ -3241,8 +3243,10 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, /*give a chance a set card prefered sampling frequency*/ if (call->localdesc->streams[0].max_rate>0) { ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate); - ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); - ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); + if (lc->sound_conf.play_sndcard) + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + if (lc->sound_conf.capt_sndcard) + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); } if (!was_ringing && call->audiostream->ms.ticker==NULL){ diff --git a/mediastreamer2 b/mediastreamer2 index c516f225b..ec2d04150 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c516f225bea6ac2132f3468235138e2dde6cfcda +Subproject commit ec2d04150521197905bf5812991b54bab97fbdf8 From c61dc5a039c5b2de5a00eb5cb1d780e63aaec991 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 10:30:27 +0200 Subject: [PATCH 653/909] Update JNI according to latest presence API changes. --- coreapi/linphonecore_jni.cc | 230 +++++++++++++++--- .../linphone/core/LinphoneCoreFactory.java | 17 ++ .../org/linphone/core/PresenceActivity.java | 19 ++ .../org/linphone/core/PresenceModel.java | 57 +++-- .../org/linphone/core/PresenceNote.java | 5 + .../org/linphone/core/PresenceService.java | 55 +++++ .../core/LinphoneCoreFactoryImpl.java | 26 ++ .../linphone/core/PresenceActivityImpl.java | 21 ++ .../org/linphone/core/PresenceModelImpl.java | 78 ++++-- .../org/linphone/core/PresenceNoteImpl.java | 4 + .../linphone/core/PresenceServiceImpl.java | 66 +++++ 11 files changed, 515 insertions(+), 63 deletions(-) create mode 100644 java/common/org/linphone/core/PresenceService.java create mode 100644 java/impl/org/linphone/core/PresenceServiceImpl.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index a3acc1ec2..74d62cb0a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3287,6 +3287,46 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *en linphone_event_unref(ev); } +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__(JNIEnv *env, jobject jobj) { + return (jlong)linphone_presence_model_new(); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: (ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__ILjava_lang_String_2(JNIEnv *env, jobject jobj, jint type, jstring description) { + LinphonePresenceModel *model; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + model = linphone_presence_model_new_with_activity((LinphonePresenceActivityType)type, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return (jlong)model; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__ILjava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2( + JNIEnv *env, jobject jobj, jint type, jstring description, jstring note, jstring lang) { + LinphonePresenceModel *model; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + const char *cnote = note ? env->GetStringUTFChars(note, NULL) : NULL; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + model = linphone_presence_model_new_with_activity_and_note((LinphonePresenceActivityType)type, cdescription, cnote, clang); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + if (cnote) env->ReleaseStringUTFChars(note, cnote); + if (clang) env->ReleaseStringUTFChars(lang, clang); + return (jlong)model; +} + /* * Class: org_linphone_core_PresenceModelImpl * Method: unref @@ -3353,28 +3393,6 @@ JNIEXPORT void JNICALL Java_org_linphone_core_PresenceModelImpl_setContact(JNIEn if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); } -/* - * Class: org_linphone_core_PresenceModelImpl - * Method: nbActivities - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { - LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; - return (jlong)linphone_presence_model_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: getActivity @@ -3400,17 +3418,35 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_setActivity(JNIE return res; } +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: nbActivities + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_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, jint acttype, jstring description) { - LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; - const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; - jint res = (jint)linphone_presence_model_add_activity(model, (LinphonePresenceActivityType)acttype, cdescription); - if (cdescription) env->ReleaseStringUTFChars(description, cdescription); - return res; +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); } /* @@ -3463,6 +3499,60 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearNotes(JNIEn } /* + * Class: org_linphone_core_PresenceModelImpl + * Method: nbServices + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbServices(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_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_PresenceActivityImpl + * Method: newPresenceActivityImpl + * Signature: (ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceActivityImpl_newPresenceActivityImpl(JNIEnv *env, jobject jobj, jint type, jstring description) { + LinphonePresenceActivity *activity; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + activity = linphone_presence_activity_new((LinphonePresenceActivityType)type, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return (jlong)activity; +} + + /* * Class: org_linphone_core_PresenceActivityImpl * Method: unref * Signature: (J)V @@ -3495,6 +3585,16 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_getType(JNIEn 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 @@ -3506,6 +3606,80 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceActivityImpl_getDescrip return cdescription ? env->NewStringUTF(cdescription) : NULL; } +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: setDescription + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_setDescription(JNIEnv *env, jobject jobj, jlong ptr, jstring description) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + linphone_presence_activity_set_description(activity, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: newPresenceServiceImpl + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceServiceImpl(JNIEnv *env, jobject jobj) { + return (jlong)linphone_presence_service_new(); +} + +/* + * 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: 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; + const char *ccontact = linphone_presence_service_get_contact(service); + return ccontact ? env->NewStringUTF(ccontact) : NULL; +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: setContact + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setContact(JNIEnv *env, jobject jobj, jlong ptr, jstring contact) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL; + linphone_presence_service_set_contact(service, ccontact); + if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); +} + /* * Class: org_linphone_core_PresenceNoteImpl * Method: unref diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 281d89e46..c0513e514 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -111,4 +111,21 @@ abstract public class LinphoneCoreFactory { * Create a LinphoneContent object */ abstract public LinphoneContent createLinphoneContent(String type, String subType, String data); + + /** + * Create a PresenceActivity object. + */ + abstract public PresenceActivity createPresenceActivity(PresenceActivityType type, String description); + + /** + * Create a PresenceService object. + */ + abstract public PresenceService createPresenceService(); + + /** + * 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/PresenceActivity.java b/java/common/org/linphone/core/PresenceActivity.java index 4f116c43c..b965b526b 100644 --- a/java/common/org/linphone/core/PresenceActivity.java +++ b/java/common/org/linphone/core/PresenceActivity.java @@ -33,10 +33,29 @@ public interface PresenceActivity { */ 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/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java index 8f4d3716d..44f232c77 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -52,19 +52,6 @@ public interface PresenceModel { */ void setContact(String contact); - /** - * @brief Gets the number of activities included in the presence model. - * @return The number of activities included in the #PresenceModel object. - */ - long nbActivities(); - - /** - * @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 Gets the first activity of a presence model (there is usually only one). * @return A #PresenceActivity object if successful, null otherwise. @@ -82,13 +69,25 @@ public interface PresenceModel { */ 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 nbActivities(); + + /** + * @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 #PresenceActivityType to add to the model. - * @param[in] description An additional description of the activity to add to the model. Can be null if no additional description is to be added. + * @param[in] activity The #PresenceActivity to add to the model. * @return 0 if successful, a value < 0 in case of error. */ - int addActivity(PresenceActivityType activity, String description); + int addActivity(PresenceActivity activity); /** * @brief Clears the activities of a presence model. @@ -119,4 +118,30 @@ public interface PresenceModel { */ int clearNotes(); + /** + * @brief Gets the number of services included in the presence model. + * @return The number of services included in the #PresenceModel object. + */ + long nbServices(); + + /** + * @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(); + } diff --git a/java/common/org/linphone/core/PresenceNote.java b/java/common/org/linphone/core/PresenceNote.java index a89cde1df..638985fc1 100644 --- a/java/common/org/linphone/core/PresenceNote.java +++ b/java/common/org/linphone/core/PresenceNote.java @@ -33,4 +33,9 @@ public interface PresenceNote { */ String getLang(); + /** + * @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..779073476 --- /dev/null +++ b/java/common/org/linphone/core/PresenceService.java @@ -0,0 +1,55 @@ +/* +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 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 model. + * @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 native pointer for this object. + */ + long getNativePtr(); + +} diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index e757389c9..b424728d2 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -179,4 +179,30 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { String data) { return new LinphoneContentImpl(type,subType,data); } + + @Override + public PresenceActivity createPresenceActivity(PresenceActivityType type, String description) { + return new PresenceActivityImpl(type, description); + } + + @Override + public PresenceService createPresenceService() { + return new PresenceServiceImpl(); + } + + @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/PresenceActivityImpl.java b/java/impl/org/linphone/core/PresenceActivityImpl.java index fc63c4114..281ecc9f2 100644 --- a/java/impl/org/linphone/core/PresenceActivityImpl.java +++ b/java/impl/org/linphone/core/PresenceActivityImpl.java @@ -26,6 +26,11 @@ public class PresenceActivityImpl implements PresenceActivity { 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); @@ -43,9 +48,25 @@ public class PresenceActivityImpl implements PresenceActivity { 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 index 3cafe3cd7..7250fe3ac 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -26,15 +26,26 @@ public class PresenceModelImpl implements PresenceModel { 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); } - public long getNativePtr() { - return mNativePtr; - } - private native int getBasicStatus(long nativePtr); @Override public PresenceBasicStatus getBasicStatus() { @@ -65,18 +76,6 @@ public class PresenceModelImpl implements PresenceModel { setContact(mNativePtr, contact); } - private native long nbActivities(long nativePtr); - @Override - public long nbActivities() { - return nbActivities(mNativePtr); - } - - private native Object getNthActivity(long nativePtr, long idx); - @Override - public PresenceActivity getNthActivity(long idx) { - return (PresenceActivity)getNthActivity(mNativePtr, idx); - } - private native Object getActivity(long nativePtr); @Override public PresenceActivity getActivity() { @@ -89,10 +88,22 @@ public class PresenceModelImpl implements PresenceModel { return setActivity(mNativePtr, activity.toInt(), description); } - private native int addActivity(long nativePtr, int activity, String description); + private native long nbActivities(long nativePtr); @Override - public int addActivity(PresenceActivityType activity, String description) { - return addActivity(mNativePtr, activity.toInt(), description); + public long nbActivities() { + return nbActivities(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); @@ -118,4 +129,33 @@ public class PresenceModelImpl implements PresenceModel { public int clearNotes() { return clearNotes(mNativePtr); } + + private native long nbServices(long nativePtr); + @Override + public long nbServices() { + return nbServices(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); + } + + public long getNativePtr() { + return mNativePtr; + } + } diff --git a/java/impl/org/linphone/core/PresenceNoteImpl.java b/java/impl/org/linphone/core/PresenceNoteImpl.java index 38c541cf2..c5857eec5 100644 --- a/java/impl/org/linphone/core/PresenceNoteImpl.java +++ b/java/impl/org/linphone/core/PresenceNoteImpl.java @@ -42,4 +42,8 @@ public class PresenceNoteImpl implements PresenceNote { public String getLang() { return getLang(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..fe1d80ce2 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -0,0 +1,66 @@ +/* +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(); + protected PresenceServiceImpl() { + mNativePtr = newPresenceServiceImpl(); + } + + 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 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); + } + + public long getNativePtr() { + return mNativePtr; + } +} From 3296462b7a673e21173827105bbc4ce4f1a91e16 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 12:10:34 +0200 Subject: [PATCH 654/909] Allow setting the id of a presence service. --- coreapi/linphonepresence.h | 3 ++- coreapi/presence.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 7a38e6b3d..9e650c6ce 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -389,11 +389,12 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel /** * @brief Creates a presence service. + * @param[in] id The id of the presence service to be created. Can be NULL to generate it automatically. * @returns The created presence service, NULL on error. * * The created presence service has the basic status 'closed'. */ -LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(void); +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id); /** * @brief Gets the basic status of a presence service. diff --git a/coreapi/presence.c b/coreapi/presence.c index 6e0e3ef11..ac4319df9 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -354,7 +354,7 @@ int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, Linph if (model == NULL) return -1; linphone_presence_model_clear_services(model); - service = linphone_presence_service_new(); + service = linphone_presence_service_new(NULL); if (service == NULL) return -1; if (linphone_presence_service_set_basic_status(service, basic_status) < 0) return -1; @@ -403,7 +403,7 @@ int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char service = linphone_presence_model_get_nth_service(model, 0); if (service == NULL) { - service = linphone_presence_service_new(); + service = linphone_presence_service_new(NULL); if (service == NULL) return -1; linphone_presence_model_add_service(model, service); } @@ -708,11 +708,16 @@ int linphone_presence_model_clear_services(LinphonePresenceModel *model) { * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ -LinphonePresenceService * linphone_presence_service_new(void) { +LinphonePresenceService * linphone_presence_service_new(const char *id) { LinphonePresenceService *service; - char *id = generate_presence_id(); - service = presence_service_new(id, LinphonePresenceBasicStatusClosed); - ms_free(id); + char *service_id; + if (id == NULL) + service_id = generate_presence_id(); + else + service_id = ms_strdup(id); + service = presence_service_new(service_id, LinphonePresenceBasicStatusClosed); + if (service_id != NULL) + ms_free(service_id); return service; } From 9752a9c3e8ec1edf61f64105d191712f71b63f5c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 12:20:57 +0200 Subject: [PATCH 655/909] Reflect in the JNI the changes made in the presence API. --- coreapi/linphonecore_jni.cc | 10 +++++++--- java/common/org/linphone/core/LinphoneCoreFactory.java | 4 +++- .../org/linphone/core/LinphoneCoreFactoryImpl.java | 4 ++-- java/impl/org/linphone/core/PresenceServiceImpl.java | 6 +++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 74d62cb0a..e7d5a7092 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3621,10 +3621,14 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_setDescriptio /* * Class: org_linphone_core_PresenceServiceImpl * Method: newPresenceServiceImpl - * Signature: ()J + * Signature: (Ljava/lang/String;)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceServiceImpl(JNIEnv *env, jobject jobj) { - return (jlong)linphone_presence_service_new(); +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceServiceImpl(JNIEnv *env, jobject jobj, jstring id) { + LinphonePresenceService *service; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + service = linphone_presence_service_new(cid); + if (cid) env->ReleaseStringUTFChars(id, cid); + return (jlong)service; } /* diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index c0513e514..b7287801e 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -119,8 +119,10 @@ abstract public class LinphoneCoreFactory { /** * Create a PresenceService object. + * @param id The id of the presence service. Can be null to generate it automatically. + * @return A new PresenceService object. */ - abstract public PresenceService createPresenceService(); + abstract public PresenceService createPresenceService(String id); /** * Create a PresenceModel object. diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index b424728d2..581b6acba 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -186,8 +186,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @Override - public PresenceService createPresenceService() { - return new PresenceServiceImpl(); + public PresenceService createPresenceService(String id) { + return new PresenceServiceImpl(id); } @Override diff --git a/java/impl/org/linphone/core/PresenceServiceImpl.java b/java/impl/org/linphone/core/PresenceServiceImpl.java index fe1d80ce2..5a3a31416 100644 --- a/java/impl/org/linphone/core/PresenceServiceImpl.java +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -26,9 +26,9 @@ public class PresenceServiceImpl implements PresenceService { mNativePtr = nativePtr; } - private native long newPresenceServiceImpl(); - protected PresenceServiceImpl() { - mNativePtr = newPresenceServiceImpl(); + private native long newPresenceServiceImpl(String id); + protected PresenceServiceImpl(String id) { + mNativePtr = newPresenceServiceImpl(id); } private native void unref(long nativePtr); From 439f9223101a040e5d285e870bbcfab139571378 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 12:53:15 +0200 Subject: [PATCH 656/909] Fix wrong contact being written in presence XML. --- coreapi/presence.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index ac4319df9..52724bdfc 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1528,7 +1528,9 @@ static int write_xml_presence_service(xmlTextWriterPtr writer, LinphonePresenceS err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"priority", (const xmlChar *)"0.8"); } if (err >= 0) { - err = xmlTextWriterWriteString(writer, (const xmlChar *)contact); + const char *contact_str = service->contact; + if (contact_str == NULL) contact_str = contact; + err = xmlTextWriterWriteString(writer, (const xmlChar *)contact_str); } if (err >= 0) { /* Close the "contact" element. */ From 5c7159d87fe6da3b593de9820268cd47e6124bc6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 12:59:52 +0200 Subject: [PATCH 657/909] More coherent API for linphone_presence_service_new(). --- coreapi/linphonepresence.h | 4 +++- coreapi/presence.c | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 9e650c6ce..b4cef5252 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -390,11 +390,13 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel /** * @brief Creates a presence service. * @param[in] id The id of the presence service to be created. Can be NULL to generate it automatically. + * @param[in] basic_status The #LinphonePresenceBasicStatus to set for the #LinphonePresenceService object. + * @param[in] contact The contact string to set. * @returns The created presence service, NULL on error. * * The created presence service has the basic status 'closed'. */ -LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id); +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus, const char *contact); /** * @brief Gets the basic status of a presence service. diff --git a/coreapi/presence.c b/coreapi/presence.c index 52724bdfc..16c8bdcd2 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -354,10 +354,9 @@ int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, Linph if (model == NULL) return -1; linphone_presence_model_clear_services(model); - service = linphone_presence_service_new(NULL); + service = linphone_presence_service_new(NULL, basic_status, NULL); if (service == NULL) return -1; - if (linphone_presence_service_set_basic_status(service, basic_status) < 0) return -1; if (linphone_presence_model_add_service(model, service) < 0) return -1; return 0; } @@ -403,7 +402,7 @@ int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char service = linphone_presence_model_get_nth_service(model, 0); if (service == NULL) { - service = linphone_presence_service_new(NULL); + service = linphone_presence_service_new(NULL, LinphonePresenceBasicStatusClosed, NULL); if (service == NULL) return -1; linphone_presence_model_add_service(model, service); } @@ -708,14 +707,15 @@ int linphone_presence_model_clear_services(LinphonePresenceModel *model) { * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ -LinphonePresenceService * linphone_presence_service_new(const char *id) { +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, LinphonePresenceBasicStatusClosed); + 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; From 480144c98f95c6fc02b5cee86542eef2118063d4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Sep 2013 13:07:55 +0200 Subject: [PATCH 658/909] Update JNI one more time. --- coreapi/linphonecore_jni.cc | 8 +++++--- java/common/org/linphone/core/LinphoneCoreFactory.java | 4 +++- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 4 ++-- java/impl/org/linphone/core/PresenceServiceImpl.java | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index e7d5a7092..3b61d7438 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3621,13 +3621,15 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_setDescriptio /* * Class: org_linphone_core_PresenceServiceImpl * Method: newPresenceServiceImpl - * Signature: (Ljava/lang/String;)J + * Signature: (Ljava/lang/String;ILjava/lang/String;)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceServiceImpl(JNIEnv *env, jobject jobj, jstring id) { +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; - service = linphone_presence_service_new(cid); + const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL; + service = linphone_presence_service_new(cid, (LinphonePresenceBasicStatus)basic_status, ccontact); if (cid) env->ReleaseStringUTFChars(id, cid); + if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); return (jlong)service; } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index b7287801e..91f026ae0 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -120,9 +120,11 @@ abstract public class LinphoneCoreFactory { /** * 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); + abstract public PresenceService createPresenceService(String id, PresenceBasicStatus status, String contact); /** * Create a PresenceModel object. diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 581b6acba..6c1f370ae 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -186,8 +186,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @Override - public PresenceService createPresenceService(String id) { - return new PresenceServiceImpl(id); + public PresenceService createPresenceService(String id, PresenceBasicStatus status, String contact) { + return new PresenceServiceImpl(id, status, contact); } @Override diff --git a/java/impl/org/linphone/core/PresenceServiceImpl.java b/java/impl/org/linphone/core/PresenceServiceImpl.java index 5a3a31416..a3c53a890 100644 --- a/java/impl/org/linphone/core/PresenceServiceImpl.java +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -26,9 +26,9 @@ public class PresenceServiceImpl implements PresenceService { mNativePtr = nativePtr; } - private native long newPresenceServiceImpl(String id); - protected PresenceServiceImpl(String id) { - mNativePtr = newPresenceServiceImpl(id); + 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); From 461baa0e2820334905b4b0c03fa7bb3ab6fac8dc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 10 Sep 2013 15:48:23 +0200 Subject: [PATCH 659/909] Added linphonerc setting to disable ha1 password storage for auth info --- coreapi/authentication.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 4682325e9..57af57927 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -162,7 +162,7 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj==NULL || lp_config_get_int(config, "sip", "store_auth_info", 1) == 0){ return; } - if (!obj->ha1 && obj->realm && obj->passwd && (obj->username||obj->userid)) { + 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); From 9df7a19ca3c32044eee9eee9670ef91be278828b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Sep 2013 16:25:52 +0200 Subject: [PATCH 660/909] support all reasons for linphone_core_decline_call(). update ms2 --- coreapi/bellesip_sal/sal_op_call.c | 32 +++++------------------------- mediastreamer2 | 2 +- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 69aefd556..5f7a53789 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -646,46 +646,24 @@ int sal_call_accept(SalOp*h){ 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; - switch(reason) { - case SalReasonBusy: - status=486; - break; - case SalReasonTemporarilyUnavailable: - status=480; - break; - case SalReasonDoNotDisturb: - status=600; - break; - case SalReasonMedia: - status=415; - break; - case SalReasonDeclined: - status=603; - break; - case SalReasonRedirect: - if(redirection!=NULL) { + int status=sal_reason_to_sip_code(reason); + + if (reason==SalReasonRedirect){ + if (redirection!=NULL) { if (strstr(redirection,"sip:")!=0) status=302; status=380; contact= belle_sip_header_contact_new(); belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); - break; } else { ms_error("Cannot redirect to null"); } - /* no break */ - - default: - status=500; - ms_error("Unexpected decline reason [%i]",reason); - /* no break */ } response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); belle_sip_server_transaction_send_response(op->pending_server_trans,response); return 0; - } + int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); if (reinvite){ diff --git a/mediastreamer2 b/mediastreamer2 index ec2d04150..6d02dd51a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ec2d04150521197905bf5812991b54bab97fbdf8 +Subproject commit 6d02dd51a10ddd6125d66b5a03770face3ffb172 From 3a69a548dfd963eb34323d66761564cca74d771e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Sep 2013 16:35:34 +0200 Subject: [PATCH 661/909] move cpu count detection to mediastreamer2 --- gtk/main.c | 13 +------------ mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 60c6931ae..de8dd9fa2 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -232,15 +232,6 @@ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); - long num_cpu=1; -#ifdef WIN32 /*fixme to be tested*/ - SYSTEM_INFO sysinfo; - GetSystemInfo( &sysinfo ); - - num_cpu = sysinfo.dwNumberOfProcessors; -#elif __APPLE_ || __linux - num_cpu = sysconf( _SC_NPROCESSORS_ONLN ); -#endif vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; @@ -261,9 +252,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); - if (num_cpu>1) { - ms_set_cpu_count(num_cpu); - } + 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); diff --git a/mediastreamer2 b/mediastreamer2 index 6d02dd51a..a1a296d10 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6d02dd51a10ddd6125d66b5a03770face3ffb172 +Subproject commit a1a296d106633ff6f250db46e991f53acf4f7991 From 05ee4c4a31efdc8b2d85b6bc49191c8c74ab362d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Sep 2013 21:55:13 +0200 Subject: [PATCH 662/909] allow adding Contacts in publish --- coreapi/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 0b54f607a..557560011 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "private.h" - +#include "lpconfig.h" struct _LinphoneEvent{ LinphoneSubscriptionDir dir; @@ -156,7 +156,7 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ SalBody salbody; LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event); - linphone_configure_op(lc,lev->op,resource,NULL,FALSE); + linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0)); sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); return lev; } From ceeaf2b2b66daa6aab9d20211f8a03e53f3715a0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Sep 2013 22:00:55 +0200 Subject: [PATCH 663/909] fix compilation issue on iOS --- coreapi/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index ca91dd7c0..2059a9ff9 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -136,7 +136,7 @@ AM_CXXFLAGS=$(AM_CFLAGS) make_gitversion_h: if test "$(GITDESCRIBE)" != "" ; then \ - if test "$(GIT_TAG)" != $(PACKAGE_VERSION) ; then \ + if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \ echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ exit 1; \ fi ; \ From adef4bdb1233ecd2edcfd300dca20bf2533e68d8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Sep 2013 22:38:16 +0200 Subject: [PATCH 664/909] fix build problems when building out of sources --- coreapi/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 2059a9ff9..b6ed2ec32 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,8 +1,8 @@ GITVERSION_FILE=liblinphone_gitversion.h GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp -GITDESCRIBE=`git describe --always` -GIT_TAG=`git describe --abbrev=0` -GITREVISION=`git rev-parse HEAD` +GITDESCRIBE=`cd $(top_srcdir) && git describe --always` +GIT_TAG=`cd $(top_srcdir) && git describe --abbrev=0` +GITREVISION=`cd $(top_srcdir) && git rev-parse HEAD` ECHO=/bin/echo From 2cbe71c569e089803800a8080c134f45c82b6faa Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 11 Sep 2013 09:51:03 +0200 Subject: [PATCH 665/909] Fix possible crash when generating presence xml. --- coreapi/presence.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 16c8bdcd2..314946c4f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1528,8 +1528,11 @@ static int write_xml_presence_service(xmlTextWriterPtr writer, LinphonePresenceS err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"priority", (const xmlChar *)"0.8"); } if (err >= 0) { - const char *contact_str = service->contact; - if (contact_str == NULL) contact_str = contact; + 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) { From 3fdf79fdc5df584a4efe7d2ff35ee904691b1b4d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 11 Sep 2013 14:21:46 +0200 Subject: [PATCH 666/909] make sure random port is used if sip_random_port=1 and no transport selected --- coreapi/linphonecore.c | 8 +++++--- mediastreamer2 | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4c501c6fa..ac9f22355 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1890,15 +1890,17 @@ int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * t if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) { /*legacy random mode*/ - if (tr.udp_port>0 && random_port){ + if (tr.udp_port>0){ tr.udp_port=random_port; tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tcp_port>0 && random_port){ + }else if (tr.tcp_port>0){ tr.tcp_port=random_port; tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tls_port>0 && random_port){ + }else if (tr.tls_port>0){ tr.tls_port=random_port; tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ + } else { + tr.udp_port=random_port; } } if (tr.udp_port == LC_SIP_TRANSPORT_RANDOM) { diff --git a/mediastreamer2 b/mediastreamer2 index a1a296d10..ec2d04150 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a1a296d106633ff6f250db46e991f53acf4f7991 +Subproject commit ec2d04150521197905bf5812991b54bab97fbdf8 From ab2b7d0e38e40c362015ed04e699f8c4286e064b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 12 Sep 2013 03:18:25 +0200 Subject: [PATCH 667/909] allow contacts to be sent in publish, and better management of publish. --- coreapi/bellesip_sal/sal_op_publish.c | 6 ++++++ coreapi/proxy.c | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index ec4ecc324..ce3490eac 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -45,6 +45,9 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); + if (sal_op_get_contact(op)){ + 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); @@ -67,6 +70,9 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); + if (sal_op_get_contact(op)){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); + } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 3247f5086..275aa1bfd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -840,15 +840,22 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm } int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){ - int err; + int err=0; - if (proxy->publish_op==NULL){ - proxy->publish_op=sal_op_new(proxy->lc->sal); - sal_op_set_route(proxy->publish_op,proxy->reg_proxy); - sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); - sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); - } - err=sal_publish_presence(proxy->publish_op,NULL,NULL,proxy->expires,(SalPresenceModel *)presence); + if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){ + if (proxy->publish_op==NULL){ + proxy->publish_op=sal_op_new(proxy->lc->sal); + sal_op_set_route(proxy->publish_op,proxy->reg_proxy); + sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); + sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); + if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){ + SalAddress *addr=sal_address_new(NULL); + sal_op_set_contact(proxy->publish_op,addr); + sal_address_unref(addr); + } + } + err=sal_publish_presence(proxy->publish_op,NULL,NULL,proxy->expires,(SalPresenceModel *)presence); + }else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/ return err; } @@ -1175,12 +1182,14 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ } if (can_register(cfg)){ linphone_proxy_config_register(cfg); + ms_message("***Registering...(%p)",cfg); cfg->commit=FALSE; if (cfg->publish) cfg->send_publish=TRUE; } } if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){ linphone_proxy_config_send_publish(cfg,lc->presence_model); + ms_message("***Publishing..."); cfg->send_publish=FALSE; } } From 26c8f6ff983bda1dee4553e11eac300989c42925 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 12 Sep 2013 11:59:06 +0200 Subject: [PATCH 668/909] only propagate net,download_ptime to rtp,download_ptime if value != 0 --- coreapi/linphonecore.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ac9f22355..08d30d2d8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -494,8 +494,11 @@ static void net_config_read (LinphoneCore *lc) lc->net_conf.nat_sdp_only=tmp; tmp=lp_config_get_int(lc->config,"net","mtu",1300); linphone_core_set_mtu(lc,tmp); - tmp=lp_config_get_int(lc->config,"net","download_ptime",0); - linphone_core_set_download_ptime(lc,tmp); + tmp=lp_config_get_int(lc->config,"net","download_ptime",-1); + if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) { + /*legacy parameter*/ + linphone_core_set_download_ptime(lc,tmp); + } /* This is to filter out unsupported firewall policies */ linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc)); From cbf99ae50447ab3b7d0f167afc31f75a9ea15f79 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 12 Sep 2013 12:32:01 +0200 Subject: [PATCH 669/909] fix presence test --- tester/presence_tester.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tester/presence_tester.c b/tester/presence_tester.c index af287d141..cc95d6c8a 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -203,8 +203,6 @@ static void simple_subscribe(void) { CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); - - linphone_core_manager_destroy(marie); CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ @@ -262,7 +260,7 @@ static void presence_information(void) { /* Presence activity without description. */ presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityDinner, NULL); linphone_core_set_presence_model(pauline->lc, presence); - wait_core(marie->lc); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityDinner,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); CU_ASSERT_PTR_NOT_NULL(activity); @@ -273,7 +271,7 @@ static void presence_information(void) { /* Presence activity with description. */ presence = linphone_presence_model_new_with_activity(LinphonePresenceActivitySteering, bike_description); linphone_core_set_presence_model(pauline->lc, presence); - wait_core(marie->lc); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivitySteering,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); CU_ASSERT_PTR_NOT_NULL(activity); @@ -285,7 +283,7 @@ static void presence_information(void) { /* 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_core(marie->lc); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityVacation,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1); activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); CU_ASSERT_PTR_NOT_NULL(activity); @@ -306,7 +304,7 @@ static void presence_information(void) { 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_core(marie->lc); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnThePhone,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone, 1); contact2 = linphone_presence_model_get_contact(presence); CU_ASSERT_PTR_NOT_NULL(contact2); @@ -319,7 +317,7 @@ static void presence_information(void) { current_timestamp = time(NULL); presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityShopping, NULL); linphone_core_set_presence_model(pauline->lc, presence); - wait_core(marie->lc); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityShopping,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityShopping, 1); presence_timestamp = linphone_presence_model_get_timestamp(presence); CU_ASSERT_TRUE(presence_timestamp >= current_timestamp); From e48d96c6382fa89b55e45ade04487f6583858f98 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 12 Sep 2013 14:59:40 +0200 Subject: [PATCH 670/909] Fix opening of configuration file Allow passing absolute filename. --- gtk/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gtk/main.c b/gtk/main.c index de8dd9fa2..9f781d2cd 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -164,7 +164,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){ @@ -1924,6 +1926,12 @@ int main(int argc, char *argv[]){ return -1; } if (config_file) free(config_file); + if (custom_config_file && !g_path_is_absolute(custom_config_file)) { + gchar *res = g_get_current_dir(); + res = g_strjoin(G_DIR_SEPARATOR_S, res, custom_config_file, NULL); + free(custom_config_file); + custom_config_file = res; + } config_file=linphone_gtk_get_config_file(custom_config_file); settings=gtk_settings_get_default(); From 16da9c1b3bf76fa74f97fec1029f217c4fb68ecc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 15:13:57 +0200 Subject: [PATCH 671/909] send username in contacts of publish send unSUBSCRIBE when friend subscription is toggled off. --- coreapi/friend.c | 2 ++ coreapi/linphonecore.c | 2 ++ coreapi/proxy.c | 4 +--- mediastreamer2 | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 158317612..2aa0db7cf 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -406,6 +406,8 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ if (fr->subscribe && fr->subscribe_active==FALSE){ ms_message("Sending a new SUBSCRIBE"); __linphone_friend_do_subscribe(fr); + }else if (fr->subscribe_active && !fr->subscribe){ + linphone_friend_unsubscribe(fr); } ms_message("linphone_friend_apply() done."); lc->bl_refresh=TRUE; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 08d30d2d8..2c3feefa1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5017,7 +5017,9 @@ static MSVideoSizeDef supported_resolutions[]={ { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, { {MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H} , "vga" }, +#ifdef __ios { {MS_VIDEO_SIZE_IOS_MEDIUM_H,MS_VIDEO_SIZE_IOS_MEDIUM_W} , "ios-medium" }, +#endif { {MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H} , "cif" }, { {MS_VIDEO_SIZE_QVGA_W,MS_VIDEO_SIZE_QVGA_H} , "qvga" }, { {MS_VIDEO_SIZE_QCIF_W,MS_VIDEO_SIZE_QCIF_H} , "qcif" }, diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 275aa1bfd..08df88bb6 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -849,7 +849,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){ - SalAddress *addr=sal_address_new(NULL); + SalAddress *addr=sal_address_new(linphone_proxy_config_get_identity(proxy)); sal_op_set_contact(proxy->publish_op,addr); sal_address_unref(addr); } @@ -1182,14 +1182,12 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ } if (can_register(cfg)){ linphone_proxy_config_register(cfg); - ms_message("***Registering...(%p)",cfg); cfg->commit=FALSE; if (cfg->publish) cfg->send_publish=TRUE; } } if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){ linphone_proxy_config_send_publish(cfg,lc->presence_model); - ms_message("***Publishing..."); cfg->send_publish=FALSE; } } diff --git a/mediastreamer2 b/mediastreamer2 index ec2d04150..7c4bfcb0b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ec2d04150521197905bf5812991b54bab97fbdf8 +Subproject commit 7c4bfcb0baf9ebc0e6edd94fc46b7a512fb733bf From c413a81e39547c2a3e0705e1072bb50a54dd7050 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 16:10:34 +0200 Subject: [PATCH 672/909] bugfixes in Event api when refreshing subscribes fix test suite --- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_events.c | 50 ++++++++++------------------ coreapi/bellesip_sal/sal_op_impl.c | 1 + coreapi/callbacks.c | 3 +- tester/eventapi_tester.c | 4 +-- 5 files changed, 24 insertions(+), 35 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index d99235c4f..befbb3fda 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -92,6 +92,7 @@ struct SalOp{ int ref; SalOpType type; SalPrivacyMask privacy; + belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/ bool_t auto_answer_asked; bool_t sdp_offering; bool_t call_released; diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index cf67c992d..b43e3d579 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -147,15 +147,19 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque op->pending_server_trans=server_transaction; event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event"); - eventname=belle_sip_header_get_unparsed_value(event_header); sal_op_get_body(op,(belle_sip_message_t*)req,&body); - if (eventname==NULL){ + 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){ @@ -210,26 +214,6 @@ void sal_op_subscribe_fill_cbs(SalOp*op) { op->type=SalOpSubscribe; } -static int set_event_name(SalOp *op, belle_sip_message_t *msg){ - belle_sip_transaction_t *last_transaction; - belle_sip_request_t *req; - belle_sip_header_t *event; - - if (!op->dialog) return -1; - - last_transaction=belle_sip_dialog_get_last_transaction(op->dialog); - - if (!last_transaction) return -1; - - req=belle_sip_transaction_get_request(last_transaction); - event=belle_sip_message_get_header((belle_sip_message_t*)req,"Event"); - if (!event){ - ms_error("No event header in last request."); - return -1; - } - belle_sip_message_add_header(msg,event); - return 0; -} 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; @@ -243,20 +227,25 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event sal_op_subscribe_fill_cbs(op); /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ req=sal_op_build_request(op,"SUBSCRIBE"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); + 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); }else{ - belle_sip_transaction_t *last=belle_sip_dialog_get_last_transaction(op->dialog); - belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last)); req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); if (!req) { ms_error("Cannot create subscribe refresh."); return -1; } if (expires==-1){ + belle_sip_transaction_t *last=(belle_sip_transaction_t*)op->pending_client_trans; + belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last)); belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t); expires=belle_sip_header_expires_get_expires(eh); } - set_event_name(op,(belle_sip_message_t*)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))); sal_op_add_body(op,(belle_sip_message_t*)req,body); @@ -271,7 +260,7 @@ int sal_unsubscribe(SalOp *op){ } if (op->refresher) belle_sip_refresher_stop(op->refresher); - set_event_name(op,(belle_sip_message_t*)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(0))); return sal_op_send_request(op,req); } @@ -299,10 +288,7 @@ int sal_notify(SalOp *op, const SalBody *body){ if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; - if (set_event_name(op,(belle_sip_message_t*)notify)==-1){ - belle_sip_object_unref(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))); @@ -315,7 +301,7 @@ 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; - set_event_name(op,(belle_sip_message_t*)notify); + 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 index b3e6dc12e..e31ec7a4d 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -59,6 +59,7 @@ void sal_op_release_impl(SalOp *op){ if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + if (op->event) belle_sip_object_unref(op->event); __sal_op_free(op); return ; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6d0083ea0..e6f194532 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1059,7 +1059,8 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, cons lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing,eventname); } if (lc->vtable.notify_received){ - lc->vtable.notify_received(lc,lev,eventname,linphone_content_from_sal_body(&content,body)); + const LinphoneContent *ct=linphone_content_from_sal_body(&content,body); + if (ct) lc->vtable.notify_received(lc,lev,eventname,ct); } if (st!=SalSubscribeNone){ linphone_event_set_state(lev,linphone_subscription_state_from_sal(st)); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index cc7a6905b..563f856a4 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -126,8 +126,8 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); - /*make sure marie receives first notification before terminating - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000));*/ + /*make sure marie receives first notification before terminating*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); if (terminated_by_subscriber){ linphone_event_terminate(lev); From bbedbf76523d76851b0026a45da4ba7b00905fdf Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 16:48:50 +0200 Subject: [PATCH 673/909] update ms2 --- coreapi/friend.c | 8 ++++++++ coreapi/linphonefriend.h | 11 +++++++++++ coreapi/private.h | 1 + mediastreamer2 | 2 +- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 2aa0db7cf..d045f4c46 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -159,6 +159,14 @@ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ return fr; } +void linphone_friend_set_user_data(LinphoneFriend *lf, void *data){ + lf->up=data; +} + +void* linphone_friend_get_user_data(const LinphoneFriend *lf){ + return lf->up; +} + bool_t linphone_friend_in_list(const LinphoneFriend *lf){ return lf->lc!=NULL; } diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 8eea8c052..57697e308 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -228,6 +228,17 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFr */ 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); LINPHONE_PUBLIC void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); LINPHONE_PUBLIC const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); diff --git a/coreapi/private.h b/coreapi/private.h index 7c8dd1667..11899d03e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -439,6 +439,7 @@ struct _LinphoneFriend{ struct _LinphoneCore *lc; BuddyInfo *info; char *refkey; + void *up; bool_t subscribe; bool_t subscribe_active; bool_t inc_subscribe_pending; diff --git a/mediastreamer2 b/mediastreamer2 index 7c4bfcb0b..612d8ec2c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7c4bfcb0baf9ebc0e6edd94fc46b7a512fb733bf +Subproject commit 612d8ec2c4997f457c1f2142618e2b87b5d46f44 From ede5ab7c703618937650dda6e5357bc0715b75ae Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Sep 2013 17:15:30 +0200 Subject: [PATCH 674/909] Remove duplicate definition. --- coreapi/linphonefriend.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 57697e308..61fd33f2a 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -149,13 +149,6 @@ LINPHONE_PUBLIC int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneA */ LINPHONE_PUBLIC int linphone_friend_set_name(LinphoneFriend *lf, const char *name); -/** - * set the display name for this friend - * @param lf #LinphoneFriend object - * @param name - */ -int linphone_friend_set_name(LinphoneFriend *lf, const char *name); - /** * get address of this friend * @param lf #LinphoneFriend object From 26a522902e38b825ce85fe07f34e3b504a4f05b8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 18:37:52 +0200 Subject: [PATCH 675/909] fix crash in presence unsubscription --- coreapi/bellesip_sal/sal_op_presence.c | 6 +++++- coreapi/friend.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 5ea4cfe7b..eef7d3916 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -295,10 +295,14 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi return -1; } } + if (!op->event){ + op->event=belle_sip_header_create("Event","presence"); + belle_sip_object_ref(op->event); + } belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag"); belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag"); req=sal_op_build_request(op,"SUBSCRIBE"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); + 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); diff --git a/coreapi/friend.c b/coreapi/friend.c index d045f4c46..7b685a408 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -451,11 +451,13 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) } 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); } } From d11111b22517b21efc5fe702e05b34cb45fc1498 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 21:17:09 +0200 Subject: [PATCH 676/909] update ms2 for AEC on android 4.3 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 612d8ec2c..f1d3279e1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 612d8ec2c4997f457c1f2142618e2b87b5d46f44 +Subproject commit f1d3279e11269a2e84f30540116dc436132d7335 From bce40f37753f6c1264fc9422e77ebac2629b75e7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Sep 2013 21:51:07 +0200 Subject: [PATCH 677/909] allow passing NULL LinphoneContent to API. --- coreapi/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/info.c b/coreapi/info.c index ab1c2cd6a..539855ab8 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -91,7 +91,7 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons } SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ - if (lc->type){ + if (lc && lc->type){ body->type=lc->type; body->subtype=lc->subtype; body->data=lc->data; From 2cf1ff7ecbb9dbf9f6db5558d2af27de81792b78 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Sep 2013 09:25:17 +0200 Subject: [PATCH 678/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f1d3279e1..8ee88e781 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f1d3279e11269a2e84f30540116dc436132d7335 +Subproject commit 8ee88e781b5d2693a9360d451b903d472abe88f0 From cb1b69f2eb8e281723f39886c056398b24604cbf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Sep 2013 09:25:31 +0200 Subject: [PATCH 679/909] Add linphone_friend_get_name(). --- coreapi/friend.c | 8 +++++++- coreapi/linphonefriend.h | 35 ++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 7b685a408..f5b6f626c 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -207,7 +207,7 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char } } -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); @@ -288,6 +288,12 @@ const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){ return lf->uri; } +const char * linphone_friend_get_name(const LinphoneFriend *lf) { + LinphoneAddress *fr = lf->uri; + if (fr == NULL) return NULL; + return linphone_address_get_display_name(fr); +} + bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){ return lf->subscribe; } diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 61fd33f2a..ae5c13dc9 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -101,11 +101,10 @@ typedef enum _LinphoneOnlineStatus{ * Pending */ LinphoneStatusPending, - - /** - * Vacation - */ - LinphoneStatusVacation, + /** + * Vacation + */ + LinphoneStatusVacation, LinphoneStatusEnd }LinphoneOnlineStatus; @@ -136,25 +135,39 @@ LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_addr(const char *addr); LINPHONE_PUBLIC void linphone_friend_destroy(LinphoneFriend *lf); /** - * set #LinphoneAddress for this friend + * Set #LinphoneAddress for this friend * @param fr #LinphoneFriend object * @param address #LinphoneAddress */ -LINPHONE_PUBLIC int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneAddress* address); +LINPHONE_PUBLIC int linphone_friend_set_address(LinphoneFriend *fr, const LinphoneAddress* address); /** - * set the display name for this friend + * 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 address of this friend + * Get the display name for this friend * @param lf #LinphoneFriend object - * @return #LinphoneAddress + * @return The display name of this friend */ -LINPHONE_PUBLIC const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); +LINPHONE_PUBLIC const char * linphone_friend_get_name(const LinphoneFriend *lf); + /** * get subscription flag value * @param lf #LinphoneFriend object From 68684f3c243a19d7e9e19d2f4313cd67fbe76dc2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 16 Sep 2013 09:36:53 +0200 Subject: [PATCH 680/909] add link to libopus to android build script --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 8ee88e781..4d4137357 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8ee88e781b5d2693a9360d451b903d472abe88f0 +Subproject commit 4d4137357d244681fcc714411345f77e03459bdf From f754eae25f92fdef0ea4c370c0085c4bb9b3404a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Sep 2013 11:47:52 +0200 Subject: [PATCH 681/909] Some cleaning. --- coreapi/linphonefriend.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index ae5c13dc9..cd74a10c6 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -184,14 +184,15 @@ LINPHONE_PUBLIC bool_t linphone_friend_subscribes_enabled(const LinphoneFriend * */ 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. */ LINPHONE_PUBLIC int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol); + /** * get current subscription policy for this #LinphoneFriend * @param lf #LinphoneFriend object @@ -205,20 +206,18 @@ LINPHONE_PUBLIC LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy * * 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); - - - /** * @brief Get the status of a friend * @param[in] lf A #LinphoneFriend object @@ -234,7 +233,6 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFr */ LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); - /** * Store user pointer to friend object. **/ @@ -250,7 +248,6 @@ LINPHONE_PUBLIC void linphone_friend_set_ref_key(LinphoneFriend *lf, const char LINPHONE_PUBLIC const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); LINPHONE_PUBLIC bool_t linphone_friend_in_list(const LinphoneFriend *lf); -#define linphone_friend_url(lf) ((lf)->url) /** * Return humain readable presence status @@ -293,35 +290,41 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_core_get_presence_info(const Linph LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); LINPHONE_PUBLIC 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 */ 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 */ LINPHONE_PUBLIC 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 * */ LINPHONE_PUBLIC void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); + LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); From 632f0ac005b532e3a5d1b8ba3ef550df789b10ee Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 16 Sep 2013 11:53:29 +0200 Subject: [PATCH 682/909] add libopus to android.mk --- build/android/common.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/android/common.mk b/build/android/common.mk index 09cf9545a..48047d67b 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -226,6 +226,9 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/sqlite3/ endif +ifeq ($(BUILD_SQLITE),1) +LOCAL_STATIC_LIBRARIES += libopus +endif LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) From 5c88a8dd21f97f253e561276eaa5b9cd7efe9438 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 16 Sep 2013 16:40:58 +0200 Subject: [PATCH 683/909] fix crash in sal_process_authentication when auth cannot be sent synchronously --- coreapi/bellesip_sal/sal_impl.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 4f88c257d..5ce18ab0b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -105,7 +105,8 @@ void sal_remove_pending_auth(Sal *sal, SalOp *op){ } void sal_process_authentication(SalOp *op) { - belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); + 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; @@ -114,30 +115,31 @@ void sal_process_authentication(SalOp *op) { sal_add_pending_auth(op->base.root,op); if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { - request = belle_sip_dialog_create_request_from(op->dialog,request); - if (!request) - request = belle_sip_dialog_create_queued_request_from(op->dialog,request); + 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 { - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); - belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); + 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 (request==NULL) { + 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,request,response,&auth_list)) { + if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) { if (is_within_dialog) { - sal_op_send_request(op,request); + sal_op_send_request(op,new_request); } else { - sal_op_resend_request(op,request); + sal_op_resend_request(op,new_request); } sal_remove_pending_auth(op->base.root,op); }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); if (is_within_dialog) { - belle_sip_object_unref(request); + belle_sip_object_unref(new_request); } if (op->auth_info) sal_auth_info_delete(op->auth_info); auth_event=(belle_sip_auth_event_t*)(auth_list->data); From a1ec7d69658b8b534a9c5b6ca446dddd82442b41 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 16 Sep 2013 16:48:20 +0200 Subject: [PATCH 684/909] fix Android makefiles for audio build --- build/android/Android-no-neon.mk | 2 +- build/android/Android.mk | 2 +- build/android/common.mk | 9 +++------ mediastreamer2 | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index c1f9e7f05..79b58baaf 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -25,7 +25,7 @@ include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk -ifeq ($(LINPHONE_VIDEO),1) +ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ liblinavcodecnoneon \ liblinswscale \ diff --git a/build/android/Android.mk b/build/android/Android.mk index 645676ffc..2b2389fc8 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -25,7 +25,7 @@ include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk -ifeq ($(LINPHONE_VIDEO),1) +ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ liblinavcodec \ liblinswscale \ diff --git a/build/android/common.mk b/build/android/common.mk index 48047d67b..4e6efdd7d 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -74,14 +74,11 @@ LOCAL_CFLAGS += \ LOCAL_CFLAGS += -DIN_LINPHONE -ifeq ($(LINPHONE_VIDEO),1) -LOCAL_CFLAGS += -DVIDEO_ENABLED +ifeq ($(_BUILD_VIDEO),1) +LOCAL_CFLAGS += -DVIDEO_ENABLED -DENABLE_HD ifeq ($(BUILD_X264),1) LOCAL_CFLAGS += -DHAVE_X264 endif -ifeq ($(LINPHONE_HD_VIDEO),1) -LOCAL_CFLAGS += -DENABLE_HD -endif endif ifeq ($(USE_JAVAH),1) @@ -157,7 +154,7 @@ LOCAL_SHARED_LIBRARIES += libbcg729 LOCAL_STATIC_LIBRARIES += libmsbcg729 endif -ifeq ($(LINPHONE_VIDEO),1) +ifeq ($(_BUILD_VIDEO),1) LOCAL_LDLIBS += -lGLESv2 LOCAL_STATIC_LIBRARIES += libvpx ifeq ($(BUILD_X264),1) diff --git a/mediastreamer2 b/mediastreamer2 index 4d4137357..ac5233ae1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4d4137357d244681fcc714411345f77e03459bdf +Subproject commit ac5233ae16394d59cf4d9783a229f2adc2111b12 From f9e0782528bd292ad35c3a3b2b66c4bd99338829 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 16 Sep 2013 20:30:34 +0200 Subject: [PATCH 685/909] enable generic publish not to be refreshed automatically --- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_events.c | 1 + coreapi/bellesip_sal/sal_op_impl.c | 6 ++++++ coreapi/event.c | 1 + coreapi/help/Doxyfile.in | 2 +- include/sal/sal.h | 2 ++ 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index befbb3fda..4b9120196 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -96,6 +96,7 @@ struct SalOp{ bool_t auto_answer_asked; bool_t sdp_offering; bool_t call_released; + bool_t manual_refresher; }; diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index b43e3d579..6f20c1f92 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -84,6 +84,7 @@ static void subscribe_response_event(void *op_base, const belle_sip_response_eve } if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); + if (op->refresher) belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); } if (sss==SalSubscribeNone) sss=SalSubscribeActive; /*without Subscription-state header, consider subscription is accepted.*/ op->base.root->callbacks.subscribe_response(op,sss,SalErrorNone,SalReasonUnknown); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index e31ec7a4d..bf6b5f152 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -25,6 +25,7 @@ SalOp * sal_op_new(Sal *sal){ __sal_op_init(op,sal); op->type=SalOpUnknown; op->privacy=SalPrivacyNone; + op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/ sal_op_ref(op); return op; } @@ -478,6 +479,7 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { belle_sip_refresher_set_listener(op->refresher,listener,op); belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); + belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); return 0; } else { return -1; @@ -573,3 +575,7 @@ bool_t sal_op_is_secure(const SalOp* op) { return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0; } + +void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){ + op->manual_refresher=enabled; +} diff --git a/coreapi/event.c b/coreapi/event.c index 557560011..5f850e0de 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -157,6 +157,7 @@ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *re SalBody salbody; LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event); linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0)); + sal_op_set_manual_refresher_mode(lev->op,lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); return lev; } diff --git a/coreapi/help/Doxyfile.in b/coreapi/help/Doxyfile.in index 03dbf91a0..dce1804b2 100644 --- a/coreapi/help/Doxyfile.in +++ b/coreapi/help/Doxyfile.in @@ -165,7 +165,7 @@ MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- -GENERATE_XML = NO +GENERATE_XML = YES XML_OUTPUT = xml XML_SCHEMA = XML_DTD = diff --git a/include/sal/sal.h b/include/sal/sal.h index 4305e4df0..da97bf7ec 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -499,6 +499,8 @@ const char* sal_op_get_call_id(const SalOp *op); const SalAddress* sal_op_get_service_route(const SalOp *op); void sal_op_set_service_route(SalOp *op,const SalAddress* service_route); +void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled); + /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); From fed415507fddb794d2110c3a4e022c12018229e5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Sep 2013 14:03:52 +0200 Subject: [PATCH 686/909] enhance event API to be notified of publish states. lp-gen-wrappers is in progress --- coreapi/bellesip_sal/sal_impl.c | 31 +- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_events.c | 3 +- coreapi/bellesip_sal/sal_op_impl.c | 9 +- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/bellesip_sal/sal_op_publish.c | 32 +- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/callbacks.c | 30 +- coreapi/event.c | 100 ++++-- coreapi/event.h | 52 ++- coreapi/linphonecore.h | 6 + coreapi/private.h | 18 ++ include/sal/sal.h | 5 + tester/eventapi_tester.c | 78 ++++- tester/liblinphone_tester.c | 5 +- tester/liblinphone_tester.h | 8 +- tools/Makefile.am | 12 +- tools/genwrappers.cc | 356 +++++++++++++++++++++ 18 files changed, 693 insertions(+), 57 deletions(-) create mode 100644 tools/genwrappers.cc diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 5ce18ab0b..d00ba86b7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -174,7 +174,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e } } -static void process_request_event(void *sal, const belle_sip_request_event_t *event) { +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); @@ -195,36 +196,41 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev return; } }else if (strcmp("INVITE",method)==0) { - op=sal_op_new((Sal*)sal); + 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*)sal); + 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*)sal); + 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*)sal)->prov,resp); + 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*)sal)->prov,resp); + 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*)sal)->prov,resp); + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) { + resp=belle_sip_response_create_from_request(req,200);/*out of dialog BYE */ + belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA")); + belle_sip_provider_send_response(sal->prov,resp); return; }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,501); - belle_sip_provider_send_response(((Sal*)sal)->prov,resp); + belle_sip_provider_send_response(sal->prov,resp); return; } @@ -460,6 +466,10 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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; } @@ -825,3 +835,8 @@ int sal_get_refresher_retry_after(const Sal *sal) { 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; +} + diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 4b9120196..371153ea5 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -46,6 +46,7 @@ struct Sal{ bool_t tls_verify_cn; bool_t use_dates; bool_t auto_contacts; + bool_t enable_test_features; }; typedef enum SalOpState { diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 6f20c1f92..be60a0b98 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -22,11 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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) { - sal_op_unref(op); op->dialog=NULL; + sal_op_unref(op); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index bf6b5f152..640664ecc 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -407,10 +407,15 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal *sal_reason=SalReasonServiceUnavailable; break; default: - if (code>0){ + if (code>=300){ *sal_err=SalErrorFailure; *sal_reason=SalReasonUnknown; - }else *sal_err=SalErrorNoResponse; + }else if (code>=100){ + *sal_err=SalErrorNone; + *sal_reason=SalReasonUnknown; + }else if (code==0){ + *sal_err=SalErrorNoResponse; + } /* no break */ } } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index eef7d3916..85ecd4691 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -56,7 +56,7 @@ static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog } } -static void presence_refresher_listener( const belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){ +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: { diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index ce3490eac..f7788808c 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -19,21 +19,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" -static void publish_refresher_listener ( const belle_sip_refresher_t* refresher +static void publish_refresher_listener (belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ - ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); + ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op)); if (status_code==412){ /*resubmit the request after removing the SIP-If-Match*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match"); belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + }else if (status_code==0){ + op->base.root->callbacks.on_expire(op); + }else if (status_code>=200){ + SalError err; + SalReason reason; + sal_compute_sal_errors_from_code(status_code,&err,&reason); + op->base.root->callbacks.on_publish_response(op,err,reason); } } + +static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){ + SalOp *op=(SalOp*)userctx; + int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); + SalError err; + SalReason reason; + sal_compute_sal_errors_from_code(code,&err,&reason); + op->base.root->callbacks.on_publish_response(op,err,reason); +} + +void sal_op_publish_fill_cbs(SalOp*op) { + op->callbacks.process_response_event=publish_response_event; + op->type=SalOpPublish; +} + /*presence publish */ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){ belle_sip_request_t *req=NULL; @@ -68,7 +90,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna if (to) sal_op_set_to(op,to); - op->type=SalOpPublish; + sal_op_publish_fill_cbs(op); req=sal_op_build_request(op,"PUBLISH"); if (sal_op_get_contact(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); @@ -82,8 +104,6 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna 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),body); - return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); + 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 index cfdedc9e5..a611af029 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" -static void register_refresher_listener ( const belle_sip_refresher_t* refresher +static void register_refresher_listener (belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase) { diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e6f194532..7d437cf69 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1086,6 +1086,32 @@ static void subscribe_closed(SalOp *op){ linphone_event_set_state(lev,LinphoneSubscriptionTerminated); } +static void on_publish_response(SalOp* op, SalError err, SalReason reason){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + if (lev==NULL) return; + if (err==SalErrorNone){ + if (!lev->terminating) + linphone_event_set_publish_state(lev,LinphonePublishOk); + else + linphone_event_set_publish_state(lev,LinphonePublishCleared); + + }else{ + linphone_event_set_reason(lev,linphone_reason_from_sal(reason)); + linphone_event_set_publish_state(lev,LinphonePublishError); + } +} + +static void on_expire(SalOp *op){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + if (lev==NULL) return; + + if (linphone_event_get_publish_state(lev)==LinphonePublishOk){ + linphone_event_set_publish_state(lev,LinphonePublishExpiring); + } +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -1120,7 +1146,9 @@ SalCallbacks linphone_sal_callbacks={ notify_presence, ping_reply, auth_requested, - info_received + info_received, + on_publish_response, + on_expire }; diff --git a/coreapi/event.c b/coreapi/event.c index 5f850e0de..9546e9e7b 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -20,18 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "lpconfig.h" -struct _LinphoneEvent{ - LinphoneSubscriptionDir dir; - LinphoneCore *lc; - SalOp *op; - LinphoneSubscriptionState state; - LinphoneReason reason; - void *userdata; - int refcnt; - char *name; - LinphoneAddress *from; - LinphoneAddress *resource_addr; -}; LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){ switch(ss){ @@ -43,6 +31,31 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu return LinphoneSubscriptionNone; } +const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state){ + switch(state){ + case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone"; + case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived"; + case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit"; + case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending"; + case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive"; + case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated"; + case LinphoneSubscriptionError: return "LinphoneSubscriptionError"; + } + return NULL; +} + +LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state){ + switch(state){ + case LinphonePublishNone: return "LinphonePublishNone"; + case LinphonePublishProgress: return "LinphonePublishProgress"; + case LinphonePublishOk: return "LinphonePublishOk"; + case LinphonePublishError: return "LinphonePublishError"; + case LinphonePublishCleared: return "LinphonePublishCleared"; + case LinphonePublishExpiring: return "LinphonePublishExpiring"; + } + return NULL; +} + static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){ LinphoneEvent *lev=ms_new0(LinphoneEvent,1); lev->lc=lc; @@ -72,8 +85,9 @@ LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneS void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){ LinphoneCore *lc=lev->lc; - if (lev->state!=state){ - lev->state=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; if (lc->vtable.subscription_state_changed){ lc->vtable.subscription_state_changed(lev->lc,lev,state); } @@ -83,6 +97,21 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat } } +void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){ + LinphoneCore *lc=lev->lc; + if (lev->publish_state!=state){ + ms_message("LinphoneEvent [%p] moving to publish state %s",lev,linphone_publish_state_to_string(state)); + lev->publish_state=state; + if (lc->vtable.publish_state_changed){ + lc->vtable.publish_state_changed(lev->lc,lev,state); + } + } +} + +LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){ + return lev->publish_state; +} + void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){ lev->reason=reason; } @@ -105,7 +134,7 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress * int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; - if (lev->state!=LinphoneSubscriptionActive){ + if (lev->subscription_state!=LinphoneSubscriptionActive){ ms_error("linphone_event_update_subscribe(): cannot update subscription if subscription wasn't accepted."); return -1; } @@ -118,7 +147,7 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b int linphone_event_accept_subscription(LinphoneEvent *lev){ int err; - if (lev->state!=LinphoneSubscriptionIncomingReceived){ + if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){ ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received."); return -1; } @@ -131,7 +160,7 @@ int linphone_event_accept_subscription(LinphoneEvent *lev){ int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){ int err; - if (lev->state!=LinphoneSubscriptionIncomingReceived){ + if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){ ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received."); return -1; } @@ -142,7 +171,7 @@ int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; - if (lev->state!=LinphoneSubscriptionActive){ + if (lev->subscription_state!=LinphoneSubscriptionActive){ ms_error("linphone_event_notify(): cannot notify if subscription is not active."); return -1; } @@ -155,17 +184,30 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ SalBody salbody; + int err; LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event); linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0)); sal_op_set_manual_refresher_mode(lev->op,lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); - sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); + err=sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); + if (err==0){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else{ + linphone_event_unref(lev); + lev=NULL; + } return lev; } - int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; - return sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); + int err; + err=sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); + if (err==0){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else{ + linphone_event_set_publish_state(lev,LinphonePublishError); + } + return err; } void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ @@ -177,15 +219,25 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev){ } 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->state!=LinphoneSubscriptionNone){ - linphone_event_set_state(lev,LinphoneSubscriptionTerminated); + if (lev->publish_state!=LinphonePublishNone){ + if (lev->publish_state==LinphonePublishOk){ + sal_publish(lev->op,NULL,NULL,NULL,0,NULL); + } + return; } + + if (lev->subscription_state!=LinphoneSubscriptionNone){ + linphone_event_set_state(lev,LinphoneSubscriptionTerminated); + return; + } + } @@ -213,7 +265,7 @@ LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){ } LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){ - return lev->state; + return lev->subscription_state; } const char *linphone_event_get_name(const LinphoneEvent *lev){ diff --git a/coreapi/event.h b/coreapi/event.h index 8ed3dae4b..fa97c2387 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -26,6 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct _LinphoneEvent; +/** + * Object representing an event state, which is subcribed or published. + * @see linphone_core_publish() + * @see linphone_core_subscribe() +**/ typedef struct _LinphoneEvent LinphoneEvent; /** @@ -55,8 +60,32 @@ enum _LinphoneSubscriptionState{ LinphoneSubscriptionError /**refresh_generic_publish property is set to 0.*/ + LinphonePublishCleared /** #include "liblinphone_tester.h" @@ -78,6 +79,20 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li } } +void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + stats* counters = get_stats(lc); + switch(state){ + case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break; + case LinphonePublishOk: counters->number_of_LinphonePublishOk++; break; + case LinphonePublishError: counters->number_of_LinphonePublishError++; break; + case LinphonePublishExpiring: counters->number_of_LinphonePublishExpiring++; break; + case LinphonePublishCleared: counters->number_of_LinphonePublishCleared++;break; + default: + break; + } + +} + static void subscribe_test_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -151,17 +166,68 @@ static void subscribe_test_terminated_by_notifier(void){ subscribe_test_with_args(FALSE); } -test_t subscribe_tests[] = { +static void publish_test_with_args(bool_t refresh){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneContent content; + LinphoneEvent *lev; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",!refresh); + + lev=linphone_core_publish(marie->lc,pauline->identity,"dodo",5,&content); + linphone_event_ref(lev); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000)); + + if (!refresh){ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishExpiring,1,5000)); + linphone_event_update_publish(lev,&content); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000)); + }else{ + + } + + linphone_event_terminate(lev); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,1000)); + + linphone_event_unref(lev); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void publish_test(){ + publish_test_with_args(TRUE); +} + +static void publish_no_auto_test(){ + publish_test_with_args(FALSE); +} + +test_t event_tests[] = { { "Subscribe declined" , subscribe_test_declined }, { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, - { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier } + { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, + { "Publish", publish_test }, + { "Publish without automatic refresh",publish_no_auto_test } }; -test_suite_t subscribe_test_suite = { - "Subscribe", +test_suite_t event_test_suite = { + "Event", NULL, NULL, - sizeof(subscribe_tests) / sizeof(subscribe_tests[0]), - subscribe_tests + sizeof(event_tests) / sizeof(event_tests[0]), + event_tests }; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 25e91aa1e..a1115c8ce 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -106,7 +106,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); - + sal_enable_test_features(lc->sal,TRUE); #ifndef ANDROID snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path); #else @@ -190,6 +190,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.info_received=info_message_received; mgr->v_table.subscription_state_changed=linphone_subscription_state_change; mgr->v_table.notify_received=linphone_notify_received; + mgr->v_table.publish_state_changed=linphone_publish_state_changed; mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file); linphone_core_set_user_data(mgr->lc,mgr); reset_counters(&mgr->stat); @@ -311,7 +312,7 @@ void liblinphone_tester_init(void) { #ifdef UPNP add_test_suite(&upnp_test_suite); #endif - add_test_suite(&subscribe_test_suite); + add_test_suite(&event_test_suite); } void liblinphone_tester_uninit(void) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 70aeaf83e..f9c58d725 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -51,7 +51,7 @@ 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 subscribe_test_suite; +extern test_suite_t event_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -164,6 +164,11 @@ typedef struct _stats { int number_of_LinphoneSubscriptionTerminated; int number_of_LinphoneSubscriptionError; + int number_of_LinphonePublishProgress; + int number_of_LinphonePublishOk; + int number_of_LinphonePublishExpiring; + int number_of_LinphonePublishError; + int number_of_LinphonePublishCleared; }stats; typedef struct _LinphoneCoreManager { @@ -192,6 +197,7 @@ void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneI void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); +void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); LinphoneAddress * create_linphone_address(const char * domain); diff --git a/tools/Makefile.am b/tools/Makefile.am index 8757ab27f..9f8233a80 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,6 +12,8 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) +AM_CXXFLAGS=$(LIBXML2_CFLAGS) + EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc if BUILD_TOOLS @@ -39,7 +41,7 @@ liblpc2xml_la_LIBADD=\ libxml2lpc_la_LDFLAGS=-no-undefined liblpc2xml_la_LDFLAGS=-no-undefined -bin_PROGRAMS=xml2lpc_test lpc2xml_test +bin_PROGRAMS=xml2lpc_test lpc2xml_test lp-gen-wrappers xml2lpc_test_SOURCES=\ xml2lpc_test.c @@ -55,7 +57,13 @@ xml2lpc_test_LDADD=\ lpc2xml_test_CFLAGS=$(COMMON_CFLAGS) lpc2xml_test_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ - liblpc2xml.la + liblpc2xml.la + +lp_gen_wrappers_SOURCES=genwrappers.cc + +lp_gen_wrappers_LDADD= \ + $(LIBXML2_LIBS) + endif diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc new file mode 100644 index 000000000..c506f6f71 --- /dev/null +++ b/tools/genwrappers.cc @@ -0,0 +1,356 @@ +/* +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 +#include +#include +#include +#include +#include + + +using namespace::std; + + +class Type{ +public: + enum BasicType{ + Integer, + String, + Klass + }; + static Type *getType(const std::string &tname){ + if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ + return &sStringType; + }else if (strcmp(tname.c_str(),"int")==0){ + return &sIntegerType; + }else{ + Type* ret; + string tmp=tname; + ssize_t pos; + + /*really ugly and slow*/ + + pos=tmp.find('*'); + if (pos!=string::npos) + tmp.erase(pos,1); + + pos=tmp.find("const"); + if (pos!=string::npos) + tmp.erase(pos,strlen("const")); + + while ((pos=tmp.find(' '))!=string::npos){ + tmp.erase(pos,1); + } + + if ((ret=mTypes[tmp])==0){ + cout<<"Adding new class type '"< mTypes; +}; + +Type Type::sStringType(Type::String); +Type Type::sIntegerType(Type::Integer); +std::map Type::mTypes; + +class Argument{ +public: + Argument(Type *type, const string &argname, bool isConst) : mType(type), mName(argname), mConst(isConst){ + } + Type *getType()const{ + return mType; + } +private: + bool mConst; + Type *mType; + string mName; + string mHelp; +}; + +class Method{ +public: + Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args){ + mUid=uid; + mReturn=return_arg; + mName=name; + mArgs=args; + } + void setHelp(const std::string &help){ + mHelp=help; + } +private: + string mUid; + Argument *mReturn; + string mName; + list mArgs; + string mHelp; +}; + +class Class{ +public: + Class(const std::string &name): mName(name){ + } + void addMethod(Method *method){ + mMethods.push_back(method); + } + void setHelp(const std::string &help){ + mHelp=help; + } +private: + list mMethods; + string mName; + string mHelp; +}; + +class Project{ +public: + Class *getClass(const std::string &name){ + Class *ret; + if ((ret=mClasses[name])==NULL){ + ret=mClasses[name]=new Class(name); + } + return ret; + } +private: + map mClasses; +}; + +static xmlNode * findChild(xmlNode *a_node, const char *element_name){ + xmlNode *cur_node; + + for (cur_node = a_node->children; cur_node != NULL ; cur_node = cur_node->next){ + if (strcmp((const char*)cur_node->name,(const char*)element_name)==0){ + return cur_node; + } + } + return NULL; +} + +static bool isSpace(const char *str){ + for(;*str!='\0';++str){ + if (!isspace(*str)) return false; + } + return true; +} + +static string findChildContent(xmlNode *a_node, const char *element_name){ + xmlNode *node=findChild(a_node,element_name); + string res; + if (node) { + xmlChar *text=xmlNodeGetContent(node); + if (!isSpace((const char*)text)) + res=(char*)text; + xmlFree(text); + } + return res; +} + +#define nullOrEmpty(p) (p==NULL || *p=='\0') + +static Argument *parseArgument(xmlNode *node){ + string name=findChildContent(node,"name"); + + xmlNode *typenode=findChild(node,"type"); + + if (!typenode) { + cout<<"Cannot find type from node."<0) + useUpper=true; + }else{ + if (useUpper) + *w++=toupper(p); + else + *w++=p; + useUpper=false; + } + } + *w++='\0'; + return tmp; +} + +static string extractMethodName(const string &c_name, const std::string& class_name){ + string prefix=classNameToPrefix(class_name); + if (c_name.find(prefix)==0){ + return makeMethodName(c_name.substr(prefix.size(),string::npos)); + } + return ""; +} + +static void parseFunction(Project *proj, xmlNode *node){ + string name; + Argument *first_arg=NULL; + xmlNode *cur_node; + string className; + string methodName; + + for (cur_node = node->children; cur_node != NULL ; cur_node = cur_node->next){ + if (strcmp((const char*)cur_node->name,"name")==0){ + xmlChar *content=xmlNodeGetContent(cur_node); + name=(const char*)content; + xmlFree(content); + }else if (strcmp((const char*)cur_node->name,"param")==0){ + if (first_arg==NULL){ + first_arg=parseArgument(cur_node); + } + } + } + if (!first_arg){ + cout<<"Could not determine first argument of "<getType()->getName(); + methodName=extractMethodName(name,className); + if (!methodName.empty()){ + cout<<"Found "<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, 0); + + if (doc == NULL) { + cerr<<"xmlReadFile failed."< Date: Tue, 17 Sep 2013 19:26:14 +0200 Subject: [PATCH 687/909] wrap new publishStateChanged callback to Java --- .../core/tutorials/TutorialBuddyStatus.java | 8 +++++ .../core/tutorials/TutorialChatRoom.java | 8 +++++ .../core/tutorials/TutorialHelloWorld.java | 8 +++++ .../core/tutorials/TutorialRegistration.java | 8 +++++ coreapi/linphonecore_jni.cc | 29 +++++++++++++++++++ .../linphone/core/LinphoneCoreListener.java | 7 +++++ 6 files changed, 68 insertions(+) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index af3c7c187..221867898 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -38,6 +38,7 @@ import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; import org.linphone.core.LinphoneFriend.SubscribePolicy; +import org.linphone.core.PublishState; import org.linphone.core.SubscriptionState; /** @@ -272,5 +273,12 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index e3594970b..371b9af8e 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -36,6 +36,7 @@ import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.PublishState; import org.linphone.core.SubscriptionState; @@ -194,5 +195,12 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index c624a9e83..e8ba341ad 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -36,6 +36,7 @@ import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.PublishState; import org.linphone.core.SubscriptionState; @@ -198,5 +199,12 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 685997f11..98b74656c 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -36,6 +36,7 @@ import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.PublishState; import org.linphone.core.SubscriptionState; @@ -229,6 +230,13 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 3b61d7438..0361809a1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -175,6 +175,7 @@ public: vTable.info_received = infoReceived; vTable.subscription_state_changed=subscriptionStateChanged; vTable.notify_received=notifyReceived; + vTable.publish_state_changed=publishStateChanged; listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); @@ -227,6 +228,8 @@ public: subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V"); + publishStateId = env->GetMethodID(listenerClass,"publishStateChanged", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/PublishState;)V"); notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V"); @@ -263,6 +266,9 @@ public: subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState")); subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;"); + publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState")); + publishStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;"); + subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); } @@ -303,6 +309,7 @@ public: jmethodID transferStateId; jmethodID infoReceivedId; jmethodID subscriptionStateId; + jmethodID publishStateId; jmethodID notifyRecvId; jclass globalStateClass; @@ -358,6 +365,9 @@ public: jclass subscriptionStateClass; jmethodID subscriptionStateFromIntId; + jclass publishStateClass; + jmethodID publishStateFromIntId; + jclass subscriptionDirClass; jmethodID subscriptionDirFromIntId; @@ -642,6 +652,25 @@ public: env->DeleteGlobalRef(jevent); } } + static void publishStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + jobject jstate; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->publishStateClass,lcData->publishStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->publishStateId + ,lcData->core + ,jevent + ,jstate + ); + } static void notifyReceived(LinphoneCore *lc, LinphoneEvent *ev, const char *evname, const LinphoneContent *content){ JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index af5b07b84..60e9e3d59 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -148,6 +148,13 @@ public interface LinphoneCoreListener { * @param content content of the NOTIFY request. */ void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content); + /** + * Notifies about outgoing generic publish states. + * @param lc the LinphoneCore + * @param ev a LinphoneEvent representing the publish, typically created by {@link LinphoneCore#publish} + * @param state the publish state + */ + void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state); /**< @Deprecated Notifies the application that it should show up * @return */ From 255eaef302646298a9790672264b51e3de17db5c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Sep 2013 19:27:11 +0200 Subject: [PATCH 688/909] add missing file --- .../org/linphone/core/PublishState.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 java/common/org/linphone/core/PublishState.java diff --git a/java/common/org/linphone/core/PublishState.java b/java/common/org/linphone/core/PublishState.java new file mode 100644 index 000000000..7dfe86e3e --- /dev/null +++ b/java/common/org/linphone/core/PublishState.java @@ -0,0 +1,45 @@ +package org.linphone.core; + +public enum PublishState { + /** + * Initial state, should not be used. + */ + None(0), + /** + * Publish is in progress. + */ + Progress(1), + /** + * Publish succeeded. + */ + Ok(2), + /** + * Publish encountered an error. {@link LinphoneEvent.getReason()} gives more information about failure. + */ + Error(3), + /** + * Publish is about to expire. Application can trigger a refresh by calling {@link LinphoneCore.updatePublish()} + */ + Expiring(4), + /** + * Publish is terminated cleared. + */ + Cleared(5); + + protected final int mValue; + private PublishState(int value){ + mValue=value; + } + static protected PublishState fromInt(int value) throws LinphoneCoreException{ + switch(value){ + case 0: return None; + case 1: return Progress; + case 2: return Ok; + case 3: return Error; + case 4: return Expiring; + case 5: return Cleared; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for PublishState"); + } + } +} From 40cb573eac5da648776728cc4136467c3818bc13 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 18 Sep 2013 11:16:28 +0200 Subject: [PATCH 689/909] add LinphoneProxyConfig.getError() java/jni --- coreapi/linphonecore_jni.cc | 4 ++++ java/common/org/linphone/core/LinphoneProxyConfig.java | 6 ++++++ java/impl/org/linphone/core/LinphoneProxyConfigImpl.java | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 0361809a1..4c34f9123 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1430,6 +1430,10 @@ extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_publishEnable return (jboolean)linphone_proxy_config_publish_enabled((LinphoneProxyConfig*)proxyCfg); } +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv* env,jobject thiz,jlong ptr) { + return linphone_proxy_config_get_error((LinphoneProxyConfig *) ptr); +} + //Auth Info extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index b6b8919fb..2db0756b6 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -151,4 +151,10 @@ public interface LinphoneProxyConfig { * @param e164 phone number */ public int lookupCCCFromE164(String e164); + + /** + * Return reason error code. + * @return reason code. + */ + public Reason getError(); } diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 649d46fe3..903d2a1c6 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -158,4 +158,9 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public int lookupCCCFromE164(String e164) { return lookupCCCFromE164(nativePtr, e164); } + private native int getReason(long nativeptr); + @Override + public Reason getError() { + return Reason.fromInt(getReason(nativePtr)); + } } From 5ec5f0285d4bc7fa93d951fd0efa9f2996459798 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 18 Sep 2013 12:08:29 +0200 Subject: [PATCH 690/909] fix bug in jni --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4c34f9123..dd34771b3 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -267,7 +267,7 @@ public: subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;"); publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState")); - publishStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;"); + publishStateFromIntId = env->GetStaticMethodID(publishStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;"); subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); From 2da7c76b3628a21a3d33403dea0e3a0ec5e32e46 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Sep 2013 13:14:22 +0200 Subject: [PATCH 691/909] Complete presence API to handle presence persons. --- coreapi/linphonepresence.h | 139 +++++++++++++++++++++++++++++++++++- coreapi/presence.c | 140 ++++++++++++++++++++++++++++++++----- 2 files changed, 261 insertions(+), 18 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index b4cef5252..ede8e9358 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -382,6 +382,36 @@ LINPHONE_PUBLIC int linphone_presence_model_add_service(LinphonePresenceModel *m */ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel *model); +/** + * @brief 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_nb_persons(const LinphonePresenceModel *model); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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 * @@ -398,6 +428,23 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel */ LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus, const char *contact); +/** + * @brief 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); + +/** + * @brief 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); + /** * @brief Gets the basic status of a presence service. * @param[in] service The #LinphonePresenceService object to get the basic status from. @@ -423,14 +470,74 @@ LINPHONE_PUBLIC int linphone_presence_service_set_basic_status(LinphonePresenceS LINPHONE_PUBLIC char * linphone_presence_service_get_contact(const LinphonePresenceService *service); /** - * @brief Sets the contact of a presence model. - * @param[in] model The #LinphonePresenceModel object for which to set the contact. + * @brief 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); +/***************************************************************************** + * PRESENCE PERSON FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * @brief Creates a presence person. + * @param[in] id The id of the presence person to be created. Can be NULL to generate it automatically. + * @returns The created presence person, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_new(const char *id); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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_nb_activities(const LinphonePresencePerson *person); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + + + /***************************************************************************** * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ @@ -562,6 +669,34 @@ void linphone_presence_service_set_user_data(LinphonePresenceService *service, v */ void * linphone_presence_service_get_user_data(LinphonePresenceService *service); +/** + * Increase the reference count of the #LinphonePresencePerson object. + * @param[in] person The #LinphonePresencePerson object for which the reference count is to be increased. + * @return The #LinphonePresencePerson object with the increased reference count. + */ +LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person); + +/** + * Decrease the reference count of the #LinphonePresencePerson object and destroy it if it reaches 0. + * @param[in] person The #LinphonePresencePerson object for which the reference count is to be decreased. + * @return The #LinphonePresencePerson object if the reference count is still positive, NULL if the object has been destroyed. + */ +LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person); + +/** + * Sets the user data of a #LinphonePresencePerson object. + * @param[in] person The #LinphonePresencePerson object for which to set the user data. + * @param[in] user_data A pointer to the user data to set. + */ +void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data); + +/** + * Gets the user data of a #LinphonePresencePerson object. + * @param[in] person The #LinphonePresencePerson object for which to get the user data. + * @return A pointer to the user data. + */ +void * linphone_presence_person_get_user_data(LinphonePresencePerson *person); + /** * Increase the reference count of the #LinphonePresenceActivity object. * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be increased. diff --git a/coreapi/presence.c b/coreapi/presence.c index 314946c4f..ef6af42d1 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -62,6 +62,8 @@ struct _LinphonePresenceActivity { }; struct _LinphonePresencePerson { + void *user_data; + int refcnt; char *id; MSList *activities; /**< A list of _LinphonePresenceActivity structures. */ MSList *activities_notes; /**< A list of _LinphonePresenceNote structures. */ @@ -249,6 +251,7 @@ static char * timestamp_to_string(time_t timestamp) { 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); } @@ -272,10 +275,6 @@ static void presence_person_delete(LinphonePresencePerson *person) { ms_free(person); } -static void presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) { - person->activities = ms_list_append(person->activities, activity); -} - static void presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { person->activities_notes = ms_list_append(person->activities_notes, note); } @@ -284,12 +283,6 @@ static void presence_person_add_note(LinphonePresencePerson *person, LinphonePre person->notes = ms_list_append(person->notes, note); } -static void presence_person_clear_activities(LinphonePresencePerson *person) { - ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); - ms_list_free(person->activities); - person->activities = NULL; -} - static void presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { model->persons = ms_list_append(model->persons, person); } @@ -309,7 +302,7 @@ static void presence_model_delete(LinphonePresenceModel *model) { ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref); ms_list_free(model->services); - ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); + 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); @@ -498,14 +491,14 @@ int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphoneP person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); } - presence_person_add_activity(person, activity); + 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)presence_person_clear_activities); + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_clear_activities); return 0; } @@ -701,6 +694,32 @@ int linphone_presence_model_clear_services(LinphonePresenceModel *model) { return 0; } +unsigned int linphone_presence_model_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_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, 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; +} + /***************************************************************************** @@ -721,6 +740,22 @@ LinphonePresenceService * linphone_presence_service_new(const char *id, Linphone 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; @@ -750,6 +785,57 @@ int linphone_presence_service_set_contact(LinphonePresenceService *service, cons +/***************************************************************************** + * 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_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_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, 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; +} + + + /***************************************************************************** * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ @@ -934,6 +1020,28 @@ void * linphone_presence_service_get_user_data(LinphonePresenceService *service) return service->user_data; } +LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person) { + person->refcnt++; + return person; +} + +LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person) { + person->refcnt--; + if (person->refcnt == 0) { + presence_person_delete(person); + return NULL; + } + return person; +} + +void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data) { + person->user_data = user_data; +} + +void * linphone_presence_person_get_user_data(LinphonePresencePerson *person) { + return person->user_data; +} + LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity) { activity->refcnt++; return activity; @@ -1152,7 +1260,7 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); if (err < 0) break; activity = linphone_presence_activity_new(acttype, description); - presence_person_add_activity(person, activity); + linphone_presence_person_add_activity(person, activity); if (description != NULL) free_xml_text_content(description); } } @@ -1243,7 +1351,7 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp if (err == 0) { presence_model_add_person(model, person); } else { - presence_person_delete(person); + linphone_presence_person_unref(person); break; } } @@ -1255,7 +1363,7 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp if (err < 0) { /* Remove all the persons added since there was an error. */ - ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete); + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref); } return err; } From 77b1aff186c656672a9324869b923f24871c873b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Sep 2013 14:21:44 +0200 Subject: [PATCH 692/909] Complete presence API to have access to the notes of presence services and persons. --- coreapi/linphonepresence.h | 89 ++++++++++++++++++++++++++++++++++++++ coreapi/presence.c | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index ede8e9358..763cc0cd8 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -477,6 +477,36 @@ LINPHONE_PUBLIC char * linphone_presence_service_get_contact(const LinphonePrese */ LINPHONE_PUBLIC int linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact); +/** + * @brief 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_nb_notes(const LinphonePresenceService *service); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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 * @@ -536,6 +566,65 @@ LINPHONE_PUBLIC int linphone_presence_person_add_activity(LinphonePresencePerson */ LINPHONE_PUBLIC int linphone_presence_person_clear_activities(LinphonePresencePerson *person); +/** + * @brief 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_nb_notes(const LinphonePresencePerson *person); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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_nb_activities_notes(const LinphonePresencePerson *person); + +/** + * @brief 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); + +/** + * @brief 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); + +/** + * @brief 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_activites_notes(LinphonePresencePerson *person); /***************************************************************************** diff --git a/coreapi/presence.c b/coreapi/presence.c index ef6af42d1..b4f057826 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -783,6 +783,32 @@ int linphone_presence_service_set_contact(LinphonePresenceService *service, cons return 0; } +unsigned int linphone_presence_service_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_nb_notes(service))) + return NULL; + + return (LinphonePresenceNote *)ms_list_nth_data(service->notes, idx); +} + +int linphone_presence_service_add_person(LinphonePresenceService *service, LinphonePresenceNote *note) { + if ((service == NULL) || (note == NULL)) return -1; + service->notes = ms_list_append(service->notes, 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; +} + /***************************************************************************** @@ -834,6 +860,55 @@ int linphone_presence_person_clear_activities(LinphonePresencePerson *person) { return 0; } +unsigned int linphone_presence_person_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_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, 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_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_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, 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; +} /***************************************************************************** From 879bb3f619d2368e26249ab9da356e827e35d17e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Sep 2013 16:03:21 +0200 Subject: [PATCH 693/909] Fix typos. --- coreapi/linphonepresence.h | 2 +- coreapi/presence.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 763cc0cd8..24e91fd74 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -624,7 +624,7 @@ LINPHONE_PUBLIC int linphone_presence_person_add_activities_note(LinphonePresenc * @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_activites_notes(LinphonePresencePerson *person); +LINPHONE_PUBLIC int linphone_presence_person_clear_activities_notes(LinphonePresencePerson *person); /***************************************************************************** diff --git a/coreapi/presence.c b/coreapi/presence.c index b4f057826..2d23198c6 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -794,7 +794,7 @@ LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePres return (LinphonePresenceNote *)ms_list_nth_data(service->notes, idx); } -int linphone_presence_service_add_person(LinphonePresenceService *service, LinphonePresenceNote *note) { +int linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { if ((service == NULL) || (note == NULL)) return -1; service->notes = ms_list_append(service->notes, note); return 0; From c7ba1b8ee153b95309513acecefc12e3cd93ae30 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Sep 2013 16:04:09 +0200 Subject: [PATCH 694/909] Update JNI according to latest presence API changes. --- coreapi/linphonecore_jni.cc | 274 ++++++++++++++++++ .../org/linphone/core/PresenceModel.java | 26 ++ .../org/linphone/core/PresencePerson.java | 120 ++++++++ .../org/linphone/core/PresenceService.java | 41 ++- .../org/linphone/core/PresenceModelImpl.java | 24 ++ .../org/linphone/core/PresencePersonImpl.java | 126 ++++++++ .../linphone/core/PresenceServiceImpl.java | 36 +++ 7 files changed, 646 insertions(+), 1 deletion(-) create mode 100644 java/common/org/linphone/core/PresencePerson.java create mode 100644 java/impl/org/linphone/core/PresencePersonImpl.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index dd34771b3..b116efe46 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3572,6 +3572,47 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearServices(JN return (jint)linphone_presence_model_clear_services(model); } +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: nbPersons + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbPersons(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_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 @@ -3676,6 +3717,29 @@ JNIEXPORT void JNICALL Java_org_linphone_core_PresenceServiceImpl_unref(JNIEnv * 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; + const char *cid = linphone_presence_service_get_id(service); + return cid ? env->NewStringUTF(cid) : NULL; +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: setId + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setId(JNIEnv *env, jobject jobj, jlong ptr, jstring id) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + linphone_presence_service_set_id(service, cid); + if (cid) env->ReleaseStringUTFChars(id, cid); +} + /* * Class: org_linphone_core_PresenceServiceImpl * Method: getBasicStatus @@ -3719,6 +3783,216 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setContact(JNI if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); } +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: nbNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_nbNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jlong)linphone_presence_service_nb_notes(service); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getNthNote + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceServiceImpl_getNthNote(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + LinphonePresenceNote *note = linphone_presence_service_get_nth_note(service, (unsigned int)idx); + if (note == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceNoteImpl", linphone_presence_note, note) +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: addNote + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_addNote(JNIEnv *env, jobject jobj, jlong ptr, jlong notePtr) { + return (jint)linphone_presence_service_add_note((LinphonePresenceService *)ptr, (LinphonePresenceNote *)notePtr); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: clearNotes + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_clearNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jint)linphone_presence_service_clear_notes(service); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: newPresencePersonImpl + * Signature: (Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_newPresencePersonImpl(JNIEnv *env, jobject jobj, jstring id) { + LinphonePresencePerson *person; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + person = linphone_presence_person_new(cid); + if (cid) env->ReleaseStringUTFChars(id, cid); + return (jlong)person; +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresencePersonImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + linphone_presence_person_unref(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getId + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresencePersonImpl_getId(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + const char *cid = linphone_presence_person_get_id(person); + return cid ? env->NewStringUTF(cid) : NULL; +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: setId + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_setId(JNIEnv *env, jobject jobj, jlong ptr, jstring id) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + linphone_presence_person_set_id(person, cid); + if (cid) env->ReleaseStringUTFChars(id, cid); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: nbActivities + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_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: nbNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_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: nbActivitiesNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbActivitiesNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_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: unref diff --git a/java/common/org/linphone/core/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java index 44f232c77..b225e6606 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -144,4 +144,30 @@ public interface PresenceModel { */ int clearServices(); + /** + * @brief Gets the number of persons included in the presence model. + * @return The number of persons included in the #PresenceModel object. + */ + long nbPersons(); + + /** + * @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/PresencePerson.java b/java/common/org/linphone/core/PresencePerson.java new file mode 100644 index 000000000..0e9822a60 --- /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 nbActivities(); + + /** + * @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 nbNotes(); + + /** + * @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 nbActivitiesNotes(); + + /** + * @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 index 779073476..082f7d5fd 100644 --- a/java/common/org/linphone/core/PresenceService.java +++ b/java/common/org/linphone/core/PresenceService.java @@ -21,6 +21,19 @@ 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. @@ -41,12 +54,38 @@ public interface PresenceService { String getContact(); /** - * @brief Sets the contact of a presence model. + * @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 nbNotes(); + + /** + * @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. */ diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java index 7250fe3ac..30cc4751e 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -154,6 +154,30 @@ public class PresenceModelImpl implements PresenceModel { return clearServices(mNativePtr); } + private native long nbPersons(long nativePtr); + @Override + public long nbPersons() { + return nbPersons(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/PresencePersonImpl.java b/java/impl/org/linphone/core/PresencePersonImpl.java new file mode 100644 index 000000000..ab4d85ceb --- /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 nbActivities(long nativePtr); + @Override + public long nbActivities() { + return nbActivities(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 nbNotes(long nativePtr); + @Override + public long nbNotes() { + return nbNotes(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 nbActivitiesNotes(long nativePtr); + @Override + public long nbActivitiesNotes() { + return nbActivitiesNotes(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 index a3c53a890..bbca443ab 100644 --- a/java/impl/org/linphone/core/PresenceServiceImpl.java +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -36,6 +36,18 @@ public class PresenceServiceImpl implements PresenceService { 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() { @@ -60,6 +72,30 @@ public class PresenceServiceImpl implements PresenceService { return setContact(mNativePtr, contact); } + private native long nbNotes(long nativePtr); + @Override + public long nbNotes() { + return nbNotes(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; } From 43186ab4c9e39cefc550bd43329fc9ce765d14ec Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Sep 2013 16:09:56 +0200 Subject: [PATCH 695/909] Fix memory leaks. --- coreapi/linphonecore_jni.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b116efe46..d1fb06674 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3724,8 +3724,10 @@ JNIEXPORT void JNICALL Java_org_linphone_core_PresenceServiceImpl_unref(JNIEnv * */ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceServiceImpl_getId(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceService *service = (LinphonePresenceService *)ptr; - const char *cid = linphone_presence_service_get_id(service); - return cid ? env->NewStringUTF(cid) : NULL; + char *cid = linphone_presence_service_get_id(service); + jstring jid = cid ? env->NewStringUTF(cid) : NULL; + if (cid) ms_free(cid); + return jid; } /* @@ -3767,8 +3769,10 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setBasicStatus */ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceServiceImpl_getContact(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceService *service = (LinphonePresenceService *)ptr; - const char *ccontact = linphone_presence_service_get_contact(service); - return ccontact ? env->NewStringUTF(ccontact) : NULL; + char *ccontact = linphone_presence_service_get_contact(service); + jstring jcontact = ccontact ? env->NewStringUTF(ccontact) : NULL; + if (ccontact) ms_free(ccontact); + return jcontact; } /* @@ -3854,8 +3858,10 @@ JNIEXPORT void JNICALL Java_org_linphone_core_PresencePersonImpl_unref(JNIEnv *e */ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresencePersonImpl_getId(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; - const char *cid = linphone_presence_person_get_id(person); - return cid ? env->NewStringUTF(cid) : NULL; + char *cid = linphone_presence_person_get_id(person); + jstring jid = cid ? env->NewStringUTF(cid) : NULL; + if (cid) ms_free(cid); + return jid; } /* From 20dfd43aac43ed8a3cd966c8d0db57c3be8d2be8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 11:15:29 +0200 Subject: [PATCH 696/909] More coherent friend API. --- console/commands.c | 4 ++-- coreapi/friend.c | 8 ++++---- coreapi/help/buddy_status.c | 2 +- coreapi/linphonecore_jni.cc | 4 ++-- coreapi/linphonefriend.h | 14 ++++++++++++-- coreapi/presence.c | 8 ++++---- coreapi/private.h | 4 +--- gtk/buddylookup.c | 2 +- gtk/calllogs.c | 2 +- gtk/chat.c | 4 ++-- gtk/friendlist.c | 4 ++-- tester/presence_tester.c | 4 ++-- 12 files changed, 34 insertions(+), 26 deletions(-) diff --git a/console/commands.c b/console/commands.c index 67b2446f4..1e893619d 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1022,7 +1022,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) linphonec_friend_add(lc, name, addr); #else LinphoneFriend *new_friend; - new_friend = linphone_friend_new_with_addr(args); + new_friend = linphone_friend_new_with_address(args); linphone_core_add_friend(lc, new_friend); #endif return 1; @@ -1852,7 +1852,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; } diff --git a/coreapi/friend.c b/coreapi/friend.c index f5b6f626c..7626617ba 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -78,7 +78,7 @@ static int friend_compare(const void * a, const void * b){ } -MSList *linphone_find_friend_by_addr(MSList *fl, const LinphoneAddress *addr, 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; @@ -145,7 +145,7 @@ LinphoneFriend * linphone_friend_new(){ 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; @@ -154,7 +154,7 @@ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ return NULL; } fr=linphone_friend_new(); - linphone_friend_set_addr(fr,linphone_address); + linphone_friend_set_address(fr,linphone_address); linphone_address_destroy(linphone_address); return fr; } @@ -605,7 +605,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde if (tmp==NULL) { return NULL; } - lf=linphone_friend_new_with_addr(tmp); + lf=linphone_friend_new_with_address(tmp); if (lf==NULL) { return NULL; } diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 5e073d75a..bcd71b99f 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -155,7 +155,7 @@ int main(int argc, char *argv[]){ LinphoneFriend* my_friend=NULL; if (dest_friend) { - my_friend = linphone_friend_new_with_addr(dest_friend); /*creates friend object from dest*/ + my_friend = linphone_friend_new_with_address(dest_friend); /*creates friend object from dest*/ if (my_friend == NULL) { printf("bad destination uri for friend [%s]\n",dest_friend); goto end; diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d1fb06674..44f94935a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2042,7 +2042,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNI if (jFriendUri) { const char* friendUri = env->GetStringUTFChars(jFriendUri, NULL); - lResult= linphone_friend_new_with_addr(friendUri); + lResult= linphone_friend_new_with_address(friendUri); env->ReleaseStringUTFChars(jFriendUri, friendUri); } else { lResult = linphone_friend_new(); @@ -2053,7 +2053,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 diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index cd74a10c6..fd896ac3f 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -121,12 +121,19 @@ typedef struct _LinphoneFriend LinphoneFriend; * @return a new empty #LinphoneFriend */ LINPHONE_PUBLIC LinphoneFriend * linphone_friend_new(); + /** - * Contructor same as linphone_friend_new() + linphone_friend_set_addr() + * Contructor same as linphone_friend_new() + linphone_friend_set_address() * @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink */ -LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_addr(const char *addr); +LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_address(const char *addr); + +/** + * Contructor same as linphone_friend_new() + linphone_friend_set_address() + * @deprecated Use #linphone_friend_new_with_address instead + */ +#define linphone_friend_new_with_addr linphone_friend_new_with_address /** * Destructor @@ -289,6 +296,9 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_core_get_presence_info(const Linph */ 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); /** diff --git a/coreapi/presence.c b/coreapi/presence.c index 2d23198c6..20a0ead0e 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1502,7 +1502,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){ - LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber); + LinphoneFriend *fl=linphone_friend_new_with_address(subscriber); if (fl==NULL) return ; fl->insub=op; linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept); @@ -1555,14 +1555,14 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ } /* check if we answer to this subscription */ - if (linphone_find_friend_by_addr(lc->friends,uri,&lf)!=NULL){ + if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){ lf->insub=op; lf->inc_subscribe_pending=TRUE; sal_subscribe_accept(op); linphone_friend_done(lf); /*this will do all necessary actions */ }else{ /* check if this subscriber is in our black list */ - if (linphone_find_friend_by_addr(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,SalReasonDeclined); @@ -1926,7 +1926,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa 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_addr(lc->friends,(LinphoneAddress*)addr,&lf); + linphone_find_friend_by_address(lc->friends,(LinphoneAddress*)addr,&lf); } if (lf!=NULL){ LinphonePresenceActivity *activity = NULL; diff --git a/coreapi/private.h b/coreapi/private.h index 4cead54df..2d817f6bb 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -253,7 +253,7 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf); void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence); LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); -MSList *linphone_find_friend_by_addr(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); +MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen); int set_lock_file(); @@ -303,8 +303,6 @@ void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalO void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); -MSList *linphone_find_friend_by_addr(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); diff --git a/gtk/buddylookup.c b/gtk/buddylookup.c index 55c3f334e..4a6cb8d7a 100644 --- a/gtk/buddylookup.c +++ b/gtk/buddylookup.c @@ -287,7 +287,7 @@ void linphone_gtk_add_buddy_from_database(GtkWidget *button){ gtk_tree_model_get (model, &iter,LOOKUP_RESULT_SIP_URI , &uri,LOOKUP_RESULT_NAME, &name, -1); addr=g_strdup_printf("%s <%s>",name,uri); - lf=linphone_friend_new_with_addr(addr); + lf=linphone_friend_new_with_address(addr); linphone_friend_set_inc_subscribe_policy(lf,presence ? LinphoneSPAccept : LinphoneSPDeny); linphone_friend_send_subscribe(lf,presence); linphone_core_add_friend(linphone_gtk_get_core(),lf); diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 466541006..e9b460636 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -82,7 +82,7 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){ la=(LinphoneAddress*)pla; if (la!=NULL){ char *uri=linphone_address_as_string(la); - lf=linphone_friend_new_with_addr(uri); + lf=linphone_friend_new_with_address(uri); linphone_gtk_show_contact(lf); ms_free(uri); } diff --git a/gtk/chat.c b/gtk/chat.c index 40ad17252..25e1c0d75 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -335,7 +335,7 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ LinphoneFriend *lf=NULL; char *uri=linphone_address_as_string(addr); - lf=linphone_friend_new_with_addr(uri); + lf=linphone_friend_new_with_address(uri); ms_free(uri); char *fixed_uri=NULL; gboolean show_presence=FALSE; @@ -348,7 +348,7 @@ void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - linphone_friend_set_addr(lf,addr); + linphone_friend_set_address(lf,addr); linphone_core_add_friend(linphone_gtk_get_core(),lf); ms_free(fixed_uri); linphone_gtk_show_friends(); diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 12da891f4..2eedd5b54 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -450,7 +450,7 @@ static void icon_press_handler(GtkEntry *entry){ } lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); if (lf==NULL) - lf=linphone_friend_new_with_addr(uri); + lf=linphone_friend_new_with_address(uri); if (lf!=NULL){ linphone_gtk_show_contact(lf); } @@ -886,7 +886,7 @@ void linphone_gtk_contact_ok(GtkWidget *button){ } friend_address = linphone_address_new(fixed_uri); linphone_address_set_display_name(friend_address,name); - linphone_friend_set_addr(lf,friend_address); + linphone_friend_set_address(lf,friend_address); linphone_address_destroy(friend_address); linphone_friend_send_subscribe(lf,show_presence); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index cc95d6c8a..688a8b5fc 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -146,7 +146,7 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph char* identity=linphone_address_as_string_uri_only(callee_mgr->identity); - LinphoneFriend* friend=linphone_friend_new_with_addr(identity); + LinphoneFriend* friend=linphone_friend_new_with_address(identity); linphone_friend_edit(friend); linphone_friend_enable_subscribes(friend,TRUE); linphone_friend_done(friend); @@ -211,7 +211,7 @@ static void simple_subscribe(void) { static void unsubscribe_while_subscribing(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneFriend* friend = linphone_friend_new_with_addr("sip:toto@git.linphone.org"); /*any unexisting address*/ + 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); From 1c604269a5dba8d7d3081c302ab1be60a61977ce Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 11:41:52 +0200 Subject: [PATCH 697/909] Use linphone_core_interpret_url() instead of linphone_core_interpret_friend_uri(). --- gtk/chat.c | 9 +++++---- gtk/friendlist.c | 34 +++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index 25e1c0d75..b1d0ec320 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -334,23 +334,24 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ LinphoneFriend *lf=NULL; + LinphoneAddress *fixed_uri=NULL; + gboolean show_presence=FALSE; char *uri=linphone_address_as_string(addr); + lf=linphone_friend_new_with_address(uri); ms_free(uri); - char *fixed_uri=NULL; - gboolean show_presence=FALSE; linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); linphone_friend_send_subscribe(lf,show_presence); - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),uri,&fixed_uri); + fixed_uri = linphone_core_interpret_url(linphone_gtk_get_core(),uri); if (fixed_uri==NULL){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } linphone_friend_set_address(lf,addr); linphone_core_add_friend(linphone_gtk_get_core(),lf); - ms_free(fixed_uri); + linphone_address_destroy(fixed_uri); linphone_gtk_show_friends(); } diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 2eedd5b54..ddf324734 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -442,19 +442,23 @@ void linphone_gtk_my_presence_clicked(GtkWidget *button){ static void icon_press_handler(GtkEntry *entry){ const char *text=gtk_entry_get_text(entry); if (text && strlen(text)>0){ - char *uri; + LinphoneAddress *addr; LinphoneFriend *lf; - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),text,&uri); - if (uri==NULL){ + char *uri; + addr=linphone_core_interpret_url(linphone_gtk_get_core(),text); + if (addr==NULL){ return ; } + uri=linphone_address_as_string_uri_only(addr); lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); + ms_free(uri); if (lf==NULL) - lf=linphone_friend_new_with_address(uri); + lf=linphone_friend_new(); if (lf!=NULL){ + linphone_friend_set_address(lf,addr); linphone_gtk_show_contact(lf); } - ms_free(uri); + linphone_address_destroy(addr); } } @@ -476,11 +480,12 @@ static void check_contact(GtkEditable *editable, LinphoneCore *lc){ char *tmp=gtk_editable_get_chars(editable,0,-1); if (tmp!=NULL){ if (strlen(tmp)>0){ - char *uri=NULL; - linphone_core_interpret_friend_uri(lc,tmp,&uri); - if (uri){ + LinphoneAddress *addr=linphone_core_interpret_url(lc,tmp); + if (addr){ + char *uri=linphone_address_as_string_uri_only(addr); LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,uri); ms_free(uri); + linphone_address_destroy(addr); if (lf) { update_star(GTK_ENTRY(editable),TRUE); g_free(tmp); @@ -862,7 +867,6 @@ void linphone_gtk_contact_ok(GtkWidget *button){ GtkWidget *w=gtk_widget_get_toplevel(button); LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(w),"friend_ref"); LinphoneFriend *lf2; - char *fixed_uri=NULL; gboolean show_presence=FALSE,allow_presence=FALSE; const gchar *name,*uri; LinphoneAddress* friend_address; @@ -879,28 +883,28 @@ void linphone_gtk_contact_ok(GtkWidget *button){ uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address"))); show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence"))); allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence"))); - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),uri,&fixed_uri); - if (fixed_uri==NULL){ + friend_address=linphone_core_interpret_url(linphone_gtk_get_core(),uri); + if (friend_address==NULL){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - friend_address = linphone_address_new(fixed_uri); linphone_address_set_display_name(friend_address,name); linphone_friend_set_address(lf,friend_address); - linphone_address_destroy(friend_address); linphone_friend_send_subscribe(lf,show_presence); linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny); if (linphone_friend_in_list(lf)) { linphone_friend_done(lf); } else { - lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),fixed_uri); + char *uri=linphone_address_as_string_uri_only(friend_address); + lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); + ms_free(uri); if(lf2==NULL){ linphone_friend_set_name(lf,name); linphone_core_add_friend(linphone_gtk_get_core(),lf); } } - ms_free(fixed_uri); + linphone_address_destroy(friend_address); linphone_gtk_show_friends(); gtk_widget_destroy(w); } From 0dec8ef3e86f877b659e215c0cb8b673056ea659 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 11:53:48 +0200 Subject: [PATCH 698/909] Add missing presence note API. --- coreapi/linphonepresence.h | 24 +++++++++++++++ coreapi/presence.c | 62 ++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 24e91fd74..121dc472e 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -683,6 +683,14 @@ LINPHONE_PUBLIC int linphone_presence_activity_set_description(LinphonePresenceA * PRESENCE NOTE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * ****************************************************************************/ +/** + * @brief Creates a presence note. + * @param[in] content The content of the note to be created. + * @param[in] lang The language of the note to be created. Can be NULL if no language is to be specified for the note. + * @returns The created presence note, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_new(const char *content, const char *lang); + /** * @brief Gets the content of a presence note. * @param[in] note A pointer to the #LinphonePresenceNote for which to get the content. @@ -690,6 +698,14 @@ LINPHONE_PUBLIC int linphone_presence_activity_set_description(LinphonePresenceA */ LINPHONE_PUBLIC const char * linphone_presence_note_get_content(const LinphonePresenceNote *note); +/** + * @brief 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); + /** * @brief Gets the language of a presence note. * @param[in] note A pointer to the #LinphonePresenceNote for which to get the language. @@ -697,6 +713,14 @@ LINPHONE_PUBLIC const char * linphone_presence_note_get_content(const LinphonePr */ LINPHONE_PUBLIC const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note); +/** + * @brief 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 * diff --git a/coreapi/presence.c b/coreapi/presence.c index 20a0ead0e..877a1e3e7 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -154,16 +154,6 @@ static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus } } -static LinphonePresenceNote * presence_note_new(const char *content, const char *lang) { - LinphonePresenceNote * note = ms_new0(LinphonePresenceNote, 1); - note->refcnt = 1; - note->content = ms_strdup(content); - if (lang != NULL) { - note->lang = ms_strdup(lang); - } - return note; -} - static void presence_note_delete(LinphonePresenceNote *note) { ms_free(note->content); if (note->lang != NULL) { @@ -172,13 +162,6 @@ static void presence_note_delete(LinphonePresenceNote *note) { ms_free(note); } -static void presence_note_set_content(LinphonePresenceNote *note, const char *content) { - if (note->content != NULL) { - ms_free(note->content); - } - note->content = ms_strdup(content); -} - static LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) { LinphonePresenceService *service = ms_new0(LinphonePresenceService, 1); service->refcnt = 1; @@ -618,9 +601,9 @@ int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *n /* Search for an existing note in the specified language. */ note = find_presence_note_in_list(service->notes, lang); if (note == NULL) { - note = presence_note_new(note_content, lang); + note = linphone_presence_note_new(note_content, lang); } else { - presence_note_set_content(note, note_content); + linphone_presence_note_set_content(note, note_content); } if (note == NULL) return -1; @@ -1033,18 +1016,51 @@ int linphone_presence_activity_set_description(LinphonePresenceActivity *activit * 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; +} + /***************************************************************************** @@ -1226,7 +1242,7 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i); lang = get_xml_text_content(xml_ctx, xpath_str); - note = presence_note_new(note_str, lang); + note = linphone_presence_note_new(note_str, lang); presence_service_add_note(service, note); if (lang != NULL) free_xml_text_content(lang); free_xml_text_content(note_str); @@ -1367,7 +1383,7 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); lang = get_xml_text_content(xml_ctx, xpath_str); - note = presence_note_new(note_str, lang); + note = linphone_presence_note_new(note_str, lang); presence_person_add_activities_note(person, note); if (lang != NULL) free_xml_text_content(lang); free_xml_text_content(note_str); @@ -1385,7 +1401,7 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i); lang = get_xml_text_content(xml_ctx, xpath_str); - note = presence_note_new(note_str, lang); + note = linphone_presence_note_new(note_str, lang); presence_person_add_note(person, note); if (lang != NULL) free_xml_text_content(lang); free_xml_text_content(note_str); @@ -1460,7 +1476,7 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i); lang = get_xml_text_content(xml_ctx, xpath_str); - note = presence_note_new(note_str, lang); + note = linphone_presence_note_new(note_str, lang); presence_model_add_note(model, note); if (lang != NULL) free_xml_text_content(lang); free_xml_text_content(note_str); From b1ab2d9ed0013637bdcfe10a9d89341ec54c01fb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 12:14:50 +0200 Subject: [PATCH 699/909] Update JNI according to latest presence API changes. --- coreapi/linphonecore_jni.cc | 39 +++++++++++++++++++ .../org/linphone/core/PresenceNote.java | 14 +++++++ .../org/linphone/core/PresenceNoteImpl.java | 17 ++++++++ 3 files changed, 70 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 44f94935a..b243d25d9 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3999,6 +3999,21 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearActivitesN return (jint)linphone_presence_person_clear_activities_notes(person); } +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: newPresenceNoteImpl + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceNoteImpl_newPresenceNoteImpl(JNIEnv *env, jobject jobj, jstring content, jstring lang) { + LinphonePresenceNote *note; + const char *ccontent = content ? env->GetStringUTFChars(content, NULL) : NULL; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + note = linphone_presence_note_new(ccontent, clang); + if (clang) env->ReleaseStringUTFChars(lang, clang); + if (ccontent) env->ReleaseStringUTFChars(content, ccontent); + return (jlong)note; +} + /* * Class: org_linphone_core_PresenceNoteImpl * Method: unref @@ -4020,6 +4035,18 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceNoteImpl_getContent(JNI return ccontent ? env->NewStringUTF(ccontent) : NULL; } +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: setContent + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceNoteImpl_setContent(JNIEnv *env, jobject jobj, jlong ptr, jstring content) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *ccontent = content ? env->GetStringUTFChars(content, NULL) : NULL; + linphone_presence_note_set_content(note, ccontent); + if (ccontent) env->ReleaseStringUTFChars(content, ccontent); +} + /* * Class: org_linphone_core_PresenceNoteImpl * Method: getLang @@ -4031,6 +4058,18 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceNoteImpl_getLang(JNIEnv return clang ? env->NewStringUTF(clang) : NULL; } +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: setLang + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceNoteImpl_setLang(JNIEnv *env, jobject jobj, jlong ptr, jstring lang) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + linphone_presence_note_set_lang(note, clang); + if (clang) env->ReleaseStringUTFChars(lang, clang); +} + /* * Class: org_linphone_core_PayloadTypeImpl * Method: setRecvFmtp diff --git a/java/common/org/linphone/core/PresenceNote.java b/java/common/org/linphone/core/PresenceNote.java index 638985fc1..9353d9de4 100644 --- a/java/common/org/linphone/core/PresenceNote.java +++ b/java/common/org/linphone/core/PresenceNote.java @@ -27,12 +27,26 @@ public interface PresenceNote { */ 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. */ diff --git a/java/impl/org/linphone/core/PresenceNoteImpl.java b/java/impl/org/linphone/core/PresenceNoteImpl.java index c5857eec5..113519c7f 100644 --- a/java/impl/org/linphone/core/PresenceNoteImpl.java +++ b/java/impl/org/linphone/core/PresenceNoteImpl.java @@ -26,6 +26,11 @@ public class PresenceNoteImpl implements PresenceNote { 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); @@ -37,12 +42,24 @@ public class PresenceNoteImpl implements PresenceNote { 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; } From b3a6fd3619f61ce8ce8b23e5b6be2e4b7019f061 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 15:57:00 +0200 Subject: [PATCH 700/909] Fix wrong documentation. --- coreapi/linphonefriend.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index fd896ac3f..6b07069f6 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -331,7 +331,7 @@ LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore /** * notify all friends that have subscribed * @param lc #LinphoneCore object - * @param os #LinphoneOnlineStatus to notify + * @param presence #LinphonePresenceModel to notify * */ LINPHONE_PUBLIC void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); From ae764ae9529e647db856a8660a791a5bd2a61364 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Sep 2013 16:12:40 +0200 Subject: [PATCH 701/909] Always use int values for getter/setter of LinphoneAddress port. --- coreapi/address.c | 25 ++++++++++++------------- coreapi/bellesip_sal/sal_address_impl.c | 12 ++---------- coreapi/bellesip_sal/sal_impl.c | 4 ++-- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 6 +++++- coreapi/linphonecore.h | 12 +++--------- coreapi/proxy.c | 2 +- gtk/propertybox.c | 2 +- include/sal/sal.h | 8 ++++++++ tester/register_tester.c | 2 +- 11 files changed, 37 insertions(+), 40 deletions(-) diff --git a/coreapi/address.c b/coreapi/address.c index 4151765e4..7f1971abe 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -106,18 +106,16 @@ 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){ +void linphone_address_set_port(LinphoneAddress *uri, int port){ +#ifdef USE_BELLESIP + sal_address_set_port(uri,port); +#else sal_address_set_port_int(uri,port); +#endif } /** @@ -159,8 +157,8 @@ 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; @@ -173,12 +171,13 @@ void linphone_address_destroy(LinphoneAddress *u){ sal_address_unref(u); } -int linphone_address_get_port_int(const LinphoneAddress *u) { - return sal_address_get_port_int(u); -} -const char* linphone_address_get_port(const LinphoneAddress *u) { +int linphone_address_get_port(const LinphoneAddress *u) { +#ifdef USE_BELLESIP return sal_address_get_port(u); +#else + return sal_address_get_port_int(u); +#endif } /** @} */ diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 63f587173..20da41fb2 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -70,11 +70,7 @@ const char *sal_address_get_username(const SalAddress *addr){ const char *sal_address_get_domain(const SalAddress *addr){ SAL_ADDRESS_GET(addr,host) } -const char * sal_address_get_port(const SalAddress *addr){ - ms_fatal("sal_address_get_port not implemented yet"); - return NULL; -} -int sal_address_get_port_int(const SalAddress *addr){ +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) { @@ -112,11 +108,7 @@ void sal_address_set_domain(SalAddress *addr, const char *host){ SAL_ADDRESS_SET(addr,host,host); } -void sal_address_set_port(SalAddress *addr, const char *port){ - SAL_ADDRESS_SET(addr,port,atoi(port)); -} - -void sal_address_set_port_int(SalAddress *addr, int port){ +void sal_address_set_port(SalAddress *addr, int port){ SAL_ADDRESS_SET(addr,port,port); } diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index d00ba86b7..2bc14ed21 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -488,7 +488,7 @@ int sal_add_listen_port(Sal *ctx, SalAddress* addr){ int result; belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack ,sal_address_get_domain(addr) - ,sal_address_get_port_int(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); @@ -504,7 +504,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i SalAddress* sal_addr = sal_address_new(NULL); int result; sal_address_set_domain(sal_addr,addr); - sal_address_set_port_int(sal_addr,port); + sal_address_set_port(sal_addr,port); sal_address_set_transport(sal_addr,tr); result = sal_add_listen_port(ctx,sal_addr); sal_address_destroy(sal_addr); diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 85ecd4691..2163831a5 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -72,7 +72,7 @@ static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* 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_int(contact,-1); + sal_address_set_port(contact,-1); sal_address_set_domain(contact,NULL); sal_op_set_contact_address(op,contact); sal_address_destroy(contact); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ae2ff5f01..335e49dc7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2607,7 +2607,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , if (ctt!=NULL){ /*otherwise use supllied localip*/ linphone_address_set_domain(ctt,localip); - linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); + linphone_address_set_port(ctt,linphone_core_get_sip_port(lc)); ms_message("Contact has been fixed using local ip"/* to %s",ret*/); #ifdef USE_BELLESIP ret=ctt; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2c3feefa1..eb6993b95 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1460,7 +1460,7 @@ static void update_primary_contact(LinphoneCore *lc){ lc->sip_conf.loopback_only=TRUE; }else lc->sip_conf.loopback_only=FALSE; linphone_address_set_domain(url,tmp); - linphone_address_set_port_int(url,linphone_core_get_sip_port (lc)); + linphone_address_set_port(url,linphone_core_get_sip_port (lc)); guessed=linphone_address_as_string(url); lc->sip_conf.guessed_contact=guessed; linphone_address_destroy(url); @@ -2395,7 +2395,11 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA if (transport){ SalAddress *route=sal_address_new(NULL); sal_address_set_domain(route,sal_address_get_domain((SalAddress*)dest)); +#ifdef USE_BELLESIP + sal_address_set_port(route,sal_address_get_port((SalAddress*)dest)); +#else sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)dest)); +#endif sal_address_set_transport_name(route,transport); ret=ms_list_append(ret,route); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 83c800ad1..57bab7181 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -183,19 +183,13 @@ LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddr 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. - * + * Get port number as an integer value, -1 if not set. */ -LINPHONE_PUBLIC int linphone_address_get_port_int(const LinphoneAddress *u); -/** - * Get port number, null if not present. - */ -LINPHONE_PUBLIC const char* linphone_address_get_port(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, const char *port); -LINPHONE_PUBLIC void linphone_address_set_port_int(LinphoneAddress *uri, int port); +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 char *linphone_address_as_string(const LinphoneAddress *u); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 08df88bb6..560c2e759 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -328,7 +328,7 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ } #endif - linphone_address_set_port_int(contact,localport); + linphone_address_set_port(contact,localport); linphone_address_set_domain(contact,localip); linphone_address_set_display_name(contact,NULL); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index a6cee3d48..ac4adc2b9 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -79,7 +79,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); diff --git a/include/sal/sal.h b/include/sal/sal.h index 53e2a4219..e9b20b522 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -83,16 +83,24 @@ const char *sal_address_get_display_name(const SalAddress* addr); const char *sal_address_get_display_name_unquoted(const SalAddress *addr); const char *sal_address_get_username(const SalAddress *addr); const char *sal_address_get_domain(const SalAddress *addr); +#ifdef USE_BELLESIP +int sal_address_get_port(const SalAddress *addr); +#else const char * sal_address_get_port(const SalAddress *addr); int sal_address_get_port_int(const SalAddress *addr); +#endif SalTransport sal_address_get_transport(const SalAddress* addr); const char* sal_address_get_transport_name(const SalAddress* addr); void sal_address_set_display_name(SalAddress *addr, const char *display_name); void sal_address_set_username(SalAddress *addr, const char *username); void sal_address_set_domain(SalAddress *addr, const char *host); +#ifdef USE_BELLESIP +void sal_address_set_port(SalAddress *uri, int port); +#else void sal_address_set_port(SalAddress *addr, const char *port); void sal_address_set_port_int(SalAddress *uri, int port); +#endif void sal_address_clean(SalAddress *addr); char *sal_address_as_string(const SalAddress *u); char *sal_address_as_string_uri_only(const SalAddress *u); diff --git a/tester/register_tester.c b/tester/register_tester.c index b84e1aec1..94c8461eb 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -560,7 +560,7 @@ static void tls_with_non_tls_server(){ 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_int(addr)>0?linphone_address_get_port_int(addr):5060)); + ,(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); From e990ea0cef935f9a0ea7d8615e8d8b5a23147255 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Sep 2013 10:08:16 +0200 Subject: [PATCH 702/909] wrapper generator in progress --- COPYING | 12 +- coreapi/address.c | 10 +- coreapi/help/Doxyfile.in | 2 +- coreapi/linphonecall.c | 21 +- coreapi/linphonecore.h | 22 +- mediastreamer2 | 2 +- tools/Makefile.am | 2 +- tools/genwrappers.cc | 615 ++++++++++++++++++++++++++++++++++++--- 8 files changed, 612 insertions(+), 74 deletions(-) diff --git a/COPYING b/COPYING index d60c31a97..b18ab0474 100644 --- a/COPYING +++ b/COPYING @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest diff --git a/coreapi/address.c b/coreapi/address.c index 7f1971abe..15f3a4062 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -171,13 +171,15 @@ void linphone_address_destroy(LinphoneAddress *u){ sal_address_unref(u); } +/** + * Get port number as an integer value. + */ +/** + * Get port number, 0 if not present. + */ int linphone_address_get_port(const LinphoneAddress *u) { -#ifdef USE_BELLESIP return sal_address_get_port(u); -#else - return sal_address_get_port_int(u); -#endif } /** @} */ diff --git a/coreapi/help/Doxyfile.in b/coreapi/help/Doxyfile.in index dce1804b2..27068c53d 100644 --- a/coreapi/help/Doxyfile.in +++ b/coreapi/help/Doxyfile.in @@ -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/linphonecall.c b/coreapi/linphonecall.c index 335e49dc7..cf6233546 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1203,16 +1203,31 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); } +/** + * @ingroup call_control + * Set requested level of privacy for the call. + * \xmlonly javascript \endxmlonly + * @param params the call parameters to be modified + * @param LinphonePrivacy to configure privacy + * */ void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { params->privacy=privacy; } + +/** + * @ingroup call_control + * Get requested level of privacy for the call. + * @param params the call parameters + * @return Privacy mode + * */ LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { return params->privacy; } - - - +/** + * @ingroup call_control + * @return string value of LinphonePrivacy enum + **/ const char* linphone_privacy_to_string(LinphonePrivacy privacy) { switch(privacy) { case LinphonePrivacyDefault: return "LinphonePrivacyDefault"; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 57bab7181..a7d8cc793 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -182,9 +182,6 @@ 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, -1 if not set. - */ 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); @@ -371,24 +368,9 @@ typedef enum _LinphonePrivacy { * */ typedef unsigned int LinphonePrivacyMask; -/** - * @ingroup call_control - * @return string value of LinphonePrivacy enum - * */ -const char* linphone_privacy_to_string(LinphonePrivacy privacy); -/** - * @ingroup call_control - * Set requested level of privacy for the call. - * @param params the call parameters to be modified - * @param LinphonePrivacy to configure privacy - * */ + +LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy); LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); -/** - * @ingroup call_control - * Get requested level of privacy for the call. - * @param params the call parameters - * @return Privacy mode - * */ LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params); diff --git a/mediastreamer2 b/mediastreamer2 index ac5233ae1..56128aa7e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ac5233ae16394d59cf4d9783a229f2adc2111b12 +Subproject commit 56128aa7e5e613708cd8a35beb5d2643dc4dae67 diff --git a/tools/Makefile.am b/tools/Makefile.am index 9f8233a80..169fda781 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,7 +12,7 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) -AM_CXXFLAGS=$(LIBXML2_CFLAGS) +AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc index c506f6f71..3508937db 100644 --- a/tools/genwrappers.cc +++ b/tools/genwrappers.cc @@ -23,9 +23,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#include +#include #include #include +#include +#include +#include using namespace::std; @@ -33,19 +38,41 @@ using namespace::std; class Type{ public: enum BasicType{ + Void, + Boolean, Integer, + Float, String, - Klass + Enum, + Class }; + static Type* addType(BasicType bt, const string &name){ + Type* ret; + if ((ret=mTypes[name])==0){ + cout<<"Adding new "<<(bt==Enum ? "enum" : "class")<<" type '"<mBasic=Enum; + } + return ret; + } static Type *getType(const std::string &tname){ if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ return &sStringType; - }else if (strcmp(tname.c_str(),"int")==0){ + }else if (tname.find("int")==0){ return &sIntegerType; - }else{ - Type* ret; + }else if (tname.find("float")==0){ + return &sFloatType; + }else if (tname.find("bool_t")==0){ + return &sBooleanType; + }else if (tname.find("void")!=string::npos){ + return &sVoidType; + }else if (tname.find("enum")==0){ + return addType(Enum,tname.c_str()+strlen("enum ")); + }else{/*an object?*/ + string tmp=tname; - ssize_t pos; + size_t pos; /*really ugly and slow*/ @@ -60,19 +87,17 @@ public: while ((pos=tmp.find(' '))!=string::npos){ tmp.erase(pos,1); } - - if ((ret=mTypes[tmp])==0){ - cout<<"Adding new class type '"< mTypes; }; Type Type::sStringType(Type::String); Type Type::sIntegerType(Type::Integer); +Type Type::sVoidType(Type::Void); +Type Type::sBooleanType(Type::Boolean); +Type Type::sFloatType(Type::Float); std::map Type::mTypes; class Argument{ public: - Argument(Type *type, const string &argname, bool isConst) : mType(type), mName(argname), mConst(isConst){ + Argument(Type *type, const string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){ + if (!isPointer) mConst=false; } Type *getType()const{ return mType; } + bool isConst()const{ + return mConst; + } + const string &getName()const{ + return mName; + } + bool isPointer()const{ + return mPointer; + } + const string &getHelp()const{ + return mHelp; + } private: - bool mConst; + Type *mType; string mName; string mHelp; + bool mConst; + bool mPointer; }; class Method{ public: - Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args){ + enum PropertyBehaviour{ + None, + Read, + Write + }; + Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic){ mUid=uid; mReturn=return_arg; mName=name; mArgs=args; + mConst=isConst; + mStatic=isStatic; + analyseProperties(); } void setHelp(const std::string &help){ mHelp=help; } + Argument *getReturnArg()const{ + return mReturn; + } + const string &getName()const{ + return mName; + } + const list &getArgs()const { + return mArgs; + } + bool isConst()const{ + return mConst; + } + bool isStatic()const{ + return mStatic; + } + const string &getHelp(){ + return mHelp; + } + PropertyBehaviour getPropertyBehaviour()const{ + return mPropertyBehaviour; + } + const string &getPropertyName()const{ + return mPropertyName; + } private: + void analyseProperties(){ + size_t enabled_pos; + mPropertyBehaviour=None; + + if (mName.find("get")==0 && mArgs.size()==0){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Read; + } + }else if (mName.find("enable")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(6,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Write; + } + }else if (mName.find("set")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Write; + } + }else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){ + size_t goodpos=mName.size()-7; + if (enabled_pos==goodpos){ + mPropertyName=mName.substr(0,goodpos); + if (!mPropertyName.empty()){ + mPropertyBehaviour=Read; + } + } + } + if (mPropertyBehaviour==None) + mPropertyName=""; + } string mUid; Argument *mReturn; string mName; list mArgs; string mHelp; + string mPropertyName; /*if it can be a property*/ + PropertyBehaviour mPropertyBehaviour; + bool mConst; + bool mStatic; }; +class Property{ +public: + enum Attribute{ + ReadOnly, + ReadWrite + }; + Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){ + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + void setHelp(const string &help){ + mHelp=help; + } + Attribute getAttribute()const{ + return mAttr; + } + void setAttribute(Attribute attr){ + mAttr=attr; + } + Type* getType()const{ + return mType; + } +private: + Attribute mAttr; + string mName; + Type *mType; + string mHelp; +}; + +/*actually a class or an enum*/ class Class{ public: Class(const std::string &name): mName(name){ } + Type::BasicType getType(){ + return Type::getType(mName)->getBasicType(); + } void addMethod(Method *method){ - mMethods.push_back(method); + if (mMethods.find(method->getName())==mMethods.end()) + mMethods.insert(make_pair(method->getName(),method)); } void setHelp(const std::string &help){ mHelp=help; } + const list getMethods()const{ + list ret; + map::const_iterator it; + for(it=mMethods.begin();it!=mMethods.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + const list getProperties(){ + list ret; + map::const_iterator it; + for(it=mProperties.begin();it!=mProperties.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + void computeProperties(){ + map::const_iterator it; + Property *prop; + for (it=mMethods.begin();it!=mMethods.end();++it){ + Method *m=(*it).second; + if (m->getPropertyBehaviour()==Method::Read){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + } + }else if (m->getPropertyBehaviour()==Method::Write){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + }else{ + prop->setHelp(m->getHelp()); + prop->setAttribute(Property::ReadWrite); + } + } + } + } private: - list mMethods; + map mMethods; + map mProperties; string mName; string mHelp; }; class Project{ public: + Project(const string &name="wrapper") : mName(name){ + } Class *getClass(const std::string &name){ Class *ret; if ((ret=mClasses[name])==NULL){ @@ -145,8 +347,280 @@ public: } return ret; } + list getClasses()const{ + list ret; + map::const_iterator it; + for(it=mClasses.begin();it!=mClasses.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const string &getName()const{ + return mName; + } + void analyse(){ + list classes=getClasses(); + for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); + } private: map mClasses; + string mName; +}; + +class OutputGenerator{ +public: + virtual void generate(Project *proj)=0; +}; + +class CplusplusGenerator : public OutputGenerator{ +public: + CplusplusGenerator(){ + } + virtual void 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)); + } +private: + void writeClass(Class *klass){ + ostringstream filename; + + if (klass->getType()!=Type::Class) return; + filename<getName()<<"/"<getName()<<".hh"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "< &methods=klass->getMethods(); + mCurClass=klass; + mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<"<getName().empty()) + mOutfile<<"namespace "<getName()<<"{"<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 writeTabs(int ntabs){ + int i; + for(i=0;i100 && comment[i]==' ')){ + mOutfile<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 + 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(&JavascriptGenerator::writeClass),this)); + } +private: + void writeClass(Class *klass){ + ostringstream filename; + + if (klass->getType()!=Type::Class) return; + filename<getName()<<"/"<getName()<<".js"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "< &methods=klass->getMethods(); + mCurClass=klass; + mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<getName().empty()) + // mOutfile<<"namespace "<getName()<<"{"<getName()<getHelp()< 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: + case Type::Enum: + mOutfile<<"external:"<getName(); + break; + case Type::Void: + mOutfile<<"void"; + break; + } + } + void writeArgument(Argument *arg, bool isReturn=false){ + if (!isReturn){ + mOutfile<<" * @param {"; + writeType(arg->getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); + mOutfile<<"} "<getHelp()<100 && comment[i]==' ')){ + 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->getPropertyBehaviour()!=Method::None) return; + if (method->getName()=="ref" || method->getName()=="unref") return; + + mOutfile<<"/**"<getHelp(),1); + mOutfile<getName()<<"#"<getName()<getBasicType()<<" "<getName()< args; + string help; for (cur_node = node->children; cur_node != NULL ; cur_node = cur_node->next){ if (strcmp((const char*)cur_node->name,"name")==0){ @@ -265,19 +754,42 @@ static void parseFunction(Project *proj, xmlNode *node){ name=(const char*)content; xmlFree(content); }else if (strcmp((const char*)cur_node->name,"param")==0){ - if (first_arg==NULL){ - first_arg=parseArgument(cur_node); - } + Argument *a=parseArgument(cur_node,false); + if (a) args.push_back(a); + else return; + }else if (strcmp((const char*)cur_node->name,"detaileddescription")==0){ + help=findChildContent(cur_node,"para"); } } + retarg=parseArgument(node,true); + if (!retarg){ + cerr<<"Could not parse return argument of function "<getType()->getBasicType()!=Type::Class) return; className=first_arg->getType()->getName(); methodName=extractMethodName(name,className); - if (!methodName.empty()){ + if (!methodName.empty() && methodName!="destroy"){ cout<<"Found "<isConst(),false); + method->setHelp(help); + proj->getClass(className)->addMethod(method); + delete first_arg; + } +} + +static void parseTypedef(Project *proj, xmlNode *node){ + string typecontent=findChildContent(node,"type"); + string name=findChildContent(node,"name"); + if (typecontent.find("enum")==0){ + Type::addType(Type::Enum,name); } } @@ -293,9 +805,13 @@ static void parseMemberDef(Project *proj, xmlNode *node){ return; kind=xmlGetProp(node,(const xmlChar*)"kind"); - //cout<<"Kind="<<(const char*)kind< files; + list::iterator it; LIBXML_TEST_VERSION for(i=1;ianalyse(); + gen->generate(proj); return 0; -} \ No newline at end of file +} From e8a786380d57a5302dc795ab2a82c30678727abe Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Sep 2013 16:04:35 +0200 Subject: [PATCH 703/909] genwrappers works quite well --- coreapi/linphonecore.h | 36 +++---- tools/genwrappers.cc | 220 ++++++++++++++++++++++++++++------------- 2 files changed, 168 insertions(+), 88 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a7d8cc793..fcf04e2c7 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -957,9 +957,9 @@ typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFrien * */ 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); +typedef void (*AuthInfoRequestedCb)(struct _LinphoneCore *lc, const char *realm, const char *username); /** Callback prototype */ -typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl); +typedef void (*CallLogUpdatedCb)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl); /** * Callback prototype * @deprecated use #MessageReceived instead. @@ -969,7 +969,7 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog * @param from #LinphoneAddress from * @param message incoming message * */ -typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); +typedef void (*TextMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); /** * Chat message callback prototype * @@ -977,18 +977,18 @@ typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, co * @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 (*MessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); /** Callback prototype */ -typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); +typedef void (*DtmfReceivedCb)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); /** Callback prototype */ -typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to); +typedef void (*ReferReceivedCb)(struct _LinphoneCore *lc, const char *refer_to); /** Callback prototype */ -typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); +typedef void (*BuddyInfoUpdatedCb)(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); +typedef void (*LinphoneTransferStateChangedCb)(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 (*CallStatsUpdatedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); /** Callback prototype for receiving info messages*/ typedef void (*LinphoneInfoReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); @@ -1002,15 +1002,15 @@ typedef struct _LinphoneVTable{ LinphoneCallStateCb call_state_changed;/** A text message has been received */ + TextMessageReceivedCb text_received; /** @deprecated, use #message_received instead
A text message has been received */ } LinphoneCoreVTable; /** diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc index 3508937db..55a30e396 100644 --- a/tools/genwrappers.cc +++ b/tools/genwrappers.cc @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include + using namespace::std; @@ -44,15 +45,17 @@ public: Float, String, Enum, - Class + Class, + Callback }; + static const char *sBasicTypeNames[]; static Type* addType(BasicType bt, const string &name){ Type* ret; if ((ret=mTypes[name])==0){ - cout<<"Adding new "<<(bt==Enum ? "enum" : "class")<<" type '"<mBasic=Enum; + }else if (bt!=Class){ + ret->mBasic=bt; } return ret; } @@ -117,6 +120,19 @@ Type Type::sVoidType(Type::Void); Type Type::sBooleanType(Type::Boolean); Type Type::sFloatType(Type::Float); std::map Type::mTypes; +const char *Type::sBasicTypeNames[]={ + "Void", + "Boolean", + "Integer", + "Float", + "String", + "Enum", + "Class", + "Callback", + "undef", + "undef" +}; + class Argument{ public: @@ -138,6 +154,9 @@ public: const string &getHelp()const{ return mHelp; } + void setHelp(const string &help){ + mHelp=help; + } private: Type *mType; @@ -499,6 +518,7 @@ public: list classes=proj->getClasses(); mCurProj=proj; #ifndef WIN32 + unlink(proj->getName().c_str()); mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); #else _mkdir(proj->getName().c_str()); @@ -524,8 +544,8 @@ private: //if (!mCurProj->getName().empty()) // mOutfile<<"namespace "<getName()<<"{"<getName()<getHelp()<getName()< properties=klass->getProperties(); @@ -556,6 +576,8 @@ private: case Type::Void: mOutfile<<"void"; break; + case Type::Callback: + break; } } void writeArgument(Argument *arg, bool isReturn=false){ @@ -607,7 +629,7 @@ private: if (method->getName()=="ref" || method->getName()=="unref") return; mOutfile<<"/**"<getHelp(),1); + writeHelpComment(method->getHelp(),0); mOutfile<getName()<<"#"<getName()<children; cur_node != NULL ; cur_node = cur_node->next){ - if (strcmp((const char*)cur_node->name,(const char*)element_name)==0){ - return cur_node; - } - } - return NULL; -} - static bool isSpace(const char *str){ for(;*str!='\0';++str){ if (!isspace(*str)) return false; @@ -641,35 +652,78 @@ static bool isSpace(const char *str){ return true; } -static string findChildContent(xmlNode *a_node, const char *element_name){ - xmlNode *node=findChild(a_node,element_name); - string res; - if (node) { - xmlChar *text=xmlNodeGetContent(node); - if (!isSpace((const char*)text)) - res=(char*)text; - xmlFree(text); +class XmlNode{ +public: + XmlNode(const xmlNode *node=NULL) : mNode(node){ } - return res; -} + 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; +}; -#define nullOrEmpty(p) (p==NULL || *p=='\0') - -static Argument *parseArgument(xmlNode *node, bool isReturn){ - string name=findChildContent(node,"declname"); +static Argument *parseArgument(XmlNode node, bool isReturn){ + string name=node.getChild("declname").getText(); Type *type=NULL; - xmlNode *typenode=findChild(node,"type"); - string typecontent=findChildContent(node,"type"); + string typecontent=node.getChild("type").getText(); bool isConst=false; bool isPointer=false; - if (!typenode) { - cout<<"Cannot find type from node."<getBasicType()<<" "<getName()<getBasicType()<<" "<getName()< args; string help; + XmlNode funcnode(node); + XmlNode parameterlist; + list params; + list paramsHelp; + list::iterator it,helpit; - for (cur_node = node->children; cur_node != NULL ; cur_node = cur_node->next){ - if (strcmp((const char*)cur_node->name,"name")==0){ - xmlChar *content=xmlNodeGetContent(cur_node); - name=(const char*)content; - xmlFree(content); - }else if (strcmp((const char*)cur_node->name,"param")==0){ - Argument *a=parseArgument(cur_node,false); - if (a) args.push_back(a); - else return; - }else if (strcmp((const char*)cur_node->name,"detaileddescription")==0){ - help=findChildContent(cur_node,"para"); + 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()->getName(); methodName=extractMethodName(name,className); if (!methodName.empty() && methodName!="destroy"){ - cout<<"Found "<isConst(),false); method->setHelp(help); @@ -786,32 +865,33 @@ static void parseFunction(Project *proj, xmlNode *node){ } static void parseTypedef(Project *proj, xmlNode *node){ - string typecontent=findChildContent(node,"type"); - string name=findChildContent(node,"name"); + 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("void(*")==0){ + // callbacks function, not really well parsed by doxygen + Type::addType(Type::Callback,name); + }else + proj->getClass(name)->setHelp(getHelpBody(node)); } static void parseMemberDef(Project *proj, xmlNode *node){ + XmlNode member(node); string brief; string detailed; - const xmlChar *kind; + string kind; - brief=findChildContent(node,"briefdescription"); - detailed=findChildContent(node,"detaileddescription"); - - if (brief.empty() && detailed.empty()) + if (member.getChild("briefdescription").getText().empty() && + member.getChild("detaileddescription").getChild("para").getText().empty()) return; - kind=xmlGetProp(node,(const xmlChar*)"kind"); - if (kind){ - //cout<<"Kind="<<(const char*)kind< Date: Fri, 20 Sep 2013 17:40:27 +0200 Subject: [PATCH 704/909] fix issue with window id management --- coreapi/linphonecore.c | 61 ++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eb6993b95..5dfbd37a9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4891,26 +4891,33 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) { * @ingroup media_parameters **/ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ + if (lc->video_window_id) { + /* case where the video id was previously set by the app*/ + return lc->video_window_id; + }else{ #ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call (lc); - if (call && call->videostream) - return video_stream_get_native_window_id(call->videostream); - if (lc->previewstream) - return video_stream_get_native_window_id(lc->previewstream); + /*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/ + LinphoneCall *call=linphone_core_get_current_call (lc); + if (call && call->videostream) + return video_stream_get_native_window_id(call->videostream); #endif - return lc->video_window_id; + } + return 0; } -/**@ingroup media_parameters +/** + * @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){ -#ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call(lc); 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 } @@ -4921,14 +4928,20 @@ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id * @ingroup media_parameters **/ unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc){ + if (lc->preview_window_id){ + /*case where the id was set by the app previously*/ + return lc->preview_window_id; + }else{ + /*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/ #ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call (lc); - if (call && call->videostream) - return video_stream_get_native_preview_window_id(call->videostream); - if (lc->previewstream) - return video_preview_get_native_window_id(lc->previewstream); + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call && call->videostream) + return video_stream_get_native_preview_window_id(call->videostream); + if (lc->previewstream) + return video_preview_get_native_window_id(lc->previewstream); #endif - return lc->preview_window_id; + } + return 0; } /** @@ -4938,13 +4951,15 @@ unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc) * If not set the core will create its own window. **/ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id){ -#ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call(lc); lc->preview_window_id=id; - if (call!=NULL && call->videostream){ - video_stream_set_native_preview_window_id(call->videostream,id); - }else if (lc->previewstream){ - video_preview_set_native_window_id(lc->previewstream,id); +#ifdef VIDEO_ENABLED + { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call!=NULL && call->videostream){ + video_stream_set_native_preview_window_id(call->videostream,id); + }else if (lc->previewstream){ + video_preview_set_native_window_id(lc->previewstream,id); + } } #endif } From 2fd37f338d8c2ef1ce34446c2aadabdf524ef707 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Sep 2013 17:50:38 +0200 Subject: [PATCH 705/909] RTCP fix --- coreapi/linphonecall.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index cf6233546..3135ea09a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1684,7 +1684,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr, stream->rtp_port, stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr, - linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0, + linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0, used_pt, linphone_core_get_audio_jittcomp(lc), playfile, @@ -1806,7 +1806,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_start(call->videostream, call->video_profile, rtp_addr, vstream->rtp_port, - rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0, + rtcp_addr, + linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, used_pt, linphone_core_get_video_jittcomp(lc), cam); video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); } From f8ead1facbda0de1b03eb29031f9d13e0f7d569c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 23 Sep 2013 15:25:23 +0200 Subject: [PATCH 706/909] fixes around opengl display for androdi --- coreapi/linphonecore.c | 32 ++++++++++++++++++++++++++++++-- coreapi/linphonecore_jni.cc | 8 ++++++-- mediastreamer2 | 2 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5dfbd37a9..308e6b425 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4905,12 +4905,37 @@ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ return 0; } +/* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/ +static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned long id){ + LinphoneCall *call; + MSList *elem; + + if (id!=0 && id!=-1) { + ms_error("Invalid use of unset_video_window_id()"); + return; + } +#ifdef VIDEO_ENABLED + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + call=(LinphoneCall *) elem->data; + if (call->videostream){ + if (preview) + video_stream_set_native_preview_window_id(call->videostream,id); + else + video_stream_set_native_window_id(call->videostream,id); + } + } +#endif +} + /** * @ingroup media_parameters * Set the native video window id where the video is to be displayed. - * If not set the core will create its own window. + * For MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given. **/ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){ + if (id==0 || id==(unsigned long)-1){ + unset_video_window_id(lc,FALSE,id); + } lc->video_window_id=id; #ifdef VIDEO_ENABLED { @@ -4948,9 +4973,12 @@ unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc) * @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){ + if (id==0 || id==(unsigned long)-1){ + unset_video_window_id(lc,TRUE,id); + } lc->preview_window_id=id; #ifdef VIDEO_ENABLED { diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b243d25d9..d647b94c1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2379,9 +2379,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* jobject oldWindow = (jobject) linphone_core_get_native_video_window_id((LinphoneCore*)lc); if (obj != NULL) { obj = env->NewGlobalRef(obj); - } + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): NewGlobalRef(%p)",obj); + }else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): setting to NULL"); linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj); if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): DeleteGlobalRef(%p)",oldWindow); env->DeleteGlobalRef(oldWindow); } } @@ -2393,9 +2395,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(JNIEn jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id((LinphoneCore*)lc); if (obj != NULL) { obj = env->NewGlobalRef(obj); - } + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): NewGlobalRef(%p)",obj); + }else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): setting to NULL"); linphone_core_set_native_preview_window_id((LinphoneCore*)lc,(unsigned long)obj); if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): DeleteGlobalRef(%p)",oldWindow); env->DeleteGlobalRef(oldWindow); } } diff --git a/mediastreamer2 b/mediastreamer2 index 56128aa7e..def761ec9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 56128aa7e5e613708cd8a35beb5d2643dc4dae67 +Subproject commit def761ec9d8bdbeee5dd7d1ba343675bfc999989 From c6a96174d0fd12c9364412ffbad81c43efc3641e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 23 Sep 2013 17:14:25 +0200 Subject: [PATCH 707/909] split genwrappers into several smaller pieces --- oRTP | 2 +- tools/Makefile.am | 4 +- tools/generator.cc | 284 +++++++++++++++++++ tools/generator.hh | 66 +++++ tools/genwrappers.cc | 622 +---------------------------------------- tools/software-desc.cc | 40 +++ tools/software-desc.hh | 369 ++++++++++++++++++++++++ 7 files changed, 767 insertions(+), 620 deletions(-) create mode 100644 tools/generator.cc create mode 100644 tools/generator.hh create mode 100644 tools/software-desc.cc create mode 100644 tools/software-desc.hh diff --git a/oRTP b/oRTP index 706f0b59f..ce8c19753 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 706f0b59f818a69c673053e831fa1f19a855f80b +Subproject commit ce8c19753495b4ad16a6c5df2bf2bf235443f762 diff --git a/tools/Makefile.am b/tools/Makefile.am index 169fda781..fb6253465 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -59,7 +59,9 @@ lpc2xml_test_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ liblpc2xml.la -lp_gen_wrappers_SOURCES=genwrappers.cc +lp_gen_wrappers_SOURCES=genwrappers.cc \ + software-desc.cc software-desc.hh \ + generator.cc generator.hh lp_gen_wrappers_LDADD= \ $(LIBXML2_LIBS) diff --git a/tools/generator.cc b/tools/generator.cc new file mode 100644 index 000000000..dddefb09a --- /dev/null +++ b/tools/generator.cc @@ -0,0 +1,284 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +Simon Morlat (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include + +#include "generator.hh" + +#ifdef WIN32 +#include +#endif + + +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::writeClass(Class *klass){ + ostringstream filename; + + if (klass->getType()!=Type::Class) return; + filename<getName()<<"/"<getName()<<".hh"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "< &methods=klass->getMethods(); + mCurClass=klass; + mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<"<getName().empty()) + mOutfile<<"namespace "<getName()<<"{"<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<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 + unlink(proj->getName().c_str()); + 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(&JavascriptGenerator::writeClass),this)); +} + +void JavascriptGenerator::writeClass(Class *klass){ + ostringstream filename; + + if (klass->getType()!=Type::Class) return; + filename<getName()<<"/"<getName()<<".js"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "< &methods=klass->getMethods(); + mCurClass=klass; + mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<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: + case Type::Enum: + mOutfile<<"external:"<getName(); + break; + case Type::Void: + mOutfile<<"void"; + break; + case Type::Callback: + break; + } +} + +void JavascriptGenerator::writeArgument(Argument *arg, bool isReturn){ + if (!isReturn){ + mOutfile<<" * @param {"; + writeType(arg->getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); + mOutfile<<"} "<getHelp()<100 && comment[i]==' ')){ + 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->getPropertyBehaviour()!=Method::None) return; + if (method->getName()=="ref" || method->getName()=="unref") 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); + ofstream mOutfile; + Project *mCurProj; + Class *mCurClass; +}; + +class JavascriptGenerator : public OutputGenerator{ +public: + JavascriptGenerator(); + virtual void generate(Project *proj); +private: + void writeClass(Class *klass); + void writeType(Type *type); + void writeArgument(Argument *arg, bool isReturn=false); + void writeTabs(int ntabs); + void writeHelpComment(const std::string &comment, int ntabs); + void writeProperty(Property *prop); + void writeMethod(Method *method); + ofstream mOutfile; + Project *mCurProj; + Class *mCurClass; +}; + + +#endif diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc index 55a30e396..6bc1dfb5f 100644 --- a/tools/genwrappers.cc +++ b/tools/genwrappers.cc @@ -18,632 +18,17 @@ 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 #include -#include -#include -#include - -#include -#include -using namespace::std; - - -class Type{ -public: - enum BasicType{ - Void, - Boolean, - Integer, - Float, - String, - Enum, - Class, - Callback - }; - static const char *sBasicTypeNames[]; - static Type* addType(BasicType bt, const string &name){ - Type* ret; - if ((ret=mTypes[name])==0){ - //cout<<"Adding new "<mBasic=bt; - } - return ret; - } - static Type *getType(const std::string &tname){ - if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ - return &sStringType; - }else if (tname.find("int")==0){ - return &sIntegerType; - }else if (tname.find("float")==0){ - return &sFloatType; - }else if (tname.find("bool_t")==0){ - return &sBooleanType; - }else if (tname.find("void")!=string::npos){ - return &sVoidType; - }else if (tname.find("enum")==0){ - return addType(Enum,tname.c_str()+strlen("enum ")); - }else{/*an object?*/ - - string tmp=tname; - size_t pos; - - /*really ugly and slow*/ - - pos=tmp.find('*'); - if (pos!=string::npos) - tmp.erase(pos,1); - - pos=tmp.find("const"); - if (pos!=string::npos) - tmp.erase(pos,strlen("const")); - - while ((pos=tmp.find(' '))!=string::npos){ - tmp.erase(pos,1); - } - return addType(Class,tmp); - } - cerr<<"Unhandled type name"< mTypes; -}; - -Type Type::sStringType(Type::String); -Type Type::sIntegerType(Type::Integer); -Type Type::sVoidType(Type::Void); -Type Type::sBooleanType(Type::Boolean); -Type Type::sFloatType(Type::Float); -std::map Type::mTypes; -const char *Type::sBasicTypeNames[]={ - "Void", - "Boolean", - "Integer", - "Float", - "String", - "Enum", - "Class", - "Callback", - "undef", - "undef" -}; - - -class Argument{ -public: - Argument(Type *type, const string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){ - if (!isPointer) mConst=false; - } - Type *getType()const{ - return mType; - } - bool isConst()const{ - return mConst; - } - const string &getName()const{ - return mName; - } - bool isPointer()const{ - return mPointer; - } - const string &getHelp()const{ - return mHelp; - } - void setHelp(const string &help){ - mHelp=help; - } -private: - - Type *mType; - string mName; - string mHelp; - bool mConst; - bool mPointer; -}; - -class Method{ -public: - enum PropertyBehaviour{ - None, - Read, - Write - }; - Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic){ - mUid=uid; - mReturn=return_arg; - mName=name; - mArgs=args; - mConst=isConst; - mStatic=isStatic; - analyseProperties(); - } - void setHelp(const std::string &help){ - mHelp=help; - } - Argument *getReturnArg()const{ - return mReturn; - } - const string &getName()const{ - return mName; - } - const list &getArgs()const { - return mArgs; - } - bool isConst()const{ - return mConst; - } - bool isStatic()const{ - return mStatic; - } - const string &getHelp(){ - return mHelp; - } - PropertyBehaviour getPropertyBehaviour()const{ - return mPropertyBehaviour; - } - const string &getPropertyName()const{ - return mPropertyName; - } -private: - void analyseProperties(){ - size_t enabled_pos; - mPropertyBehaviour=None; - - if (mName.find("get")==0 && mArgs.size()==0){ - mPropertyName=mName.substr(3,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Read; - } - }else if (mName.find("enable")==0 && mArgs.size()==1){ - mPropertyName=mName.substr(6,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Write; - } - }else if (mName.find("set")==0 && mArgs.size()==1){ - mPropertyName=mName.substr(3,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Write; - } - }else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){ - size_t goodpos=mName.size()-7; - if (enabled_pos==goodpos){ - mPropertyName=mName.substr(0,goodpos); - if (!mPropertyName.empty()){ - mPropertyBehaviour=Read; - } - } - } - if (mPropertyBehaviour==None) - mPropertyName=""; - } - string mUid; - Argument *mReturn; - string mName; - list mArgs; - string mHelp; - string mPropertyName; /*if it can be a property*/ - PropertyBehaviour mPropertyBehaviour; - bool mConst; - bool mStatic; -}; - -class Property{ -public: - enum Attribute{ - ReadOnly, - ReadWrite - }; - Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){ - } - const string &getName()const{ - return mName; - } - const string &getHelp()const{ - return mHelp; - } - void setHelp(const string &help){ - mHelp=help; - } - Attribute getAttribute()const{ - return mAttr; - } - void setAttribute(Attribute attr){ - mAttr=attr; - } - Type* getType()const{ - return mType; - } -private: - Attribute mAttr; - string mName; - Type *mType; - string mHelp; -}; - -/*actually a class or an enum*/ -class Class{ -public: - Class(const std::string &name): mName(name){ - } - Type::BasicType getType(){ - return Type::getType(mName)->getBasicType(); - } - void addMethod(Method *method){ - if (mMethods.find(method->getName())==mMethods.end()) - mMethods.insert(make_pair(method->getName(),method)); - } - void setHelp(const std::string &help){ - mHelp=help; - } - const list getMethods()const{ - list ret; - map::const_iterator it; - for(it=mMethods.begin();it!=mMethods.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - const string &getName()const{ - return mName; - } - const string &getHelp()const{ - return mHelp; - } - const list getProperties(){ - list ret; - map::const_iterator it; - for(it=mProperties.begin();it!=mProperties.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - void computeProperties(){ - map::const_iterator it; - Property *prop; - for (it=mMethods.begin();it!=mMethods.end();++it){ - Method *m=(*it).second; - if (m->getPropertyBehaviour()==Method::Read){ - prop=mProperties[m->getPropertyName()]; - if (prop==NULL){ - prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp()); - mProperties[m->getPropertyName()]=prop; - } - }else if (m->getPropertyBehaviour()==Method::Write){ - prop=mProperties[m->getPropertyName()]; - if (prop==NULL){ - prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp()); - mProperties[m->getPropertyName()]=prop; - }else{ - prop->setHelp(m->getHelp()); - prop->setAttribute(Property::ReadWrite); - } - } - } - } -private: - map mMethods; - map mProperties; - string mName; - string mHelp; -}; - -class Project{ -public: - Project(const string &name="wrapper") : mName(name){ - } - Class *getClass(const std::string &name){ - Class *ret; - if ((ret=mClasses[name])==NULL){ - ret=mClasses[name]=new Class(name); - } - return ret; - } - list getClasses()const{ - list ret; - map::const_iterator it; - for(it=mClasses.begin();it!=mClasses.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - const string &getName()const{ - return mName; - } - void analyse(){ - list classes=getClasses(); - for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); - } -private: - map mClasses; - string mName; -}; - -class OutputGenerator{ -public: - virtual void generate(Project *proj)=0; -}; - -class CplusplusGenerator : public OutputGenerator{ -public: - CplusplusGenerator(){ - } - virtual void 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)); - } -private: - void writeClass(Class *klass){ - ostringstream filename; - - if (klass->getType()!=Type::Class) return; - filename<getName()<<"/"<getName()<<".hh"; - mOutfile.open(filename.str().c_str()); - if (!mOutfile.is_open()){ - cerr<<"Could not write into "< &methods=klass->getMethods(); - mCurClass=klass; - mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<"<getName().empty()) - mOutfile<<"namespace "<getName()<<"{"<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 writeTabs(int ntabs){ - int i; - for(i=0;i100 && comment[i]==' ')){ - mOutfile<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 - unlink(proj->getName().c_str()); - 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(&JavascriptGenerator::writeClass),this)); - } -private: - void writeClass(Class *klass){ - ostringstream filename; - - if (klass->getType()!=Type::Class) return; - filename<getName()<<"/"<getName()<<".js"; - mOutfile.open(filename.str().c_str()); - if (!mOutfile.is_open()){ - cerr<<"Could not write into "< &methods=klass->getMethods(); - mCurClass=klass; - mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<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: - case Type::Enum: - mOutfile<<"external:"<getName(); - break; - case Type::Void: - mOutfile<<"void"; - break; - case Type::Callback: - break; - } - } - void writeArgument(Argument *arg, bool isReturn=false){ - if (!isReturn){ - mOutfile<<" * @param {"; - writeType(arg->getType()); - mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); - mOutfile<<"} "<getHelp()<100 && comment[i]==' ')){ - 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->getPropertyBehaviour()!=Method::None) return; - if (method->getName()=="ref" || method->getName()=="unref") return; - - mOutfile<<"/**"<getHelp(),0); - mOutfile<getName()<<"#"<getName()< Type::mTypes; +const char *Type::sBasicTypeNames[]={ + "Void", + "Boolean", + "Integer", + "Float", + "String", + "Enum", + "Class", + "Callback", + "undef", + "undef" +}; diff --git a/tools/software-desc.hh b/tools/software-desc.hh new file mode 100644 index 000000000..bf01ed202 --- /dev/null +++ b/tools/software-desc.hh @@ -0,0 +1,369 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +Simon Morlat (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef software_desc_hh +#define software_desc_hh + +#include +#include +#include +#include + +#include +#include +#include + + +using namespace::std; + + +class Type{ +public: + enum BasicType{ + Void, + Boolean, + Integer, + Float, + String, + Enum, + Class, + Callback + }; + static const char *sBasicTypeNames[]; + static Type* addType(BasicType bt, const string &name){ + Type* ret; + if ((ret=mTypes[name])==0){ + //cout<<"Adding new "<mBasic=bt; + } + return ret; + } + static Type *getType(const std::string &tname){ + if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ + return &sStringType; + }else if (tname.find("int")==0){ + return &sIntegerType; + }else if (tname.find("float")==0){ + return &sFloatType; + }else if (tname.find("bool_t")==0){ + return &sBooleanType; + }else if (tname.find("void")!=string::npos){ + return &sVoidType; + }else if (tname.find("enum")==0){ + return addType(Enum,tname.c_str()+strlen("enum ")); + }else{/*an object?*/ + + string tmp=tname; + size_t pos; + + /*really ugly and slow*/ + + pos=tmp.find('*'); + if (pos!=string::npos) + tmp.erase(pos,1); + + pos=tmp.find("const"); + if (pos!=string::npos) + tmp.erase(pos,strlen("const")); + + while ((pos=tmp.find(' '))!=string::npos){ + tmp.erase(pos,1); + } + return addType(Class,tmp); + } + cerr<<"Unhandled type name"< mTypes; +}; + + + +class Argument{ +public: + Argument(Type *type, const string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){ + if (!isPointer) mConst=false; + } + Type *getType()const{ + return mType; + } + bool isConst()const{ + return mConst; + } + const string &getName()const{ + return mName; + } + bool isPointer()const{ + return mPointer; + } + const string &getHelp()const{ + return mHelp; + } + void setHelp(const string &help){ + mHelp=help; + } +private: + + Type *mType; + string mName; + string mHelp; + bool mConst; + bool mPointer; +}; + +class Method{ +public: + enum PropertyBehaviour{ + None, + Read, + Write + }; + Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic){ + mUid=uid; + mReturn=return_arg; + mName=name; + mArgs=args; + mConst=isConst; + mStatic=isStatic; + analyseProperties(); + } + void setHelp(const std::string &help){ + mHelp=help; + } + Argument *getReturnArg()const{ + return mReturn; + } + const string &getName()const{ + return mName; + } + const list &getArgs()const { + return mArgs; + } + bool isConst()const{ + return mConst; + } + bool isStatic()const{ + return mStatic; + } + const string &getHelp(){ + return mHelp; + } + PropertyBehaviour getPropertyBehaviour()const{ + return mPropertyBehaviour; + } + const string &getPropertyName()const{ + return mPropertyName; + } +private: + void analyseProperties(){ + size_t enabled_pos; + mPropertyBehaviour=None; + + if (mName.find("get")==0 && mArgs.size()==0){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Read; + } + }else if (mName.find("enable")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(6,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Write; + } + }else if (mName.find("set")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Write; + } + }else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){ + size_t goodpos=mName.size()-7; + if (enabled_pos==goodpos){ + mPropertyName=mName.substr(0,goodpos); + if (!mPropertyName.empty()){ + mPropertyBehaviour=Read; + } + } + } + if (mPropertyBehaviour==None) + mPropertyName=""; + } + string mUid; + Argument *mReturn; + string mName; + list mArgs; + string mHelp; + string mPropertyName; /*if it can be a property*/ + PropertyBehaviour mPropertyBehaviour; + bool mConst; + bool mStatic; +}; + +class Property{ +public: + enum Attribute{ + ReadOnly, + ReadWrite + }; + Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){ + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + void setHelp(const string &help){ + mHelp=help; + } + Attribute getAttribute()const{ + return mAttr; + } + void setAttribute(Attribute attr){ + mAttr=attr; + } + Type* getType()const{ + return mType; + } +private: + Attribute mAttr; + string mName; + Type *mType; + string mHelp; +}; + +/*actually a class or an enum*/ +class Class{ +public: + Class(const std::string &name): mName(name){ + } + Type::BasicType getType(){ + return Type::getType(mName)->getBasicType(); + } + void addMethod(Method *method){ + if (mMethods.find(method->getName())==mMethods.end()) + mMethods.insert(make_pair(method->getName(),method)); + } + void setHelp(const std::string &help){ + mHelp=help; + } + const list getMethods()const{ + list ret; + map::const_iterator it; + for(it=mMethods.begin();it!=mMethods.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + const list getProperties(){ + list ret; + map::const_iterator it; + for(it=mProperties.begin();it!=mProperties.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + void computeProperties(){ + map::const_iterator it; + Property *prop; + for (it=mMethods.begin();it!=mMethods.end();++it){ + Method *m=(*it).second; + if (m->getPropertyBehaviour()==Method::Read){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + } + }else if (m->getPropertyBehaviour()==Method::Write){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + }else{ + prop->setHelp(m->getHelp()); + prop->setAttribute(Property::ReadWrite); + } + } + } + } +private: + map mMethods; + map mProperties; + string mName; + string mHelp; +}; + +class Project{ +public: + Project(const string &name="wrapper") : mName(name){ + } + Class *getClass(const std::string &name){ + Class *ret; + if ((ret=mClasses[name])==NULL){ + ret=mClasses[name]=new Class(name); + } + return ret; + } + list getClasses()const{ + list ret; + map::const_iterator it; + for(it=mClasses.begin();it!=mClasses.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const string &getName()const{ + return mName; + } + void analyse(){ + list classes=getClasses(); + for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); + } +private: + map mClasses; + string mName; +}; + +#endif From 26850e521381cd0675af2da18bb6de9f2cf5ad0f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 24 Sep 2013 08:48:32 +0200 Subject: [PATCH 708/909] update certificate test, use mediastream stats/iterate --- coreapi/linphonecall.c | 12 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 69 +++- tester/certificates/agent.pem | 137 ------- tester/certificates/altname/agent.pem | 76 ++++ tester/certificates/{ => altname}/cacert.pem | 0 .../certificates/altname/openssl-altname.cnf | 359 ++++++++++++++++++ tester/certificates/cn/agent.pem | 80 ++++ tester/certificates/cn/cacert.pem | 20 + tester/certificates/cn/openssl-cn.cnf | 357 +++++++++++++++++ tester/flexisip.conf | 9 +- tester/pauline_alt_rc | 30 +- tester/pauline_wild_rc | 35 +- tester/register_tester.c | 4 +- tester/tester_hosts | 2 +- 16 files changed, 987 insertions(+), 207 deletions(-) delete mode 100644 tester/certificates/agent.pem create mode 100644 tester/certificates/altname/agent.pem rename tester/certificates/{ => altname}/cacert.pem (100%) create mode 100644 tester/certificates/altname/openssl-altname.cnf create mode 100644 tester/certificates/cn/agent.pem create mode 100644 tester/certificates/cn/cacert.pem create mode 100644 tester/certificates/cn/openssl-cn.cnf diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 335e49dc7..9b97ecc93 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2245,11 +2245,11 @@ 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; +static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs){ + call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (media_stream_get_down_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (media_stream_get_up_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (media_stream_get_down_bw(vs)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (media_stream_get_up_bw(vs)*1e-3) : 0; ms_message("bandwidth usage: 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 , @@ -2364,7 +2364,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse video_load=ms_ticker_get_average_load(call->videostream->ms.ticker); vs=call->videostream->ms.session; } - report_bandwidth(call,as,vs); + report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream); ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); } diff --git a/mediastreamer2 b/mediastreamer2 index ac5233ae1..5b941cb16 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ac5233ae16394d59cf4d9783a229f2adc2111b12 +Subproject commit 5b941cb169940ae643de86e957daa86c31c25145 diff --git a/oRTP b/oRTP index 706f0b59f..ce8c19753 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 706f0b59f818a69c673053e831fa1f19a855f80b +Subproject commit ce8c19753495b4ad16a6c5df2bf2bf235443f762 diff --git a/tester/call_tester.c b/tester/call_tester.c index 74364fb66..18f7a2ec9 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -95,6 +95,35 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { } #endif +static void check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { + LinphoneCall *c1,*c2; + int i; + int dummy=0; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); + + for (i=0; i<3; i++) { + if (linphone_call_get_audio_stats(c1)->round_trip_delay >0.0 + && linphone_call_get_audio_stats(c2)->round_trip_delay >0.0 + && (!linphone_call_get_video_stats(c1) || linphone_call_get_video_stats(c1)->round_trip_delay>0.0) + && (!linphone_call_get_video_stats(c1) || linphone_call_get_video_stats(c1)->round_trip_delay>0.0)) { + break; + } + wait_for(caller->lc,callee->lc,&dummy,1); + + } + CU_ASSERT_TRUE(linphone_call_get_audio_stats(c1)->round_trip_delay>0.0); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(c2)->round_trip_delay>0.0); + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { + CU_ASSERT_TRUE(linphone_call_get_video_stats(c1)->round_trip_delay>0.0); + } + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { + CU_ASSERT_TRUE(linphone_call_get_video_stats(c2)->round_trip_delay>0.0); + } + +} + bool_t call_with_params(LinphoneCoreManager* caller_mgr ,LinphoneCoreManager* callee_mgr , const LinphoneCallParams *caller_params @@ -205,6 +234,9 @@ static void simple_call(void) { CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); /*just to sleep*/ wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + + check_rtcp(marie,pauline); + linphone_core_terminate_all_calls(lc_pauline); CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); @@ -325,9 +357,9 @@ static void call_with_dns_time_out(void) { static void early_cancelled_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_alt_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new2( "empty_rc",FALSE); - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"sip:marie@sip.example.org"); + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); linphone_core_terminate_call(pauline->lc,out_call); @@ -398,7 +430,7 @@ static void call_declined(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* in_call; - LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); linphone_call_ref(out_call); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(marie->lc)); @@ -471,6 +503,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee } return success; } + static void call_with_ice(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -487,6 +520,9 @@ static void call_with_ice(void) { CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + check_rtcp(marie,pauline); + + /*then close the call*/ linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); @@ -645,6 +681,29 @@ static void call_with_video_added(void) { linphone_core_manager_destroy(pauline); } +static void call_with_media_relay(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + CU_ASSERT_TRUE(call(pauline,marie)); + check_rtcp(pauline,marie); + +#ifdef VIDEO_ENABLED + CU_ASSERT_TRUE(add_video(pauline,marie)); + check_rtcp(pauline,marie); +#endif + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + static void call_with_declined_video(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -703,6 +762,8 @@ static void video_call(void) { linphone_call_send_vfu_request(marie_call); CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + check_rtcp(marie,pauline); + linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); @@ -901,6 +962,7 @@ static void srtp_ice_call(void) { add_video(pauline,marie); CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + check_rtcp(marie,pauline); #endif /*wait for ice to found the direct path*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); @@ -1156,6 +1218,7 @@ test_t call_tests[] = { { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, { "Simple call", simple_call }, + { "Call with media relay", call_with_media_relay}, { "Simple call compatibility mode", simple_call_compatibility_mode }, { "Early-media call", early_media_call }, { "Call terminated by caller", call_terminated_by_caller }, diff --git a/tester/certificates/agent.pem b/tester/certificates/agent.pem deleted file mode 100644 index e3d88e21e..000000000 --- a/tester/certificates/agent.pem +++ /dev/null @@ -1,137 +0,0 @@ ------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----- ------BEGIN CERTIFICATE----- -MIIDbTCCAtagAwIBAgIBADANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx -EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK -DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV -BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNDMwMTQzMTE3WhcN -MTQwNDMwMTQzMTE3WjCBvzELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3Rh -dGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQKDBlCZWxsZWRvbm5lIENvbW11 -bmljYXRpb25zMQwwCgYDVQQLDANMQUIxGjAYBgNVBAMMEXNpcDIubGlucGhvbmUu -b3JnMTowOAYJKoZIhvcNAQkBFitqZWhhbi5tb25uaWVyQGJlbGxlZG9ubmUtY29t -bXVuaWNhdGlvbnMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHZG78 -iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKtJJzhp5ysq4VH7q/dmOnM -nbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWVfgeSXstCK8m9SwxKqnqA -5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQABo3sweTAJBgNVHRMEAjAA -MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd -BgNVHQ4EFgQUMhkW8N0sNI/+El1P4AzuxQbIsYwwHwYDVR0jBBgwFoAUBl9dxxav -YvgtbnEDiKDWHSsEf7owDQYJKoZIhvcNAQEFBQADgYEAkzT/wjLRg4JXAZDZ1uVR -uAXrftoKrsvTysRU7Lr+N5W9FPoWqBh35Kx5SnRN3LYf0OIaJ5hufC8v+SOIJ6Me -QpKMlMY05Fz7R2aXkSS3Ie1GUJNKnWmos2uRFIMgIpFpr2VAZqVlsjC6J7SKIdGw -JvmtefxJrjl8Tpzw5uRNC58= ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAxx5TlbzfmfCneIzofE09/4lr+hQk2ihrBAgZi+kVto5o/oW8 -xtvUfek6dOcF8lK6Ss6AvTQH/4SrK8Ico72eOaxTXjBxpdZuEvftmowawUqvr8DV -dwsleFcp7pmdNarG6WxW9d690ixE4TKpvSYAzoVv2z/0PxjGLNTALcfav8tCvjEv -804Pw4NuSmW6wjw+kRKTz/l4wYNlVXsAXt30xAuELkbHEVmcFBL5Al4CsgwF0su3 -oA8/IYE+eOIFu6ANZa8h2t9yHZSDlAwhe0yPRt0NDzp3RbsaG0oPudkmP3ithTJz -5Pmf7Oq46Ko2Wk3GfxykaoYpvjBTahkWOUoFowIDAQABAoIBABMZ/qy7rLuo0XgI -FHlwM4VjGn+oFQz0maeOW10HpDSaHspj7AMrrYvSpu/2BaUEeKiafNEpv6ashHsz -KOowU5B2zpyXix98nZymOh38WMi4MHhsyE2ePR75RaWFCQbP9jsIUKNPlegmpQjx -gkUJ80PcmyluTjELYF+GnVUG+h4x5y2RiUiQr+zTUXGTBDny3jKdtMrmctqkG9hQ -cgIV/RG+CaFGxdkTShHEAhpd+g0DIivHZctwrF7Q1WFJBj3zChe223a6JdF2ke4c -Rr79PkHkCWGwv6Rp/95XUnQKJ8/FPTNtFoGzR6bhKmWqh3q2qfZKRKtXw2LBwFJp -f8U5++kCgYEA8ieuaVqKmCZwm/WRWeimG+UHs+EtHLgmj18ylD1jKQaRetSDcZ4m -6ounfrxyBL7DBDym/CeWbq9OI9cQB2RGLK3To6vj1UbRQ6tKiRzDq933sYZoEcTs -kBzexW8oUsclAvqYbqEjxEoEQrgHTWvjuHYiTrNlOAo+eL0VV6trZMUCgYEA0oC8 -40I8quYILtlkSYT3+iMRX4Vy1BzzMOkzRrA9jFoJZIxcOnWitJWmfBcXgOckt9ka -XchsxOcYbNa9CuI7YKrJ5SNP9cjxcxsd/gieQXcN3J/nebFwlsQFN1e8mZIZj7ik -nDf+r0lyuighDR7dLjR00a39csLCx6dH0amb90cCgYB+9jEqya7q0RSvoJQh2Knm -7DEardASQ7br6tTBBmKMKwZxqSR1mJ780FX0S+dX95CWExrWEAd+ZumIPwUHaxqj -6EuTf9cHhobHfPKqautonAt3B2pfDqmdcZWXXI1+wSz1n9/1+QSgsNIFDSm+/Pc7 -Sqz4KHTEahKRCUo8WgMHpQKBgQCXeFdy2Bi7iKbev0Mwu+OMNGut5mLISsSbr1Jc -TTkcozUbCvzafAdGFmEj7aHV+X0sZaZZUX0i+n9S4fpJuJytZHe+z/gbjipff2XH -hAAMb1SkKtPvd0Ti185BEnr9rmmCR4T7fDdhfmJ1naaawFi7hLeCocY8K/TooXBG -Z9t4xQKBgQDCqZ5Gumy+pvyUqLXtgrCmWlbr03ONBKb9n662thWeBWpCKb2e0RUA -oxTZvVsTQz88Ageoh55QHIe85//iT2wDtjUFcc80aoWDDhQuwxnu7jtEyj1wytl9 -SIsjG4JDTK1tBAVZFxyS5sMLZ2nonzynAyHPN0j1UCHF2T2Hk7/vEQ== ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIEFzCCA4CgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx -EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK -DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV -BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNzE1MTQzNDQ3WhcN -MTYwNzE0MTQzNDQ3WjCBnTELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEi -MCAGA1UECgwZQmVsbGVkb25uZSBDb21tdW5pY2F0aW9uczEMMAoGA1UECwwDTEFC -MRUwEwYDVQQDDAx1c2VsZXNzLm5hbWUxNDAyBgkqhkiG9w0BCQEWJWNvbnRhY3RA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQDHHlOVvN+Z8Kd4jOh8TT3/iWv6FCTaKGsECBmL6RW2jmj+ -hbzG29R96Tp05wXyUrpKzoC9NAf/hKsrwhyjvZ45rFNeMHGl1m4S9+2ajBrBSq+v -wNV3CyV4VynumZ01qsbpbFb13r3SLEThMqm9JgDOhW/bP/Q/GMYs1MAtx9q/y0K+ -MS/zTg/Dg25KZbrCPD6REpPP+XjBg2VVewBe3fTEC4QuRscRWZwUEvkCXgKyDAXS -y7egDz8hgT544gW7oA1lryHa33IdlIOUDCF7TI9G3Q0POndFuxobSg+52SY/eK2F -MnPk+Z/s6rjoqjZaTcZ/HKRqhim+MFNqGRY5SgWjAgMBAAGjgcIwgb8wCQYDVR0T -BAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh -dGUwHQYDVR0OBBYEFFTLqxYKaMQ+dgVPEwvjWt0QWh2uMB8GA1UdIwQYMBaAFAZf -XccWr2L4LW5xA4ig1h0rBH+6MAsGA1UdDwQEAwIF4DA3BgNVHREEMDAughVhbHRu -YW1lMS5saW5waG9uZS5vcmeCFWFsdG5hbWUyLmxpbnBob25lLm9yZzANBgkqhkiG -9w0BAQUFAAOBgQBZ8yk7MMp+wyiEH/4HF/MTobAmNJxgnVGvz3lnGGNXCrE9hJiA -xNdh0jfQfLMVJN5MtkpcM6Md9wowXkIMakpDIiTwnl+ve6GPOypZv2TXrm68sYid -SXlvHqN5G12HMUP577NNQxgpod6+d0jW6oPYWx1a7kCa8hOlKTRvajMyjQ== ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAxGYHUVdxtkJCtFbaFd31aflHq7px9Yz/QhJUuivf30UNfgwT -k7n8UQG4G7F+LXno04uNR0B4mPPLRcfibLCKzDgMwHKReqnwtS35r2Pvfva3vvdB -ZOA7HkFIEpcp8R8XxK3Lcmcn1yYAravYKawM6QwkQv1FdM0TeRNTXXSqc4/Ty1Sd -WjoJxyEbGb8N44MRIfi6fePYlpKKI7/nQ8Y+E1f87OhOcBV+33b0hBXDLBY9XqsR -7JaZDpwlMBRsTTFU6+ApF4q4RmGFoACA2ZO4GkE8OdIbRLhPa8DPVzfo52sJhmSM -gPw8JN3TRYxbmEF+KhVejdmGxtAKNEBzEwbnwwIDAQABAoIBAQCbhdP7pMxGMLhT -yIcQU+C4F4+avJzrfsjP0GZJut6gFjV2ACgsjlXw6/SX8XjimCw4AMVSjAozzLLG -Ql/aA/8VcrkeWFs9kH8tagfTzMZlewfMcE3XjP0jmzxwhEXRS/btZ1a49FkHNW/K -F0+oyDa9AUFhzuAGezMVaKlWU0F7GiGciGWRTUqt9CxtbagVdCo6Oilo1pEVpf8S -aEM0Eyl7VnkjPBWZ/wZwEhetvrFl/Wb0k31d0TkmcNpIGHd+nAbBhoJkZ0MISC64 -TmJaDW982xIV30FlGmm/tKGO4a5xTEwlw5E3k8ReubLGS8RkHLXNZKmxQK5fA1BJ -mcwa5ue5AoGBAOg40SDdLYzL8fpASBVXi15s3muAOODO9hVGzIUp/2OVxQ6SGK2P -tEI2UJwjKJtgVHgs/dN4uHhmYN+n6DPOWMt0x7UigFlskr0qjKfAEfi1hb6S1ZPR -hCWPe1NnOMKkNnasMVETkfS7FKxQ4DfhU+I0geXfKXCY7HZZRz/4Fg+XAoGBANiC -LlCzeTzkdY1+Es1MyBApyZCHWUK1aJbHhA5BYr+aojIl9t/962ioBcFQ3j4krq4x -OcQqcbu7lUSR/YdDSLkRxMH7AEfbKwwJUa4NrxAjSRkvbWVyNVGLa5B9eXj9zS3Q -AV23BKwjuWOmSCg70EsxeSyKEwvdvdrGfKWMfW61AoGAIC5PfNhpyYsxu1ZRJvP8 -0lcP86HPQAguPgCTsxiA1dIZfs1sMhEqD8rrHNgadn3A9u51NmsSVU0Ku7PPD+7W -i0thqY5gbwQGycQtvcl2NBsjr6c1hciRIYtiscoqKX8MNSHjq7KklV+fm8mRaO0G -7OAN6EcmvP3UNwpkP08n730CgYEAhtcM4VXle/cM/0I1k4buUqKz1j91aAZzTPSV -Wgt+5LX5riHWz0nlAxkh/HPQ9gMCh5pAz9tfWfxJyprhuww8joZydB1O33GwLZ7g -L/Z1wSc4r2bKSxQGAPND2olKzf/DeXTCZQtG7a6SF23IIsadwzbcsNCNbCZ9x3M2 -ziPhOsECgYB9BU7vYn5LMTtA7FIx+Fv//aepoBT/+pC8AUCA7EX5vEIf3cxEwesm -CkHknaKWlxhlK379OKQryYrUsRxjxwFd0DNK5tT+jx6m8VVKe1Bz/8uYZDNCtJr0 -zoqngR61r5jCYZLYcggcTimVoHMJXxcdsReBX8P7u3JNU2CulGvX7w== ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIID6DCCA1GgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx -EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK -DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV -BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwNzE1MTQ0MDM4WhcN -MTYwNzE0MTQ0MDM4WjCBpzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTEi -MCAGA1UECgwZQmVsbGVkb25uZSBDb21tdW5pY2F0aW9uczEMMAoGA1UECwwDTEFC -MR8wHQYDVQQDDBYqLndpbGRjYXJkLmxpbnBob25lLmZyMTQwMgYJKoZIhvcNAQkB -FiVjb250YWN0QGJlbGxlZG9ubmUtY29tbXVuaWNhdGlvbnMuY29tMIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxGYHUVdxtkJCtFbaFd31aflHq7px9Yz/ -QhJUuivf30UNfgwTk7n8UQG4G7F+LXno04uNR0B4mPPLRcfibLCKzDgMwHKReqnw -tS35r2Pvfva3vvdBZOA7HkFIEpcp8R8XxK3Lcmcn1yYAravYKawM6QwkQv1FdM0T -eRNTXXSqc4/Ty1SdWjoJxyEbGb8N44MRIfi6fePYlpKKI7/nQ8Y+E1f87OhOcBV+ -33b0hBXDLBY9XqsR7JaZDpwlMBRsTTFU6+ApF4q4RmGFoACA2ZO4GkE8OdIbRLhP -a8DPVzfo52sJhmSMgPw8JN3TRYxbmEF+KhVejdmGxtAKNEBzEwbnwwIDAQABo4GJ -MIGGMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk -IENlcnRpZmljYXRlMB0GA1UdDgQWBBRJAgxmoZo5VCDjeR/tR5XZtE2NtzAfBgNV -HSMEGDAWgBQGX13HFq9i+C1ucQOIoNYdKwR/ujALBgNVHQ8EBAMCBeAwDQYJKoZI -hvcNAQEFBQADgYEAXxtgbwO3/ilkEx3jW8wlBN4dg++EBCsw0RkhhiNyWLwF7OOf -xttppVNF4HW3xiOAs7FUSIgiNwHd+j8N3LpJxBpd7ePSaKy/U1EWoj38u8q5Q1gU -d3Lu+D0XaQvZyVW7xoYwTLa9CmRItow4GIkExoUhyrurbOmJ/3q9/SRGWF8= ------END CERTIFICATE----- diff --git a/tester/certificates/altname/agent.pem b/tester/certificates/altname/agent.pem new file mode 100644 index 000000000..c75085728 --- /dev/null +++ b/tester/certificates/altname/agent.pem @@ -0,0 +1,76 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDHZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKt +JJzhp5ysq4VH7q/dmOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWV +fgeSXstCK8m9SwxKqnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQAB +AoGAGgyi+1dmwGj2r5n3I5+aBwv2DxO5zHgOfkMssUFUneC6ZXq8duZboJd3Po/B +/93NGBRMJzFLgjv5PeYWXPUjOoJT7eg0aDJKX/uMKSvzhyIL/bUJPfyo2GCmkAr5 +CF5EBFFjlsui2kSFusxbQmyzZkkIl3OYdlTBdQFsmEROk8kCQQD3aW1ZPbDkSxsi +09VZBWVW95LojcxYQeqjPTs8EAB2jKmR4aw8KGKCz+yBGwiSdukDZ/p3IftuifHk +J+3a6kqnAkEAzlBKjM8xVWprTp/3p1DMYNA+KNsXuf08xGB/zegpU561FjUzK7U4 +QKyDSIaRgSv4WAJbIauwaZdydM6Q0DnANwJBAKEQGQeHiaiU3E2H6dPSF27OLO0H +ooeyIbWzHuSy5hpG5/z4FM/02myePzCtEJ+ImZiGEB+OF8iWNMp60/U3oPECQAoR +RPIGEkQ2wzG9AJq7iJ2Yy8+2kTvULajvhI0JrSqVbgS9Z9fUKgCN6oIZfvQsrxus +UcIc3KjqaP1mLw7aIpUCQH5S0B+GOwKa8+RbuRcgBvksqkRwRZn6jawoNJJSBCDn +gQJ5B9PvJXppTsbnulSD2srhUqCR1pzGfnl8bYV8b8Q= +-----END RSA PRIVATE KEY----- + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com + Validity + Not Before: Sep 23 15:58:58 2013 GMT + Not After : Sep 23 15:58:58 2014 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=See altname for DNS name/emailAddress=jehan.monnier@belledonne-communications.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c7:64:6e:fc:8b:09:24:c4:97:aa:dd:93:ee:43: + 06:3d:0d:f7:5c:34:2b:c7:5d:ac:96:fb:9a:79:55: + 45:0b:57:9d:28:84:92:ad:24:9c:e1:a7:9c:ac:ab: + 85:47:ee:af:dd:98:e9:cc:9d:b6:13:00:29:ea:55: + 29:69:87:cf:33:45:d4:09:77:f8:34:87:a4:f8:0f: + 25:9a:e4:9c:5e:f9:1d:61:c0:b5:95:7e:07:92:5e: + cb:42:2b:c9:bd:4b:0c:4a:aa:7a:80:e6:63:d9:c5: + f0:11:5e:0d:eb:e1:75:a4:50:ad:80:d6:55:88:5c: + 29:19:53:73:0c:0f:82:49:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Alternative Name: + DNS:altname.linphone.org, DNS:*.wildcard2.linphone.org + Signature Algorithm: sha1WithRSAEncryption + 21:05:d3:36:82:5d:f4:f4:70:71:17:ac:06:12:49:0c:d6:c3: + 21:07:9c:2f:79:c8:14:da:e5:3a:92:04:22:5b:74:cf:53:3c: + 95:33:51:93:66:04:59:c6:3d:dd:22:cf:3f:f8:0e:24:93:6b: + 2a:02:f7:bf:ba:89:1b:72:9a:d4:1b:bf:22:3d:08:51:13:a4: + bf:43:d2:89:a1:c5:f2:e3:04:24:1e:d4:33:64:06:83:2d:b6: + 66:34:16:a9:f4:8d:6f:3f:71:86:ab:73:19:36:ae:43:29:7e: + 9d:6c:35:3a:75:f4:22:8b:c5:e3:1e:ee:c1:0d:d7:63:cc:95: + 4a:6a +-----BEGIN CERTIFICATE----- +MIIDSjCCArOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwOTIzMTU1ODU4WhcN +MTQwOTIzMTU1ODU4WjCBwjELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh +dGlvbnMxDDAKBgNVBAsMA0xBQjEhMB8GA1UEAwwYU2VlIGFsdG5hbWUgZm9yIERO +UyBuYW1lMTowOAYJKoZIhvcNAQkBFitqZWhhbi5tb25uaWVyQGJlbGxlZG9ubmUt +Y29tbXVuaWNhdGlvbnMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH +ZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKtJJzhp5ysq4VH7q/d +mOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWVfgeSXstCK8m9SwxK +qnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQABo1UwUzAJBgNVHRME +AjAAMAsGA1UdDwQEAwIF4DA5BgNVHREEMjAwghRhbHRuYW1lLmxpbnBob25lLm9y +Z4IYKi53aWxkY2FyZDIubGlucGhvbmUub3JnMA0GCSqGSIb3DQEBBQUAA4GBACEF +0zaCXfT0cHEXrAYSSQzWwyEHnC95yBTa5TqSBCJbdM9TPJUzUZNmBFnGPd0izz/4 +DiSTayoC97+6iRtymtQbvyI9CFETpL9D0omhxfLjBCQe1DNkBoMttmY0Fqn0jW8/ +cYarcxk2rkMpfp1sNTp19CKLxeMe7sEN12PMlUpq +-----END CERTIFICATE----- diff --git a/tester/certificates/cacert.pem b/tester/certificates/altname/cacert.pem similarity index 100% rename from tester/certificates/cacert.pem rename to tester/certificates/altname/cacert.pem diff --git a/tester/certificates/altname/openssl-altname.cnf b/tester/certificates/altname/openssl-altname.cnf new file mode 100644 index 000000000..c4edb6c7d --- /dev/null +++ b/tester/certificates/altname/openssl-altname.cnf @@ -0,0 +1,359 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + + req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Grenoble + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Belledonne Communications + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = LAB +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 +commonName_default = See altname for DNS name + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = jehan.monnier@belledonne-communications.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = altname.linphone.org +DNS.2 = *.wildcard2.linphone.org + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/tester/certificates/cn/agent.pem b/tester/certificates/cn/agent.pem new file mode 100644 index 000000000..978221639 --- /dev/null +++ b/tester/certificates/cn/agent.pem @@ -0,0 +1,80 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDHZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKt +JJzhp5ysq4VH7q/dmOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWV +fgeSXstCK8m9SwxKqnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQAB +AoGAGgyi+1dmwGj2r5n3I5+aBwv2DxO5zHgOfkMssUFUneC6ZXq8duZboJd3Po/B +/93NGBRMJzFLgjv5PeYWXPUjOoJT7eg0aDJKX/uMKSvzhyIL/bUJPfyo2GCmkAr5 +CF5EBFFjlsui2kSFusxbQmyzZkkIl3OYdlTBdQFsmEROk8kCQQD3aW1ZPbDkSxsi +09VZBWVW95LojcxYQeqjPTs8EAB2jKmR4aw8KGKCz+yBGwiSdukDZ/p3IftuifHk +J+3a6kqnAkEAzlBKjM8xVWprTp/3p1DMYNA+KNsXuf08xGB/zegpU561FjUzK7U4 +QKyDSIaRgSv4WAJbIauwaZdydM6Q0DnANwJBAKEQGQeHiaiU3E2H6dPSF27OLO0H +ooeyIbWzHuSy5hpG5/z4FM/02myePzCtEJ+ImZiGEB+OF8iWNMp60/U3oPECQAoR +RPIGEkQ2wzG9AJq7iJ2Yy8+2kTvULajvhI0JrSqVbgS9Z9fUKgCN6oIZfvQsrxus +UcIc3KjqaP1mLw7aIpUCQH5S0B+GOwKa8+RbuRcgBvksqkRwRZn6jawoNJJSBCDn +gQJ5B9PvJXppTsbnulSD2srhUqCR1pzGfnl8bYV8b8Q= +-----END RSA PRIVATE KEY----- + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com + Validity + Not Before: Sep 23 16:13:11 2013 GMT + Not After : Sep 21 16:13:11 2023 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=sip2.linphone.org, CN=*.wildcard1.linphone.org/emailAddress=jehan.monnier@belledonne-communications.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c7:64:6e:fc:8b:09:24:c4:97:aa:dd:93:ee:43: + 06:3d:0d:f7:5c:34:2b:c7:5d:ac:96:fb:9a:79:55: + 45:0b:57:9d:28:84:92:ad:24:9c:e1:a7:9c:ac:ab: + 85:47:ee:af:dd:98:e9:cc:9d:b6:13:00:29:ea:55: + 29:69:87:cf:33:45:d4:09:77:f8:34:87:a4:f8:0f: + 25:9a:e4:9c:5e:f9:1d:61:c0:b5:95:7e:07:92:5e: + cb:42:2b:c9:bd:4b:0c:4a:aa:7a:80:e6:63:d9:c5: + f0:11:5e:0d:eb:e1:75:a4:50:ad:80:d6:55:88:5c: + 29:19:53:73:0c:0f:82:49:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 32:19:16:F0:DD:2C:34:8F:FE:12:5D:4F:E0:0C:EE:C5:06:C8:B1:8C + X509v3 Authority Key Identifier: + keyid:06:5F:5D:C7:16:AF:62:F8:2D:6E:71:03:88:A0:D6:1D:2B:04:7F:BA + + Signature Algorithm: sha1WithRSAEncryption + af:2e:d2:9a:b9:e0:ca:c8:e3:25:eb:30:0b:5e:02:e9:43:2d: + 84:09:11:d1:be:8e:a4:86:bf:c7:19:aa:18:c3:55:b2:07:c5: + 68:ff:c6:39:f7:2b:da:27:85:34:8b:7b:6c:92:8f:ba:aa:9d: + 44:f3:0c:47:88:7a:0c:b1:e0:c7:6f:eb:af:d2:ab:d0:6d:25: + d5:ff:40:37:69:2b:bd:f2:6e:4a:42:32:29:98:27:c7:ec:34: + 25:eb:22:6f:83:50:82:1c:08:88:77:ec:31:82:c2:0c:77:b1: + 2b:c9:7d:6c:ff:95:d0:10:cf:8e:9f:2e:eb:a1:a6:40:fc:c0: + ec:83 +-----BEGIN CERTIFICATE----- +MIIDjDCCAvWgAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwOTIzMTYxMzExWhcN +MjMwOTIxMTYxMzExWjCB3jELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh +dGlvbnMxDDAKBgNVBAsMA0xBQjEaMBgGA1UEAwwRc2lwMi5saW5waG9uZS5vcmcx +ITAfBgNVBAMMGCoud2lsZGNhcmQxLmxpbnBob25lLm9yZzE6MDgGCSqGSIb3DQEJ +ARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRpb25zLmNvbTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx2Ru/IsJJMSXqt2T7kMGPQ33XDQr +x12slvuaeVVFC1edKISSrSSc4aecrKuFR+6v3ZjpzJ22EwAp6lUpaYfPM0XUCXf4 +NIek+A8lmuScXvkdYcC1lX4Hkl7LQivJvUsMSqp6gOZj2cXwEV4N6+F1pFCtgNZV +iFwpGVNzDA+CSeECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYd +T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDIZFvDdLDSP +/hJdT+AM7sUGyLGMMB8GA1UdIwQYMBaAFAZfXccWr2L4LW5xA4ig1h0rBH+6MA0G +CSqGSIb3DQEBBQUAA4GBAK8u0pq54MrI4yXrMAteAulDLYQJEdG+jqSGv8cZqhjD +VbIHxWj/xjn3K9onhTSLe2ySj7qqnUTzDEeIegyx4Mdv66/Sq9BtJdX/QDdpK73y +bkpCMimYJ8fsNCXrIm+DUIIcCIh37DGCwgx3sSvJfWz/ldAQz46fLuuhpkD8wOyD +-----END CERTIFICATE----- diff --git a/tester/certificates/cn/cacert.pem b/tester/certificates/cn/cacert.pem new file mode 100644 index 000000000..2fd957d39 --- /dev/null +++ b/tester/certificates/cn/cacert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRjCCAq+gAwIBAgIJAJ3nFcA7qFrOMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD +VQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUx +IjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xB +QjEWMBQGA1UEAwwNSmVoYW4gTW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4u +bW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRpb25zLmNvbTAeFw0xMzA0MzAx +MzMwMThaFw0yMzA0MjgxMzMwMThaMIG7MQswCQYDVQQGEwJGUjETMBEGA1UECAwK +U29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9u +bmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xBQjEWMBQGA1UEAwwNSmVoYW4g +TW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5l +LWNvbW11bmljYXRpb25zLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +z5F8mMh3SUr6NUd7tq2uW2Kdn22Zn3kNpLYb78AQK4IoQMOLGXbBdyoXvz1fublg +bxtLYsiGhICd7Ul9zLGc3edn85LbD3Skb7ERx6MakRnYep3FzagZJhn14QEaZCx6 +3Qs0Ir4rSP7hmlpYt8VO/zqqNR3tsA59O0D9c7bpQ7UCAwEAAaNQME4wHQYDVR0O +BBYEFAZfXccWr2L4LW5xA4ig1h0rBH+6MB8GA1UdIwQYMBaAFAZfXccWr2L4LW5x +A4ig1h0rBH+6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAKvmt2m1o +axGKc0DjiJPypU/NsAf4Yu0nOnY8pHqJJCB0AWVoAPM7vGYPWpeH7LSdGZLuT9eK +FUWGJhPnkrnklmBdVB0l7qXYjR5uf766HDkoDxuLhNifow3IYvsS+L2Y6puRQb9w +HLMDE29mBDl0WyoX3h0yR0EiAO15V9A7I10= +-----END CERTIFICATE----- diff --git a/tester/certificates/cn/openssl-cn.cnf b/tester/certificates/cn/openssl-cn.cnf new file mode 100644 index 000000000..c6262db31 --- /dev/null +++ b/tester/certificates/cn/openssl-cn.cnf @@ -0,0 +1,357 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Grenoble + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Belledonne Communications + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = LAB +#organizationalUnitName_default = + +0.commonName = Common Name (e.g. server FQDN or YOUR name) +0.commonName_max = 64 +0.commonName_default = sip2.linphone.org + +1.commonName = Common Name (e.g. server FQDN or YOUR name) +1.commonName_max = 64 +1.commonName_default = *.wildcard1.linphone.org + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = jehan.monnier@belledonne-communications.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 28ab406a5..e5bb5389f 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -37,8 +37,7 @@ aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.exa # transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 # Default value: sip:* #transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 -transports=sip:127.0.0.1:5060 sips:127.0.0.1:5061 - +transports=sip:127.0.0.1:5060 sips:127.0.0.1:5061;tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/linphone/tester/certificates/cn sips:127.0.0.1:5062;tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/linphone/tester/certificates/altname # 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 @@ -444,14 +443,14 @@ routes= [module::MediaRelay] # Indicate whether the module is activated. # Default value: true -enabled=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') +# && (:q # Default value: -filter= +filter= (user-agent contains 'Natted Linphone') # SDP attribute set by the first proxy to forbid subsequent proxies # to provide relay. diff --git a/tester/pauline_alt_rc b/tester/pauline_alt_rc index 3a7114d4f..7c1fe55ac 100644 --- a/tester/pauline_alt_rc +++ b/tester/pauline_alt_rc @@ -1,42 +1,20 @@ [sip] -sip_port=5072 -sip_tcp_port=5072 -sip_tls_port=5073 +sip_tls_port=-1 default_proxy=0 -ping_with_options=0 register_only_when_network_is_up=0 [auth_info_0] username=pauline userid=pauline passwd=secret -realm="altname2.linphone.org" +realm=sip.example.org [proxy_0] -reg_proxy=sip2.linphone.org;transport=tls -reg_route=sip2.linphone.org;transport=tls -reg_identity=sip:pauline@altname2.linphone.org +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 - -[rtp] -audio_rtp_port=8090 -video_rtp_port=8092 - -[video] -display=0 -capture=0 -show_local=0 -size=vga -enabled=0 -self_view=0 -automatically_initiate=0 -automatically_accept=0 -device=StaticImage: Static picture - -[sound] -echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/pauline_wild_rc b/tester/pauline_wild_rc index a9b07ed93..d828c807d 100644 --- a/tester/pauline_wild_rc +++ b/tester/pauline_wild_rc @@ -1,42 +1,29 @@ [sip] -sip_port=5072 -sip_tcp_port=5072 -sip_tls_port=5073 +sip_tls_port=-1 default_proxy=0 -ping_with_options=0 register_only_when_network_is_up=0 [auth_info_0] username=pauline userid=pauline passwd=secret -realm="sip.wildcard.linphone.org" +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.wildcard.linphone.org +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 -[rtp] -audio_rtp_port=8090 -video_rtp_port=8092 +[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 -[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/register_tester.c b/tester/register_tester.c index 94c8461eb..c899403be 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -29,8 +29,6 @@ static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { mgr->lc->vtable.auth_info_requested=auth_info_requested; } - /* until we have good certificates on our test server... */ - linphone_core_verify_server_certificates(mgr->lc,FALSE); /*to allow testing with 127.0.0.1*/ linphone_core_set_network_reachable(mgr->lc,TRUE); return mgr; @@ -595,7 +593,7 @@ static void tls_wildcard_register(){ snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); - CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,2)); CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); linphone_core_destroy(mgr->lc); } diff --git a/tester/tester_hosts b/tester/tester_hosts index 39b811654..b7056b863 100644 --- a/tester/tester_hosts +++ b/tester/tester_hosts @@ -1 +1 @@ -94.23.19.176 sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org +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 From e2e4e5918f5c2e757c54ca9edaff2c35c737db82 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 24 Sep 2013 11:36:24 +0200 Subject: [PATCH 709/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index def761ec9..214f82f89 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit def761ec9d8bdbeee5dd7d1ba343675bfc999989 +Subproject commit 214f82f8942f9d1c419f038dbd33b36b65e2a1e6 From 56d6ea22def9a4d6cc831a2ed405f3dc2b8a54cf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 24 Sep 2013 16:06:55 +0200 Subject: [PATCH 710/909] update flexisip.com, change cacert path --- tester/certificates/{altname => }/cacert.pem | 0 tester/certificates/cn/cacert.pem | 20 -------------------- tester/flexisip.conf | 7 +++---- 3 files changed, 3 insertions(+), 24 deletions(-) rename tester/certificates/{altname => }/cacert.pem (100%) delete mode 100644 tester/certificates/cn/cacert.pem diff --git a/tester/certificates/altname/cacert.pem b/tester/certificates/cacert.pem similarity index 100% rename from tester/certificates/altname/cacert.pem rename to tester/certificates/cacert.pem diff --git a/tester/certificates/cn/cacert.pem b/tester/certificates/cn/cacert.pem deleted file mode 100644 index 2fd957d39..000000000 --- a/tester/certificates/cn/cacert.pem +++ /dev/null @@ -1,20 +0,0 @@ ------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/flexisip.conf b/tester/flexisip.conf index e5bb5389f..3a0431440 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -8,7 +8,7 @@ [global] # Outputs very detailed logs # Default value: false -debug=false +debug=1 # Automatically respawn flexisip in case of abnormal termination # (crashes) @@ -37,13 +37,12 @@ aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.exa # transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 # Default value: sip:* #transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 -transports=sip:127.0.0.1:5060 sips:127.0.0.1:5061;tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/linphone/tester/certificates/cn sips:127.0.0.1:5062;tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/linphone/tester/certificates/altname +transports=sip:*:5060 sips:*:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:*:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname # 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 #tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip -tls-certificates-dir=/Users/jehanmonnier/workspaces/workspace-sip-parser/linphone-private/tester/certificates ## ## STUN server parameters. @@ -149,7 +148,7 @@ db-implementation=file # for a DSN-less connection. ex3: /etc/flexisip/passwd; for a file # containing one 'user@domain password' by line. # Default value: -datasource=./userdb.conf +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), From 71f81ce6ecc0b3775b82f4beb9efd0bdfa737f13 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 24 Sep 2013 16:28:50 +0200 Subject: [PATCH 711/909] improve rtcp checking speed --- tester/call_tester.c | 9 +++++---- tester/liblinphone_tester.c | 9 ++++++--- tester/liblinphone_tester.h | 1 + 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 18f7a2ec9..fcffbcc56 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -103,14 +103,15 @@ static void check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); - for (i=0; i<3; i++) { + for (i=0; i<12 /*=6s*/; i++) { if (linphone_call_get_audio_stats(c1)->round_trip_delay >0.0 && linphone_call_get_audio_stats(c2)->round_trip_delay >0.0 - && (!linphone_call_get_video_stats(c1) || linphone_call_get_video_stats(c1)->round_trip_delay>0.0) - && (!linphone_call_get_video_stats(c1) || linphone_call_get_video_stats(c1)->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(caller->lc,callee->lc,&dummy,1); + wait_for_until(caller->lc,callee->lc,&dummy,1,500); /*just to sleep while iterating*/ } CU_ASSERT_TRUE(linphone_call_get_audio_stats(c1)->round_trip_delay>0.0); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a1115c8ce..2e4cd678e 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -125,18 +125,21 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* return lc; } -bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + +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,2000); + result=wait_for_list(lcs,counter,value,timout); ms_list_free(lcs); return result; } - +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + return wait_for_until(lc_1, lc_2,counter,value,2000); +} bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; MSList* iterator; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index f9c58d725..ae5143671 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -203,6 +203,7 @@ void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char * LinphoneAddress * create_linphone_address(const char * domain); bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms); +bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout_ms); bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); stats * get_stats(LinphoneCore *lc); From 005140d3219a317d7b5403889b4c91379f30beb2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 24 Sep 2013 22:20:57 +0200 Subject: [PATCH 712/909] improve notification of generic subscribe errors --- coreapi/bellesip_sal/sal_op_events.c | 145 ++++++++++----------------- coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/event.c | 2 +- mediastreamer2 | 2 +- tester/eventapi_tester.c | 24 ++++- tester/liblinphone_tester.c | 4 +- tools/software-desc.hh | 2 + 7 files changed, 78 insertions(+), 103 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index be60a0b98..376a88bcd 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -18,19 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" - -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); - } -} - 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; @@ -45,73 +32,49 @@ SalSubscribeStatus get_subscription_state(belle_sip_message_t *msg){ return sss; } -static void subscribe_response_event(void *op_base, const belle_sip_response_event_t *event){ - SalOp* op = (SalOp*)op_base; - belle_sip_dialog_state_t dialog_state; - belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); - belle_sip_response_t* response=belle_sip_response_event_get_response(event); - belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - int code = belle_sip_response_get_status_code(response); - char reason[256]={0}; +static void subscribe_refresher_listener (belle_sip_refresher_t* refresher + ,void* user_pointer + ,unsigned int status_code + ,const char* reason_phrase) { + SalOp* op = (SalOp*)user_pointer; SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; - belle_sip_header_expires_t* expires; - SalSubscribeStatus sss=get_subscription_state(BELLE_SIP_MESSAGE(response)); + 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; - if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { - ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); - op->base.root->callbacks.subscribe_response(op,SalSubscribeTerminated,error,sr); - return; + 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)); } - set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); - if (!op->dialog) { - ms_message("subscribe op [%p] received out of dialog answer [%i]",op,code); - return; + if (status_code>=200){ + sal_compute_sal_errors_from_code(status_code,&error,&sr); + op->base.root->callbacks.subscribe_response(op,sss,error,sr); } - dialog_state=belle_sip_dialog_get_state(op->dialog); - switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: - case BELLE_SIP_DIALOG_EARLY: { - ms_error("subscribe 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); - if (op->refresher) belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); - } - if (sss==SalSubscribeNone) sss=SalSubscribeActive; /*without Subscription-state header, consider subscription is accepted.*/ - op->base.root->callbacks.subscribe_response(op,sss,SalErrorNone,SalReasonUnknown); - } - 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("subscribe op [%p] receive answer [%i] not implemented",op,code); - } - /* no break */ + +} + +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) { - ms_message("subscribe_process_timeout not implemented yet"); } static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { - ms_message("subscribe_process_transaction_terminated not implemented yet"); } static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBody * body){ @@ -191,7 +154,8 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque } 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); @@ -235,36 +199,29 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event belle_sip_object_ref(op->event); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event); - }else{ - req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"); - if (!req) { - ms_error("Cannot create subscribe refresh."); - return -1; - } - if (expires==-1){ - belle_sip_transaction_t *last=(belle_sip_transaction_t*)op->pending_client_trans; - belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last)); - belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t); - expires=belle_sip_header_expires_get_expires(eh); - } - 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); } - 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_request(op,req); + ms_warning("sal_subscribe(): no dialog and no refresher ?"); + return -1; } int sal_unsubscribe(SalOp *op){ - belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/ - if (!req) { - ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op)); - return -1; + 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; } - if (op->refresher) - belle_sip_refresher_stop(op->refresher); - 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(0))); - return sal_op_send_request(op,req); + return -1; } int sal_subscribe_accept(SalOp *op){ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 640664ecc..13b3ba004 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -435,7 +435,7 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S } else { strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); } - if (code>400) { + if (code>=400) { sal_compute_sal_errors_from_code(code,sal_err,sal_reason); return TRUE; } else { diff --git a/coreapi/event.c b/coreapi/event.c index 9546e9e7b..46de6b779 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -91,7 +91,7 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat if (lc->vtable.subscription_state_changed){ lc->vtable.subscription_state_changed(lev->lc,lev,state); } - if (state==LinphoneSubscriptionError || state==LinphoneSubscriptionTerminated){ + if (state==LinphoneSubscriptionTerminated){ linphone_event_unref(lev); } } diff --git a/mediastreamer2 b/mediastreamer2 index 214f82f89..5003385d5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 214f82f8942f9d1c419f038dbd33b36b65e2a1e6 +Subproject commit 5003385d52f715b60772da879b4655463890ffd1 diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index b4ce30233..9a20d56a2 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -120,12 +120,15 @@ static void subscribe_test_declined(void) { } -static void subscribe_test_with_args(bool_t terminated_by_subscriber) { +static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t test_refreshing) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneContent content; LinphoneEvent *lev; + int expires= test_refreshing ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); @@ -134,7 +137,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { content.data=(char*)subscribe_content; content.size=strlen(subscribe_content); - lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); @@ -143,6 +146,11 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { /*make sure marie receives first notification before terminating*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); + + if (test_refreshing){ + wait_for_list(lcs,NULL,0,6000); + CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive); + } if (terminated_by_subscriber){ linphone_event_terminate(lev); @@ -159,11 +167,18 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber) { } static void subscribe_test_terminated_by_subscriber(void){ - subscribe_test_with_args(TRUE); + subscribe_test_with_args(TRUE,FALSE); } static void subscribe_test_terminated_by_notifier(void){ - subscribe_test_with_args(FALSE); + subscribe_test_with_args(FALSE,FALSE); +} + +/* Caution: this test does not really check that the subscribe are refreshed, because the core is not managing the expiration of + * unrefreshed subscribe dialogs. So it is just checking that it is not crashing. + */ +static void subscribe_test_refreshed(void){ + subscribe_test_with_args(TRUE,TRUE); } static void publish_test_with_args(bool_t refresh){ @@ -218,6 +233,7 @@ static void publish_no_auto_test(){ test_t event_tests[] = { { "Subscribe declined" , subscribe_test_declined }, { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, + { "Subscribe refreshed", subscribe_test_refreshed }, { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, { "Publish", publish_test }, { "Publish without automatic refresh",publish_no_auto_test } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 2e4cd678e..d9d004c05 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -143,13 +143,13 @@ 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) { int retry=0; MSList* iterator; - while (*counternext) { linphone_core_iterate((LinphoneCore*)(iterator->data)); } ms_usleep(100000); } - if(*counter Date: Tue, 24 Sep 2013 22:23:20 +0200 Subject: [PATCH 713/909] fix warnings --- coreapi/linphonecall.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5b7af9c8e..f4f596807 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2368,17 +2368,14 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse 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); } 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,(MediaStream*)call->audiostream,(MediaStream*)call->videostream); ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); From 21f419d2ee016323f5d3e380b1a5934ad9e694ff Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 24 Sep 2013 23:59:37 +0200 Subject: [PATCH 714/909] fix unimplemented RTCP setup in belle-sip sal --- coreapi/bellesip_sal/sal_op_call.c | 3 ++- tester/marie_rc | 2 +- tester/pauline_rc | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 5f7a53789..66aaa4890 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -72,11 +72,12 @@ static void sdp_process(SalOp *h){ h->result->bandwidth=h->base.remote_media->bandwidth; for(i=0;iresult->n_active_streams;++i){ - /*fixme add rtcp*/ strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); + h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; if (h->result->streams[i].proto == SalProtoRtpSavp) { h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; diff --git a/tester/marie_rc b/tester/marie_rc index 56c96bc98..e221f6fad 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -30,7 +30,7 @@ subscribe=0 [rtp] audio_rtp_port=8070 -video_rtp_port=8072 +video_rtp_port=9072 [video] display=0 diff --git a/tester/pauline_rc b/tester/pauline_rc index 4ff876cf7..1589d2cdb 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -29,7 +29,7 @@ dial_escape_plus=0 [rtp] audio_rtp_port=8090 -video_rtp_port=8092 +video_rtp_port=9092 [video] display=0 From 732787687a00a75f4d4cfc98bd367472476c153f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Sep 2013 12:00:06 +0200 Subject: [PATCH 715/909] do not send body in PUBLISH with expires 0 do not send body in SUBSCRIBE for presence with expires 0 --- coreapi/bellesip_sal/sal_op_presence.c | 28 +++++++++++++++----------- coreapi/bellesip_sal/sal_op_publish.c | 9 +++++++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 2163831a5..836cc11c6 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -24,24 +24,28 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo char *content = NULL; size_t content_length; - 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); - if (content == NULL) { + if (presence){ + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t); + contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content); ms_free(contact_info); - return; + if (content == NULL) return; } belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) - ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + 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(contact_info); - ms_free(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){ diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index f7788808c..196167095 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -56,6 +56,11 @@ void sal_op_publish_fill_cbs(SalOp*op) { 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; @@ -77,7 +82,7 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire /*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),presence); + sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? presence : NULL); return belle_sip_refresher_refresh(op->refresher,expires); } } @@ -103,7 +108,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna 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),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); } } From a6afcf99fb2fa6dbf1a2a040767fba99ad7e35e3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Sep 2013 12:07:44 +0200 Subject: [PATCH 716/909] JNI fixes --- coreapi/linphonecore_jni.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d647b94c1..5e1699900 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -646,7 +646,7 @@ public: ,jevent ,jstate ); - if (state==LinphoneSubscriptionTerminated || state==LinphoneSubscriptionError){ + if (state==LinphoneSubscriptionTerminated){ /*loose the java reference */ linphone_event_set_user_data(ev,NULL); env->DeleteGlobalRef(jevent); From 1a66f2b27884d7ef837479b65fbed7f7ff4af51a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Sep 2013 16:35:50 +0200 Subject: [PATCH 717/909] fix orders of inclusion --- console/Makefile.am | 11 ++++------- mediastreamer2 | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/console/Makefile.am b/console/Makefile.am index e844d9886..84e0c94cd 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -3,20 +3,17 @@ AM_CPPFLAGS=\ -I$(top_srcdir) \ -I$(top_srcdir)/coreapi \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/exosip + -I$(top_srcdir)/include COMMON_CFLAGS=\ -DIN_LINPHONE \ - -DENABLE_TRACE \ -D_ORTP_SOURCE \ $(STRICT_OPTIONS) \ + $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(VIDEO_CFLAGS) \ $(READLINE_CFLAGS) \ - $(OSIP_CFLAGS) \ - $(ORTP_CFLAGS) \ - $(SQLITE3_CFLAGS) \ - $(MEDIASTREAMER_CFLAGS) + $(SQLITE3_CFLAGS) if BUILD_CONSOLE diff --git a/mediastreamer2 b/mediastreamer2 index 5003385d5..8097db23c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5003385d52f715b60772da879b4655463890ffd1 +Subproject commit 8097db23c50a476593cf912f0c554ca4e391c7e3 From 1e7fa4950ec6b5336731089f74c80d08903379a4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Sep 2013 17:23:45 +0200 Subject: [PATCH 718/909] unPUBLISH cleanups --- coreapi/proxy.c | 6 ++++++ gtk/propertybox.c | 51 +++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 560c2e759..c13ed896f 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -245,6 +245,12 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ * linphone_proxy_config_done() to commit the changes. **/ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ + if (obj->publish && obj->publish_op){ + /*unpublish*/ + sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL); + sal_op_release(obj->publish_op); + obj->publish_op=NULL; + } if (obj->reg_sendregister){ /* unregister */ if (obj->state == LinphoneRegistrationOk diff --git a/gtk/propertybox.c b/gtk/propertybox.c index ac4adc2b9..b536edfd3 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -89,29 +89,29 @@ void linphone_gtk_update_my_contact(GtkWidget *w){ } void linphone_gtk_update_my_port(GtkWidget *w){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(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")); + 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); - } - } + 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); + 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; @@ -119,12 +119,12 @@ void linphone_gtk_update_my_port(GtkWidget *w){ } 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.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.tcp_port = 0; tr.tls_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); } @@ -878,11 +878,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 *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); + 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) { @@ -1001,7 +1001,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); } @@ -1206,8 +1205,8 @@ void linphone_gtk_fixed_video_port_toggle(void) { void linphone_gtk_edit_tunnel_closed(GtkWidget *button){ - GtkWidget *pb=gtk_widget_get_toplevel(button); - gtk_widget_destroy(pb); + GtkWidget *pb=gtk_widget_get_toplevel(button); + gtk_widget_destroy(pb); } void linphone_gtk_edit_tunnel(GtkButton *button){ From 643dc7f9f6c6b7d542a6e1724f943f97e0c0a9ca Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 26 Sep 2013 10:58:24 +0200 Subject: [PATCH 719/909] make sure call_tester compile even if VIDEO_ENABLED not defined --- tester/call_tester.c | 45 +++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index fcffbcc56..df88321b6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -634,6 +634,7 @@ static void call_paused_resumed_from_callee(void) { linphone_core_manager_destroy(pauline); } + #ifdef VIDEO_ENABLED static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { LinphoneVideoPolicy caller_policy; @@ -682,28 +683,7 @@ static void call_with_video_added(void) { linphone_core_manager_destroy(pauline); } -static void call_with_media_relay(void) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); - linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); - CU_ASSERT_TRUE(call(pauline,marie)); - check_rtcp(pauline,marie); -#ifdef VIDEO_ENABLED - CU_ASSERT_TRUE(add_video(pauline,marie)); - check_rtcp(pauline,marie); -#endif - - /*just to sleep*/ - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); - -} static void call_with_declined_video(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -772,8 +752,31 @@ static void video_call(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +#endif /*VIDEO_ENABLED*/ + +static void call_with_media_relay(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + CU_ASSERT_TRUE(call(pauline,marie)); + check_rtcp(pauline,marie); + +#ifdef VIDEO_ENABLED + CU_ASSERT_TRUE(add_video(pauline,marie)); + check_rtcp(pauline,marie); #endif + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + static void call_with_privacy(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); From f8bc426a1988bb2505ccf58d546cc8b2a4aa1e6e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 27 Sep 2013 08:48:45 +0200 Subject: [PATCH 720/909] * improved documentation * update ms2 * javascript generator in progress --- coreapi/linphonecore.h | 59 ++++++++-------- coreapi/linphonepresence.h | 124 +++++++++++++++++----------------- coreapi/proxy.c | 31 +-------- mediastreamer2 | 2 +- tools/generator.cc | 135 ++++++++++++++++++++++++++++++++----- tools/generator.hh | 3 + tools/genwrappers.cc | 29 ++++++-- tools/software-desc.hh | 72 +++++++++++++++++++- 8 files changed, 314 insertions(+), 141 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fcf04e2c7..638f50a64 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -535,7 +535,7 @@ LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs); LINPHONE_PUBLIC LinphoneCore *linphone_call_get_core(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call); bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); -LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); +LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(LinphoneCore *lc); LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); LINPHONE_PUBLIC char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); @@ -694,7 +694,7 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProx LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); -struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); +LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); @@ -744,7 +744,7 @@ LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const Linp **/ typedef struct _LinphoneAccountCreator{ - struct _LinphoneCore *lc; + LinphoneCore *lc; struct _SipSetupContext *ssctx; char *username; char *password; @@ -755,7 +755,7 @@ typedef struct _LinphoneAccountCreator{ bool_t succeeded; }LinphoneAccountCreator; -LinphoneAccountCreator *linphone_account_creator_new(struct _LinphoneCore *core, const char *type); +LinphoneAccountCreator *linphone_account_creator_new(LinphoneCore *core, const char *type); void linphone_account_creator_set_username(LinphoneAccountCreator *obj, const char *username); void linphone_account_creator_set_password(LinphoneAccountCreator *obj, const char *password); void linphone_account_creator_set_domain(LinphoneAccountCreator *obj, const char *domain); @@ -920,33 +920,38 @@ typedef enum _LinphoneGlobalState{ const char *linphone_global_state_to_string(LinphoneGlobalState gs); +/** + * Global state notification callback. + * @param lc + * @param gstate the global state + * @param message informational message. + */ +typedef void (*LinphoneGlobalStateCb)(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); /**Call state notification callback prototype*/ -typedef void (*LinphoneGlobalStateCb)(struct _LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); -/**Call state notification callback prototype*/ -typedef void (*LinphoneCallStateCb)(struct _LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); +typedef void (*LinphoneCallStateCb)(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); /**Call encryption changed callback prototype*/ -typedef void (*CallEncryptionChangedCb)(struct _LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); +typedef void (*CallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); /** @ingroup Proxies * Registration state notification callback prototype * */ -typedef void (*LinphoneRegistrationStateCb)(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); +typedef void (*LinphoneRegistrationStateCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); /** Callback prototype */ -typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc); +typedef void (*ShowInterfaceCb)(LinphoneCore *lc); /** Callback prototype */ -typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); +typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message); /** Callback prototype */ -typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); +typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message); /** Callback prototype */ -typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, const char *url); +typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url); /** Callback prototype */ -typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data); +typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data); /** * Report status change for a friend previously \link linphone_core_add_friend() added \endlink to #LinphoneCore. * @param lc #LinphoneCore object . * @param lf Updated #LinphoneFriend . */ -typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * lf); +typedef void (*NotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneFriend * lf); /** * Reports that a new subscription request has been received and wait for a decision. *
Status on this subscription request is notified by \link linphone_friend_set_inc_subscribe_policy() changing policy \endlink for this friend @@ -955,11 +960,11 @@ typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFrien * @param url of the subscriber * Callback prototype * */ -typedef void (*NewSubscribtionRequestCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url); +typedef void (*NewSubscribtionRequestCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); /** Callback prototype */ -typedef void (*AuthInfoRequestedCb)(struct _LinphoneCore *lc, const char *realm, const char *username); +typedef void (*AuthInfoRequestedCb)(LinphoneCore *lc, const char *realm, const char *username); /** Callback prototype */ -typedef void (*CallLogUpdatedCb)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl); +typedef void (*CallLogUpdatedCb)(LinphoneCore *lc, struct _LinphoneCallLog *newcl); /** * Callback prototype * @deprecated use #MessageReceived instead. @@ -980,24 +985,24 @@ typedef void (*TextMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, typedef void (*MessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); /** Callback prototype */ -typedef void (*DtmfReceivedCb)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); +typedef void (*DtmfReceivedCb)(LinphoneCore* lc, LinphoneCall *call, int dtmf); /** Callback prototype */ -typedef void (*ReferReceivedCb)(struct _LinphoneCore *lc, const char *refer_to); +typedef void (*ReferReceivedCb)(LinphoneCore *lc, const char *refer_to); /** Callback prototype */ -typedef void (*BuddyInfoUpdatedCb)(struct _LinphoneCore *lc, LinphoneFriend *lf); +typedef void (*BuddyInfoUpdatedCb)(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 (*LinphoneTransferStateChangedCb)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); +typedef void (*LinphoneTransferStateChangedCb)(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); /** Callback prototype for receiving quality statistics for calls*/ -typedef void (*CallStatsUpdatedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); +typedef void (*CallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); /** Callback prototype for receiving info messages*/ -typedef void (*LinphoneInfoReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +typedef void (*LinphoneInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); /** * This structure holds all callbacks that the application should implement. * None is mandatory. **/ -typedef struct _LinphoneVTable{ - LinphoneGlobalStateCb global_state_changed; /**lc=lc; linphone_proxy_config_done(obj); } + LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *ret=NULL; LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); @@ -312,38 +312,13 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ } #endif //BUILD_UPNP -#ifndef USE_BELLESIP - if(localip == NULL) { - char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'}; - localip = localip_tmp; - linphone_core_get_local_ip(obj->lc,host,localip_tmp); - } - if(localport == -1) { - localport = linphone_core_get_sip_port(obj->lc); - } - { - LCSipTransports tr; - linphone_core_get_sip_transports(obj->lc,&tr); - if (tr.udp_port <= 0) { - if (tr.tcp_port>0) { - sal_address_set_param(contact,"transport","tcp"); - } else if (tr.tls_port>0) { - sal_address_set_param(contact,"transport","tls"); - } - } - } -#endif linphone_address_set_port(contact,localport); linphone_address_set_domain(contact,localip); linphone_address_set_display_name(contact,NULL); -#ifndef USE_BELLESIP - ret = linphone_address_as_string(contact); - linphone_address_destroy(contact); -#else ret=contact; -#endif /*USE_BELLESIP*/ + linphone_address_destroy (proxy); ms_free(tmp); } diff --git a/mediastreamer2 b/mediastreamer2 index 8097db23c..dbe587475 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8097db23c50a476593cf912f0c554ca4e391c7e3 +Subproject commit dbe58747533b5e2b3e3c25009f483158e2b0cde9 diff --git a/tools/generator.cc b/tools/generator.cc index dddefb09a..1d0511162 100644 --- a/tools/generator.cc +++ b/tools/generator.cc @@ -28,6 +28,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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(){ } @@ -42,17 +50,25 @@ void CplusplusGenerator::generate(Project *proj){ for_each(classes.begin(),classes.end(),bind1st(mem_fun(&CplusplusGenerator::writeClass),this)); } +void CplusplusGenerator::writeEnumMember(ConstField *cf, bool isLast){ + writeTabs(1); + mOutfile<getName(); + if (!isLast) mOutfile<<","; + if (!cf->getHelp().empty()) mOutfile<<"\t/**< "<getHelp()<<" */"; + mOutfile<getType()!=Type::Class) return; filename<getName()<<"/"<getName()<<".hh"; mOutfile.open(filename.str().c_str()); if (!mOutfile.is_open()){ cerr<<"Could not write into "< &methods=klass->getMethods(); + list methods=klass->getMethods(); + list constFields=klass->getConstFields(); mCurClass=klass; mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<getName().empty()) mOutfile<<"namespace "<getName()<<"{"<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()< classes=proj->getClasses(); mCurProj=proj; #ifndef WIN32 - unlink(proj->getName().c_str()); - mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); + 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(proj->getName().c_str()); + _mkdir(to_lower(proj->getName()).c_str()); #endif - for_each(classes.begin(),classes.end(),bind1st(mem_fun(&JavascriptGenerator::writeClass),this)); -} - -void JavascriptGenerator::writeClass(Class *klass){ ostringstream filename; - if (klass->getType()!=Type::Class) return; - filename<getName()<<"/"<getName()<<".js"; + /*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()<<" = {};"<getType()!=Type::Enum) return; + + ostringstream filename; + list members=klass->getConstFields(); + list::iterator it; + string enum_name=klass->getName(); + int value=0; + + 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()); + } + + filename<getName())<<"/"<getName()<<" = "<getName()<<" || {};"<getHelp(),0); + mOutfile<getName()<<"."<getHelp().empty()){ + writeTabs(1); + mOutfile<<"/**"<getHelp(),1); + mOutfile<getName().substr(prefix_size,string::npos)<<" : "<getType()==Type::Enum) { + return; + } + + filename<getName())<<"/"<getName())<<".js"; mOutfile.open(filename.str().c_str()); if (!mOutfile.is_open()){ cerr<<"Could not write into "< &methods=klass->getMethods(); mCurClass=klass; mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"< &methods=klass->getMethods(); + //if (!mCurProj->getName().empty()) // mOutfile<<"namespace "<getName()<<"{"<100 && comment[i]==' ')){ mOutfile<getName()=="userData" || prop->getName()=="userPointer") return; mOutfile<<"/**"<getHelp(),0); mOutfile<getClass(name); + klass->setHelp(node.getChild("detaileddescription").getChild("para").getText()); + list enumValues=node.getChildren("enumvalue"); + list::iterator it; + for (it=enumValues.begin();it!=enumValues.end();++it){ + ConstField *cf=new ConstField(Type::getType("int"),(*it).getChild("name").getText()); + cf->setHelp((*it).getChild("detaileddescription").getChild("para").getText()); + klass->addConstField(cf); + + } + +} + static void parseTypedef(Project *proj, xmlNode *node){ XmlNode tdef(node); string typecontent=tdef.getChild("type").getText(); @@ -278,6 +294,8 @@ static void parseMemberDef(Project *proj, xmlNode *node){ parseFunction(proj,node); }else if (kind=="typedef"){ parseTypedef(proj,node); + }else if (kind=="enum"){ + parseEnum(proj,node); } } @@ -321,7 +339,7 @@ static int parse_file(Project *proj, const char *filename){ int main(int argc, char *argv[]){ int i; - Project *proj=new Project(); + string projectName="wrapper"; OutputGenerator *gen=NULL; list files; list::iterator it; @@ -330,15 +348,18 @@ int main(int argc, char *argv[]){ for(i=1;i file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]); return -1; - }if (strcmp(argv[i],"--output")==0){ + }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]); } @@ -348,7 +369,7 @@ int main(int argc, char *argv[]){ cerr<<"No output generator selected !"< fields){ + if (fields.size()<2) return ""; + list::iterator it; + string prefix=fields.front()->getName(); + int prefixsize; + + for (prefixsize=prefix.size();prefixsize>0;prefixsize--){ + bool isMatching=true; + prefix=prefix.substr(0,prefixsize); + + for(it=fields.begin();it!=fields.end();++it){ + ConstField *cf=*it; + if (prefix != cf->getName().substr(0,prefixsize)){ + isMatching=false; + break; + } + } + if (isMatching){ + cout<<"enum prefix: "< +struct name_matcher{ + name_matcher(const string &name) : mName(name){} + bool operator()(_type *cf){ + return cf->getName()==mName; + } + string mName; +}; + /*actually a class or an enum*/ class Class{ public: @@ -282,10 +341,15 @@ public: if (mMethods.find(method->getName())==mMethods.end()) mMethods.insert(make_pair(method->getName(),method)); } + void addConstField(ConstField *field){ + list::iterator it=find_if(mConstFields.begin(),mConstFields.end(),name_matcher(field->getName())); + if (it==mConstFields.end()) + mConstFields.push_back(field); + } void setHelp(const std::string &help){ mHelp=help; } - const list getMethods()const{ + list getMethods()const{ list ret; map::const_iterator it; for(it=mMethods.begin();it!=mMethods.end();++it){ @@ -293,13 +357,16 @@ public: } return ret; } + const list &getConstFields()const{ + return mConstFields; + } const string &getName()const{ return mName; } const string &getHelp()const{ return mHelp; } - const list getProperties(){ + list getProperties(){ list ret; map::const_iterator it; for(it=mProperties.begin();it!=mProperties.end();++it){ @@ -333,6 +400,7 @@ public: private: map mMethods; map mProperties; + list mConstFields; string mName; string mHelp; }; From 573f530569b425130b69b29c202bc13d32839e88 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 27 Sep 2013 11:41:15 +0200 Subject: [PATCH 721/909] remove all getaddrinfo() blocking calls from coreapi. Stun server is resolved asynchronously. --- coreapi/bellesip_sal/sal_impl.c | 8 +++ coreapi/linphonecore.c | 22 +++++- coreapi/misc.c | 121 +++++++++++++++++++++++--------- coreapi/private.h | 6 +- include/sal/sal.h | 6 ++ 5 files changed, 126 insertions(+), 37 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 2bc14ed21..f5235c808 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -840,3 +840,11 @@ void sal_enable_test_features(Sal*ctx, bool_t enabled){ ctx->enable_test_features=enabled; } +unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){ + return belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data); +} + +void sal_resolve_cancel(Sal *sal, unsigned long id){ + belle_sip_stack_resolve_cancel(sal->stack,id); +} + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 308e6b425..b37e90936 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4396,6 +4396,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); } @@ -4404,6 +4415,7 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ return lc->net_conf.stun_server; } + bool_t linphone_core_upnp_available(){ #ifdef BUILD_UPNP return TRUE; @@ -4467,7 +4479,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) if (lc->net_conf.nat_address==NULL) return NULL; - if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len)<0) { + if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) { return lc->net_conf.nat_address; } @@ -5399,7 +5411,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); @@ -5677,6 +5693,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu 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) { diff --git a/coreapi/misc.c b/coreapi/misc.c index 2da9806cd..b23a36b61 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -424,31 +424,38 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad return 0; } -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){ - struct addrinfo hints,*res=NULL; - int family = PF_INET; - int port_int = 3478; - int ret; - char port[6]; - char host[NI_MAXHOST]; +int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){ + char tmphost[NI_MAXHOST]={0}; char *p1, *p2; - if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) { - family = PF_INET6; + + if ((sscanf(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) { + } else { - p1 = strchr(server, ':'); - p2 = strrchr(server, ':'); - if (p1 && p2 && (p1 != p2)) { - family = PF_INET6; - host[NI_MAXHOST-1]='\0'; - strncpy(host, server, sizeof(host) - 1); - } else if (sscanf(server, "%[^:]:%d", host, &port_int) != 2) { - host[NI_MAXHOST-1]='\0'; - strncpy(host, server, sizeof(host) - 1); + p1 = strchr(input, ':'); + p2 = strrchr(input, ':'); + if (p1 && p2 && (p1 != p2)) {/* an ipv6 address without port*/ + strncpy(tmphost, input, sizeof(tmphost) - 1); + } else if (sscanf(input, "%[^:]:%d", tmphost, port) != 2) { + /*no port*/ + strncpy(tmphost, input, sizeof(tmphost) - 1); } } + strncpy(host,tmphost,hostlen); + return 0; +} + +int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port){ + struct addrinfo hints,*res=NULL; + char port[6]; + char host[NI_MAXHOST]; + int port_int=default_port; + int ret; + + linphone_parse_host_port(server,host,sizeof(host),&port_int); + snprintf(port, sizeof(port), "%d", port_int); memset(&hints,0,sizeof(hints)); - hints.ai_family=family; + hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; ret=getaddrinfo(host,port,&hints,&res); @@ -495,8 +502,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ return -1; } if (server!=NULL){ - struct sockaddr_storage ss; - socklen_t ss_len; + const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); ortp_socket_t sock1=-1, sock2=-1; int loops=0; bool_t video_enabled=linphone_core_video_enabled(lc); @@ -506,8 +512,8 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ double elapsed; int ret=0; - if (parse_hostname_to_addr(server,&ss,&ss_len)<0){ - ms_error("Fail to parser stun server address: %s",server); + if (ai==NULL){ + ms_error("Could not obtain stun server addrinfo."); return -1; } if (lc->vtable.display_status!=NULL) @@ -528,11 +534,11 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ int id; if (loops%20==0){ ms_message("Sending stun requests..."); - sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE); - sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE); + sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,11,TRUE); + sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,1,FALSE); if (sock2!=-1){ - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE); - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE); + sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,22,TRUE); + sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE); } } ms_usleep(10000); @@ -616,13 +622,60 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone } } +static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addrinfo *addrinfo){ + if (lc->net_conf.stun_addrinfo){ + freeaddrinfo(lc->net_conf.stun_addrinfo); + lc->net_conf.stun_addrinfo=NULL; + } + if (addrinfo){ + ms_message("Stun server resolution successful."); + }else{ + ms_warning("Stun server resolution failed."); + } + lc->net_conf.stun_addrinfo=addrinfo; + lc->net_conf.stun_res_id=0; +} +void linphone_core_resolve_stun_server(LinphoneCore *lc){ + const char *server=lc->net_conf.stun_server; + if (lc->sal && server){ + char host[NI_MAXHOST]; + int port=3478; + linphone_parse_host_port(server,host,sizeof(host),&port); + lc->net_conf.stun_res_id=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc); + } +} + +/* + * This function returns the addrinfo representation of the stun server address. + * It is critical not to block for a long time if it can't be resolved, otherwise this stucks the main thread when making a call. + * On the contrary, a fully asynchronous call initiation is complex to develop. + * The compromise is then: + * - have a cache of the stun server addrinfo + * - this cached value is returned when it is non-null + * - an asynchronous resolution is asked each time this function is called to ensure frequent refreshes of the cached value. + * - if no cached value exists, block for a short time; this case must be unprobable because the resolution will be asked each time the stun server value is + * changed. +**/ +const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){ + const char *server=linphone_core_get_stun_server(lc); + if (server){ + int wait_ms=0; + int wait_limit=1000; + linphone_core_resolve_stun_server(lc); + while (!lc->net_conf.stun_addrinfo && lc->net_conf.stun_res_id!=0 && wait_mssal); + ms_usleep(50000); + wait_ms+=50; + } + } + return lc->net_conf.stun_addrinfo; +} int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { char local_addr[64]; - struct sockaddr_storage ss; - socklen_t ss_len; + const struct addrinfo *ai; IceCheckList *audio_check_list; IceCheckList *video_check_list; const char *server = linphone_core_get_stun_server(lc); @@ -636,16 +689,16 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_warning("stun support is not implemented for ipv6"); return -1; } - - if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) { - ms_error("Fail to parser stun server address: %s", server); + ai=linphone_core_get_stun_server_addrinfo(lc); + if (ai==NULL){ + ms_warning("Fail to resolve STUN server for ICE gathering."); return -1; } if (lc->vtable.display_status != NULL) lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); /* Gather local host candidates. */ - if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) { + if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { ms_error("Fail to get local ip"); return -1; } @@ -663,7 +716,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ - ice_session_gather_candidates(call->ice_session, ss, ss_len); + ice_session_gather_candidates(call->ice_session, ai->ai_addr, ai->ai_addrlen); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index 2d817f6bb..7c70a0df2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -255,7 +255,7 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen); +int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); int set_lock_file(); int get_lock_file(); int remove_lock_file(); @@ -307,6 +307,8 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt); int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_resolve_stun_server(LinphoneCore *lc); +const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params); int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call); @@ -492,6 +494,8 @@ 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; + struct addrinfo *stun_addrinfo; + unsigned long stun_res_id; char *relay; int download_bw; int upload_bw; diff --git a/include/sal/sal.h b/include/sal/sal.h index e9b20b522..596722768 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -58,6 +58,8 @@ struct SalCustomHeader; typedef struct SalCustomHeader SalCustomHeader; +struct addrinfo; + typedef enum { SalTransportUDP, /*UDP*/ SalTransportTCP, /*TCP*/ @@ -596,6 +598,10 @@ SalPrivacy sal_op_get_privacy(const SalOp* op); /*misc*/ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); +typedef void (*SalResolverCallback)(void *data, const char *name, struct addrinfo *ai_list); + +unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data); +void sal_resolve_cancel(Sal *sal, unsigned long id); 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); From b050b22924a7f7623641a82737733222bb0460c2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 27 Sep 2013 11:45:08 +0200 Subject: [PATCH 722/909] Fix issue when using email as username --- coreapi/proxy.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 65f2a3965..cafef59d0 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -277,18 +277,14 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ const char *localip = NULL; char *tmp; - LinphoneAddress *contact=linphone_address_new(obj->reg_identity); + if (obj->contact_params) - tmp=ms_strdup_printf("",linphone_address_get_username(contact) - ,linphone_address_get_domain(contact) - ,obj->contact_params); + tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params); else - tmp=ms_strdup_printf("",linphone_address_get_username(contact) - ,linphone_address_get_domain(contact)); + tmp = strdup(obj->reg_identity); - linphone_address_destroy(contact); - contact=linphone_address_new(tmp); + LinphoneAddress *contact = linphone_address_new(tmp); if (!contact) { ms_error("No valid contact_params for [%s]",linphone_address_get_domain(proxy)); return NULL; From 4c34a2c7985afd12a39352ad812a6347accf498a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Sep 2013 13:50:34 +0200 Subject: [PATCH 723/909] Build video support on x86 platform. --- build/android/Android-no-neon.mk | 5 ++--- build/android/Android.mk | 3 +++ build/android/common.mk | 12 ++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 79b58baaf..641f3140b 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -23,6 +23,7 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi include $(CLEAR_VARS) +ifeq ($(TARGET_ARCH), arm) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(_BUILD_VIDEO),1) @@ -32,6 +33,7 @@ LOCAL_SHARED_LIBRARIES += \ liblinavcore \ liblinavutil endif +endif LOCAL_MODULE := liblinphonenoneon ifeq ($(TARGET_ARCH_ABI),armeabi) @@ -40,9 +42,6 @@ endif ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_MODULE_FILENAME := liblinphonearmv7noneon endif -ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_MODULE_FILENAME := liblinphonex86 -endif include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/Android.mk b/build/android/Android.mk index 2b2389fc8..bd3fc6133 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -37,6 +37,9 @@ LOCAL_MODULE := liblinphone ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_MODULE_FILENAME := liblinphonearmv7 endif +ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_MODULE_FILENAME := liblinphonex86 +endif include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/common.mk b/build/android/common.mk index 4e6efdd7d..f5dba448c 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -184,6 +184,7 @@ 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), arm) ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) ifeq ($(BUILD_GPLV3_ZRTP),1) LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto @@ -207,6 +208,17 @@ else LOCAL_STATIC_LIBRARIES += libsrtp-static endif endif +endif +ifeq ($(TARGET_ARCH), x86) + ifeq ($(BUILD_GPLV3_ZRTP),1) + LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto + LOCAL_SHARED_LIBRARIES += libzrtpcpp + endif + + ifeq ($(BUILD_SRTP),1) + LOCAL_SHARED_LIBRARIES += libsrtp + endif +endif ifeq ($(BUILD_REMOTE_PROVISIONING),1) LOCAL_SRC_FILES += ../tools/xml2lpc.c \ From 677f1874928e256b061a97ff4273c5e4f0e1bd42 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Sep 2013 13:47:21 +0200 Subject: [PATCH 724/909] Update ffmpeg. --- build/android/Android-no-neon.mk | 49 ------------------- build/android/Android.mk | 13 ++--- .../core/LinphoneCoreFactoryImpl.java | 37 +++----------- 3 files changed, 10 insertions(+), 89 deletions(-) delete mode 100644 build/android/Android-no-neon.mk diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk deleted file mode 100644 index 641f3140b..000000000 --- a/build/android/Android-no-neon.mk +++ /dev/null @@ -1,49 +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) - -ifeq ($(TARGET_ARCH), arm) -include $(linphone-root-dir)/submodules/linphone/build/android/common.mk - -ifeq ($(_BUILD_VIDEO),1) -LOCAL_SHARED_LIBRARIES += \ - liblinavcodecnoneon \ - liblinswscale \ - liblinavcore \ - liblinavutil -endif -endif - -LOCAL_MODULE := liblinphonenoneon -ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_MODULE_FILENAME := liblinphonearmv5noneon -endif -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_MODULE_FILENAME := liblinphonearmv7noneon -endif - -include $(BUILD_SHARED_LIBRARY) - -$(call import-module,android/cpufeatures) - diff --git a/build/android/Android.mk b/build/android/Android.mk index bd3fc6133..0ed92396c 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -27,19 +27,12 @@ include $(linphone-root-dir)/submodules/linphone/build/android/common.mk ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - liblinavcodec \ - liblinswscale \ - liblinavcore \ - liblinavutil + libavcodec-linphone \ + libswscale-linphone \ + libavutil-linphone endif LOCAL_MODULE := liblinphone -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_MODULE_FILENAME := liblinphonearmv7 -endif -ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_MODULE_FILENAME := liblinphonex86 -endif include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 6c1f370ae..1269ce88b 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -39,22 +39,13 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } static { - // FFMPEG (audio/video) - loadOptionalLibrary("linavutil"); - loadOptionalLibrary("linswscale"); - loadOptionalLibrary("linavcore"); - System.loadLibrary("neon"); - - if (!hasNeonInCpuFeatures()) { - boolean noNeonLibrariesLoaded = loadOptionalLibrary("linavcodecnoneon"); - if (!noNeonLibrariesLoaded) { - loadOptionalLibrary("linavcodec"); - } - } else { - loadOptionalLibrary("linavcodec"); - } - + + // FFMPEG (audio/video) + loadOptionalLibrary("avutil-linphone"); + loadOptionalLibrary("swscale-linphone"); + loadOptionalLibrary("avcodec-linphone"); + // OPENSSL (cryptography) // lin prefix avoids collision with libs in /system/lib loadOptionalLibrary("lincrypto"); @@ -71,21 +62,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("bcg729"); //Main library - if (isArmv7()) { - if (hasNeonInCpuFeatures()) { - Log.d("linphone", "armv7 liblinphone loaded"); - System.loadLibrary("linphonearmv7"); - } else { - Log.w("linphone", "No-neon armv7 liblinphone loaded"); - System.loadLibrary("linphonearmv7noneon"); - } - } else if (Version.isX86()) { - Log.d("linphone", "No-neon x86 liblinphone loaded"); - System.loadLibrary("linphonex86"); - } else { - Log.d("linphone", "No-neon armv5 liblinphone loaded"); - System.loadLibrary("linphonearmv5noneon"); - } + System.loadLibrary("linphone"); Version.dumpCapabilities(); } From 77f196c4f7d40a173877549ea9ad841d67577a93 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 27 Sep 2013 12:26:46 +0200 Subject: [PATCH 725/909] Update ms2 submodule for video on Android x86. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index dbe587475..25d8fb443 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit dbe58747533b5e2b3e3c25009f483158e2b0cde9 +Subproject commit 25d8fb443c8bf32de3c6b13c18632e8d0e35e2ee From eb96b18767ed16d02f33ad238c293354500e91dc Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 27 Sep 2013 13:43:42 +0200 Subject: [PATCH 726/909] update ortp te prevent linphone crash with preview enabled --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index ce8c19753..6b89540de 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit ce8c19753495b4ad16a6c5df2bf2bf235443f762 +Subproject commit 6b89540de309274bb7fdf10493879dd35c2792e1 From e35670adf2c6d67d24926f2cff5d986429335a37 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 27 Sep 2013 13:56:11 +0200 Subject: [PATCH 727/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 25d8fb443..67f1cce71 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 25d8fb443c8bf32de3c6b13c18632e8d0e35e2ee +Subproject commit 67f1cce7101a43f31cc0b1f132b90b6111516bc8 From 914656c003c1533eadea058fe61e8c34246b9ca2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 27 Sep 2013 22:30:20 +0200 Subject: [PATCH 728/909] add way for linux users to choose betwen X11/Xv or GLX video renderers. --- coreapi/linphonecall.c | 5 ++-- coreapi/linphonecore.c | 9 ++---- coreapi/linphonecore.h | 3 ++ coreapi/misc.c | 19 ++++++++++++ coreapi/private.h | 1 - gtk/parameters.ui | 35 +++++++++++++++++++++- gtk/propertybox.c | 68 +++++++++++++++++++++++++++++++++++++----- mediastreamer2 | 2 +- 8 files changed, 123 insertions(+), 19 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f4f596807..3f2102445 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1372,6 +1372,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); int dscp=linphone_core_get_video_dscp(lc); + const char *display_filter=linphone_core_get_video_display_filter(lc); call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc)); if (dscp!=-1) @@ -1379,8 +1380,8 @@ void linphone_call_init_video_stream(LinphoneCall *call){ video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size); - if( lc->video_conf.displaytype != NULL) - video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype); + if (display_filter != NULL) + video_stream_set_display_filter_name(call->videostream,display_filter); video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); if (lc->rtptf){ RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b37e90936..0aad47e1c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -956,10 +956,6 @@ static void video_config_read(LinphoneCore *lc){ 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); linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0)); linphone_core_enable_self_view(lc,self_view); @@ -4622,10 +4618,11 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED if (val){ if (lc->previewstream==NULL){ + const char *display_filter=linphone_core_get_video_display_filter(lc); lc->previewstream=video_preview_new(); video_preview_set_size(lc->previewstream,lc->video_conf.vsize); - if (lc->video_conf.displaytype) - video_preview_set_display_filter_name(lc->previewstream,lc->video_conf.displaytype); + if (display_filter) + video_preview_set_display_filter_name(lc->previewstream,display_filter); if (lc->preview_window_id!=0) video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id); video_preview_start(lc->previewstream,lc->video_conf.device); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 638f50a64..1705ad2af 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1716,6 +1716,9 @@ LINPHONE_PUBLIC int linphone_core_get_audio_dscp(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); LINPHONE_PUBLIC int linphone_core_get_video_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername); + #ifdef __cplusplus } diff --git a/coreapi/misc.c b/coreapi/misc.c index b23a36b61..e88538fb3 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1283,3 +1283,22 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ return ret; } +/** + * Set the name of the mediastreamer2 filter to be used for rendering video. + * This is for advanced users of the library, mainly to workaround hardware/driver bugs. + * @ingroup media_parameters +**/ +void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filter_name){ + lp_config_set_string(lc->config,"video","displaytype",filter_name); +} + +/** + * Get the name of the mediastreamer2 filter used for rendering video. + * @ingroup media_parameters +**/ +const char *linphone_core_get_video_display_filter(LinphoneCore *lc){ + return lp_config_get_string(lc->config,"video","displaytype",NULL); +} + + + diff --git a/coreapi/private.h b/coreapi/private.h index 7c70a0df2..d8250df90 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -540,7 +540,6 @@ typedef struct video_config{ bool_t show_local; bool_t display; bool_t selfview; /*during calls*/ - const char *displaytype; }video_config_t; typedef struct ui_config diff --git a/gtk/parameters.ui b/gtk/parameters.ui index b8063792f..6624ec01c 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -1173,7 +1173,7 @@ True False - 2 + 3 2 @@ -1237,6 +1237,39 @@ 2 + + + True + False + Video output method: + right + + + 2 + 3 + GTK_EXPAND + + + + + True + False + + + + + 0 + + + + + 1 + 2 + 2 + 3 + GTK_EXPAND + + diff --git a/gtk/propertybox.c b/gtk/propertybox.c index b536edfd3..9467d109c 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -28,21 +28,35 @@ typedef enum { static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ const char **p=devices; - int i=0,active=0; - /* glade creates a combo box without list model and text renderer, - unless we fill it with a dummy text. - This dummy text needs to be removed first*/ - gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0); + int i=0,active=-1; + GtkTreeModel *model; + + + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ + /*case where combo box is created with no model*/ + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL); + }else{ + gtk_list_store_clear(GTK_LIST_STORE(model)); + /* glade creates a combo box without list model and text renderer, + unless we fill it with a dummy text. + This dummy text needs to be removed first*/ + } + for(;*p!=NULL;++p){ if ( cap==CAP_IGNORE || (cap==CAP_CAPTURE && linphone_core_sound_device_can_capture(linphone_gtk_get_core(),*p)) || (cap==CAP_PLAYBACK && linphone_core_sound_device_can_playback(linphone_gtk_get_core(),*p)) ){ gtk_combo_box_append_text(GTK_COMBO_BOX(combo),*p); - if (strcmp(selected,*p)==0) active=i; + if (selected && strcmp(selected,*p)==0) active=i; i++; } } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); + if (active!=-1) + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } void linphone_gtk_fill_video_sizes(GtkWidget *combo){ @@ -317,6 +331,16 @@ void linphone_gtk_video_size_changed(GtkWidget *w){ defs[sel].vsize); } +void linphone_gtk_video_renderer_changed(GtkWidget *w){ + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w),&iter)){ + GtkTreeModel *model=gtk_combo_box_get_model(GTK_COMBO_BOX(w)); + gchar *name; + gtk_tree_model_get(model,&iter,0,&name,-1); + linphone_core_set_video_display_filter(linphone_gtk_get_core(),name); + } +} + void linphone_gtk_ring_file_set(GtkWidget *w){ gchar *file=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w)); linphone_core_set_ring(linphone_gtk_get_core(),file); @@ -1021,6 +1045,34 @@ void linphone_gtk_fill_webcams(GtkWidget *pb){ linphone_core_get_video_device(lc),CAP_IGNORE); } +void linphone_gtk_fill_video_renderers(GtkWidget *pb){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *combo=linphone_gtk_get_widget(pb,"renderers"); + MSList *l=ms_filter_lookup_by_interface(MSFilterVideoDisplayInterface); + MSList *elem; + int i; + const char *current_renderer=linphone_core_get_video_display_filter(lc); + GtkListStore *store; + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING)); + + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo)); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",1,NULL); + + for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next,++i){ + MSFilterDesc *desc=(MSFilterDesc *)elem->data; + GtkTreeIter iter; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,desc->name,1,desc->text,-1); + if (current_renderer && strcmp(current_renderer,desc->name)==0) + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),i); + } + ms_list_free(l); + +} + void linphone_gtk_show_parameters(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); @@ -1122,7 +1174,7 @@ void linphone_gtk_show_parameters(void){ /* MUTIMEDIA CONFIG */ linphone_gtk_fill_soundcards(pb); linphone_gtk_fill_webcams(pb); - + linphone_gtk_fill_video_renderers(pb); linphone_gtk_fill_video_sizes(linphone_gtk_get_widget(pb,"video_size")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"echo_cancelation")), linphone_core_echo_cancellation_enabled(lc)); diff --git a/mediastreamer2 b/mediastreamer2 index 67f1cce71..b25b9d8c6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 67f1cce7101a43f31cc0b1f132b90b6111516bc8 +Subproject commit b25b9d8c6b48575761d2e37c4d0308bc6e93723c From 94c264f246d3339ddb2fe1e7879edc9cf07fc410 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 30 Sep 2013 11:17:42 +0200 Subject: [PATCH 729/909] fix linphonec bugs --- console/commands.c | 17 +++++++++-------- coreapi/linphonecore.h | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/console/commands.c b/console/commands.c index 1e893619d..99effcfcc 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1082,6 +1082,7 @@ lpc_cmd_proxy(LinphoneCore *lc, char *args) } else if (strcmp(arg1,"remove")==0) { + if (arg2==NULL) return 0; linphonec_proxy_remove(lc,atoi(arg2)); } else if (strcmp(arg1,"use")==0) @@ -1109,16 +1110,16 @@ lpc_cmd_proxy(LinphoneCore *lc, char *args) { if (strstr(arg2,"default")) { - proxynum=linphone_core_get_default_proxy(lc, NULL); - if ( proxynum < 0 ) { - linphonec_out("No default proxy defined\n"); - return 1; - } - linphonec_proxy_show(lc,proxynum); + proxynum=linphone_core_get_default_proxy(lc, NULL); + if ( proxynum < 0 ) { + linphonec_out("No default proxy defined\n"); + return 1; + } + linphonec_proxy_show(lc,proxynum); } else { - linphonec_proxy_show(lc, atoi(arg2)); + linphonec_proxy_show(lc, atoi(arg2)); } } else return 0; /* syntax error */ @@ -1942,7 +1943,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); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1705ad2af..e79630cfe 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -654,7 +654,6 @@ typedef enum _LinphoneRegistrationState{ * @param cs sate */ LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegistrationState cs); - LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void); LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); From 4b36523e746faa79dc8c5c3e6438bef08ffb974b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 30 Sep 2013 14:41:49 +0200 Subject: [PATCH 730/909] Update ms2 submodule for compilation fix. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b25b9d8c6..6fabaa9d0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b25b9d8c6b48575761d2e37c4d0308bc6e93723c +Subproject commit 6fabaa9d0bbae56864d624550adb7bcad8c7b9d2 From 122c5bbcbd98fc50ed0f82037b789ee272376edd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 30 Sep 2013 15:58:27 +0200 Subject: [PATCH 731/909] update ms2 for AEC improvements --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6fabaa9d0..82e27b268 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6fabaa9d0bbae56864d624550adb7bcad8c7b9d2 +Subproject commit 82e27b268f92d090149d562835438656bbb3a3ee From 77d61696240c9fc4762563c152d5f661fdb9d87e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Oct 2013 21:59:54 +0200 Subject: [PATCH 732/909] improve documentation, rationalize some callbacks name. lp-gen-wrapper functional. --- coreapi/chat.c | 4 +- coreapi/event.h | 6 +- coreapi/linphonecore.c | 4 +- coreapi/linphonecore.h | 197 ++++++++++++++++++++++++++--------------- coreapi/private.h | 4 +- tools/generator.cc | 90 ++++++++++++++----- tools/generator.hh | 6 +- tools/genwrappers.cc | 89 ++++++++++++++++++- tools/software-desc.cc | 3 + tools/software-desc.hh | 35 ++++++-- 10 files changed, 328 insertions(+), 110 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 539e552cd..71ff7c423 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -314,7 +314,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2( * @param ud user data for the status cb. * @note The LinphoneChatMessage must not be destroyed until the the callback is called. */ -void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb, void* ud) { +void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb, void* ud) { msg->cb=status_cb; msg->cb_ud=ud; msg->state=LinphoneChatMessageStateInProgress; @@ -329,7 +329,7 @@ const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle"; case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress"; case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered"; - case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; + case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; default: return "Unknown state"; } diff --git a/coreapi/event.h b/coreapi/event.h index fa97c2387..8f9f8e6bd 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -89,17 +89,17 @@ LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishStat /** * Callback prototype for notifying the application about notification received from the network. **/ -typedef void (*LinphoneEventIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); +typedef void (*LinphoneCoreIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); /** * Callback prototype for notifying the application about changes of subscription states, including arrival of new subscriptions. **/ -typedef void (*LinphoneSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); +typedef void (*LinphoneCoreSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); /** * Callback prototype for notifying the application about changes of publish states. **/ -typedef void (*LinphonePublishStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); +typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); /** * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body. diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0aad47e1c..920336858 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -376,7 +376,7 @@ float linphone_call_log_get_quality(LinphoneCallLog *cl){ /** * return true if video was enabled at the end of the call */ -LinphoneCallStatus linphone_call_log_video_enabled(LinphoneCallLog *cl) { +bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) { return cl->video_enabled; } /** @} */ @@ -5352,7 +5352,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; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e79630cfe..5b06847cb 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -251,7 +251,7 @@ LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl); LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl); LINPHONE_PUBLIC LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl); LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl); -LINPHONE_PUBLIC LinphoneCallStatus linphone_call_log_video_enabled(LinphoneCallLog *cl); +LINPHONE_PUBLIC bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl); LINPHONE_PUBLIC time_t linphone_call_log_get_start_date(LinphoneCallLog *cl); LINPHONE_PUBLIC int linphone_call_log_get_duration(LinphoneCallLog *cl); LINPHONE_PUBLIC float linphone_call_log_get_quality(LinphoneCallLog *cl); @@ -501,7 +501,7 @@ LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneC /** Callback prototype */ -typedef void (*LinphoneCallCbFunc)(struct _LinphoneCall *call,void * user_data); +typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); /** * LinphoneCallState enum represents the different state a call can reach into. @@ -849,7 +849,7 @@ typedef enum _LinphoneChatMessageStates { *@param status LinphoneChatMessageState *@param ud application user data */ -typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); +typedef void (*LinphoneChatMessageStateChangedCb)(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path); LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); @@ -860,7 +860,7 @@ LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneC LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg); -LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud); +LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud); LINPHONE_PUBLIC void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg); LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message); LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); @@ -925,106 +925,165 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs); * @param gstate the global state * @param message informational message. */ -typedef void (*LinphoneGlobalStateCb)(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); -/**Call state notification callback prototype*/ -typedef void (*LinphoneCallStateCb)(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); -/**Call encryption changed callback prototype*/ -typedef void (*CallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); +typedef void (*LinphoneCoreGlobalStateChangedCb )(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +/** + * Call state notification callback. + * @param lc the LinphoneCore + * @param call the call object whose state is changed. + * @param cstate the new state of the call + * @param message an informational message about the state. + */ +typedef void (*LinphoneCoreCallStateChangedCb)(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); + +/** + * Call encryption changed callback. + * @param lc the LinphoneCore + * @param call the call on which encryption is changed. + * @param on whether encryption is activated. + * @param authentication_token an authentication_token, currently set for ZRTP kind of encryption only. + */ +typedef void (*LinphoneCoreCallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); /** @ingroup Proxies * Registration state notification callback prototype * */ -typedef void (*LinphoneRegistrationStateCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); -/** Callback prototype */ +typedef void (*LinphoneCoreRegistrationStateChangedCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); +/** Callback prototype + * @deprecated + */ typedef void (*ShowInterfaceCb)(LinphoneCore *lc); -/** Callback prototype */ +/** Callback prototype + * @deprecated + */ typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message); -/** Callback prototype */ +/** Callback prototype + * @deprecated + */ typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message); -/** Callback prototype */ +/** Callback prototype + * @deprecated + */ typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url); -/** Callback prototype */ +/** Callback prototype + */ typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data); /** * Report status change for a friend previously \link linphone_core_add_friend() added \endlink to #LinphoneCore. * @param lc #LinphoneCore object . * @param lf Updated #LinphoneFriend . */ -typedef void (*NotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneFriend * lf); +typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneFriend * lf); /** * Reports that a new subscription request has been received and wait for a decision. - *
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)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -/** Callback prototype */ -typedef void (*AuthInfoRequestedCb)(LinphoneCore *lc, const char *realm, const char *username); -/** Callback prototype */ -typedef void (*CallLogUpdatedCb)(LinphoneCore *lc, struct _LinphoneCallLog *newcl); + */ +typedef void (*LinphoneCoreNewSubscribtionRequestCb)(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); + +/** + * Callback to notify a new call-log entry has been added. + * This is done typically when a call terminates. + * @param lc the LinphoneCore + * @param newcl the new call log entry added. + */ +typedef void (*LinphoneCoreCallLogUpdatedCb)(LinphoneCore *lc, LinphoneCallLog *newcl); + /** * Callback prototype - * @deprecated use #MessageReceived instead. + * @deprecated use #LinphoneMessageReceived instead. * * @param lc #LinphoneCore object * @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room. * @param from #LinphoneAddress from * @param message incoming message - * */ -typedef void (*TextMessageReceivedCb)(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 (*MessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); + */ +typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); -/** Callback prototype */ -typedef void (*DtmfReceivedCb)(LinphoneCore* lc, LinphoneCall *call, int dtmf); -/** Callback prototype */ -typedef void (*ReferReceivedCb)(LinphoneCore *lc, const char *refer_to); -/** Callback prototype */ -typedef void (*BuddyInfoUpdatedCb)(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 (*LinphoneTransferStateChangedCb)(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); -/** Callback prototype for receiving quality statistics for calls*/ -typedef void (*CallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); +/** + * 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 (*LinphoneCoreReferReceivedCb)(LinphoneCore *lc, const char *refer_to); +/** Callback prototype */ +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); -/** Callback prototype for receiving info messages*/ -typedef void (*LinphoneInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); /** * This structure holds all callbacks that the application should implement. * None is mandatory. **/ typedef struct _LinphoneCoreVTable{ - LinphoneGlobalStateCb global_state_changed; /** A text message has been received */ + LinphoneCoreTextMessageReceivedCb text_received; /** @deprecated, use #message_received instead
A text message has been received */ } LinphoneCoreVTable; /** @@ -1052,7 +1111,7 @@ typedef enum _LinphoneWaitingState{ LinphoneWaitingProgress, LinphoneWaitingFinished } LinphoneWaitingState; -typedef void * (*LinphoneWaitingCallback)(LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress); +typedef void * (*LinphoneCoreWaitingCallback)(LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress); /* THE main API */ @@ -1598,7 +1657,7 @@ the config file with your own sections */ LINPHONE_PUBLIC struct _LpConfig *linphone_core_get_config(LinphoneCore *lc); /*set a callback for some blocking operations, it takes you informed of the progress of the operation*/ -void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context); +void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneCoreWaitingCallback cb, void *user_context); /*returns the list of registered SipSetup (linphonecore plugins) */ const MSList * linphone_core_get_sip_setups(LinphoneCore *lc); @@ -1606,15 +1665,15 @@ 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; diff --git a/coreapi/private.h b/coreapi/private.h index d8250df90..191105a09 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -131,7 +131,7 @@ struct _LinphoneChatMessage { LinphoneChatRoom* chat_room; LinphoneChatMessageDir dir; char* message; - LinphoneChatMessageStateChangeCb cb; + LinphoneChatMessageStateChangedCb cb; void* cb_ud; void* message_userdata; char* external_body_url; @@ -614,7 +614,7 @@ struct _LinphoneCore char *rec_file; time_t prevtime; int audio_bw; - LinphoneWaitingCallback wait_cb; + LinphoneCoreWaitingCallback wait_cb; void *wait_ctx; unsigned long video_window_id; unsigned long preview_window_id; diff --git a/tools/generator.cc b/tools/generator.cc index 1d0511162..b03c907f6 100644 --- a/tools/generator.cc +++ b/tools/generator.cc @@ -147,6 +147,8 @@ void CplusplusGenerator::writeHelpComment(const std::string &comment, int ntabs) } void CplusplusGenerator::writeMethod(Method *method){ + if (method->isCallback()) return; + Argument *retarg=method->getReturnArg(); const list &args=method->getArgs(); list::const_iterator it; @@ -204,20 +206,24 @@ void JavascriptGenerator::generate(Project *proj){ for_each(classes.begin(),classes.end(),bind1st(mem_fun(&JavascriptGenerator::writeClass),this)); } +string JavascriptGenerator::getEnumName(Class *klass){ + string enum_name=klass->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=klass->getName(); + string enum_name=getEnumName(klass); int value=0; - 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()); - } - filename<getName())<<"/"<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()); @@ -273,9 +281,6 @@ void JavascriptGenerator::writeClass(Class *klass){ mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"< &methods=klass->getMethods(); - //if (!mCurProj->getName().empty()) // mOutfile<<"namespace "<getName()<<"{"<getName().empty()) // mOutfile<<"} //end of namespace "<getName()<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, bool isReturn){ - if (!isReturn){ - mOutfile<<" * @param {"; - writeType(arg->getType()); - mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); - mOutfile<<"} "<getHelp()<getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); + mOutfile<<"} "<getHelp()<getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()< &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; @@ -379,7 +399,37 @@ void JavascriptGenerator::writeMethod(Method *method){ for(it=args.begin();it!=args.end();++it){ writeArgument(*it); } - writeArgument(retarg,true); + writeArgument(retarg,Return); mOutfile<<"**/"< &args=event->getArgs(); + list::const_iterator it; + + if (!event->isCallback()) return; + mOutfile<<"/**"<getHelp()),0); + mOutfile<getName()<<"#"<getName()<getType()->getBasicType()!=Type::Class) return; @@ -250,6 +250,84 @@ static void parseFunction(Project *proj, xmlNode *node){ } } +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); @@ -272,9 +350,8 @@ static void parseTypedef(Project *proj, xmlNode *node){ string name=tdef.getChild("name").getText(); if (typecontent.find("enum")==0){ Type::addType(Type::Enum,name); - }else if (typecontent.find("void(*")==0){ - // callbacks function, not really well parsed by doxygen - Type::addType(Type::Callback,name); + }else if (typecontent.find("(*")!=string::npos){ + parseCallback(proj,node); }else proj->getClass(name)->setHelp(getHelpBody(node)); } @@ -288,6 +365,10 @@ static void parseMemberDef(Project *proj, xmlNode *node){ 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"){ diff --git a/tools/software-desc.cc b/tools/software-desc.cc index d0a4ae77b..7930cb289 100644 --- a/tools/software-desc.cc +++ b/tools/software-desc.cc @@ -25,6 +25,8 @@ Type Type::sIntegerType(Type::Integer); Type Type::sVoidType(Type::Void); Type Type::sBooleanType(Type::Boolean); Type Type::sFloatType(Type::Float); +Type Type::sArrayType(Type::Array); + std::map Type::mTypes; const char *Type::sBasicTypeNames[]={ "Void", @@ -35,6 +37,7 @@ const char *Type::sBasicTypeNames[]={ "Enum", "Class", "Callback", + "Array", "undef", "undef" }; diff --git a/tools/software-desc.hh b/tools/software-desc.hh index 567eadfe9..f5a1a180b 100644 --- a/tools/software-desc.hh +++ b/tools/software-desc.hh @@ -44,7 +44,8 @@ public: String, Enum, Class, - Callback + Callback, + Array }; static const char *sBasicTypeNames[]; static Type* addType(BasicType bt, const string &name){ @@ -58,18 +59,23 @@ public: return ret; } static Type *getType(const std::string &tname){ + if (tname.find("(")!=string::npos) return NULL; //arrives when parsing function pointer declared inside function prototype if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ return &sStringType; - }else if (tname.find("int")==0){ + }else if (tname.find("int")!=string::npos){ return &sIntegerType; - }else if (tname.find("float")==0){ + }else if (tname.find("size_t")!=string::npos){ + return &sIntegerType; + }else if (tname.find("float")!=string::npos){ return &sFloatType; - }else if (tname.find("bool_t")==0){ + }else if (tname.find("bool_t")!=string::npos){ return &sBooleanType; }else if (tname.find("void")!=string::npos){ return &sVoidType; - }else if (tname.find("enum")==0){ + }else if (tname.find("enum")!=string::npos){ return addType(Enum,tname.c_str()+strlen("enum ")); + }else if (tname.find("MSList")!=string::npos){ + return &sArrayType; }else{/*an object?*/ string tmp=tname; @@ -109,6 +115,7 @@ private: static Type sVoidType; static Type sBooleanType; static Type sFloatType; + static Type sArrayType; static std::map mTypes; }; @@ -153,13 +160,14 @@ public: Read, Write }; - Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic){ + Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic, bool isCallback=false){ mUid=uid; mReturn=return_arg; mName=name; mArgs=args; mConst=isConst; mStatic=isStatic; + mIsCallback=isCallback; analyseProperties(); } void setHelp(const std::string &help){ @@ -180,6 +188,9 @@ public: bool isStatic()const{ return mStatic; } + bool isCallback()const{ + return mIsCallback; + } const string &getHelp(){ return mHelp; } @@ -235,6 +246,7 @@ private: PropertyBehaviour mPropertyBehaviour; bool mConst; bool mStatic; + bool mIsCallback; }; class Property{ @@ -307,7 +319,7 @@ public: } } if (isMatching){ - cout<<"enum prefix: "< classes=getClasses(); for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); } + void addCallback(Method *callback){ + list::iterator it=find_if(mCallbacks.begin(),mCallbacks.end(),name_matcher(callback->getName())); + if (it==mCallbacks.end()) + mCallbacks.push_back(callback); + } + const list &getCallbacks()const{ + return mCallbacks; + } private: map mClasses; + list mCallbacks; string mName; }; From 8056c59ad6e66037fb0e271c636bd48489a428e4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Oct 2013 22:04:46 +0200 Subject: [PATCH 733/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 82e27b268..ff24a844f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 82e27b268f92d090149d562835438656bbb3a3ee +Subproject commit ff24a844fb3f2345fc620d65ed1a8e7eb61eb24f From dd83a25bd762fbe64060a056ac39127c0802b345 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 2 Oct 2013 11:16:55 +0200 Subject: [PATCH 734/909] Always enable HD video. --- build/android/common.mk | 2 +- coreapi/linphonecore.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index f5dba448c..ee4832ea1 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -75,7 +75,7 @@ LOCAL_CFLAGS += \ LOCAL_CFLAGS += -DIN_LINPHONE ifeq ($(_BUILD_VIDEO),1) -LOCAL_CFLAGS += -DVIDEO_ENABLED -DENABLE_HD +LOCAL_CFLAGS += -DVIDEO_ENABLED ifeq ($(BUILD_X264),1) LOCAL_CFLAGS += -DHAVE_X264 endif diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 920336858..97f063b00 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5063,13 +5063,11 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { } static MSVideoSizeDef supported_resolutions[]={ -#ifdef ENABLE_HD { { MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H } , "1080p" }, { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, -#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" }, From a0d580ceb9d759bcff05bcb59846569dcfcf860e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Oct 2013 14:57:46 +0200 Subject: [PATCH 735/909] fix macos build issue remove useless code --- coreapi/friend.c | 12 +----------- tools/Makefile.am | 3 ++- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 7626617ba..8493cda88 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -108,17 +108,8 @@ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){ } void __linphone_friend_do_subscribe(LinphoneFriend *fr){ - char *friend=NULL; - const char *from=NULL; - LinphoneProxyConfig *cfg; LinphoneCore *lc=fr->lc; - friend=linphone_address_as_string(fr->uri); - cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); - if (cfg!=NULL){ - from=linphone_proxy_config_get_identity(cfg); - }else from=linphone_core_get_primary_contact(fr->lc); - if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ fr->presence=NULL; @@ -132,9 +123,8 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ } fr->outsub=sal_op_new(lc->sal); linphone_configure_op(lc,fr->outsub,fr->uri,NULL,TRUE); - sal_subscribe_presence(fr->outsub,from,friend,lp_config_get_int(lc->config,"sip","subscribe_expires",600)); + 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(){ diff --git a/tools/Makefile.am b/tools/Makefile.am index fb6253465..d0e6d350a 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,7 +12,8 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) -AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) +#-fpermissive to workaround a g++ bug on macos 32bit SDK. +AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) -fpermissive EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc From e8668e2e312c390e891c372e3237ba3e6a54f53a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 2 Oct 2013 15:08:51 +0200 Subject: [PATCH 736/909] Update ms2 submodule for fix of video bitrate change. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ff24a844f..a77698c85 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff24a844fb3f2345fc620d65ed1a8e7eb61eb24f +Subproject commit a77698c854a728bbee194988683e94009b8561e9 From 3878b016ab2bc97f1064b009065fd791044cb73a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 2 Oct 2013 16:05:34 +0200 Subject: [PATCH 737/909] Remove useless libneon on Android. --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 7 ------- mediastreamer2 | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 1269ce88b..bd850d1df 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -21,7 +21,6 @@ package org.linphone.core; import java.io.File; import java.io.IOException; -import org.linphone.mediastream.CpuUtils; import org.linphone.mediastream.Version; import android.util.Log; @@ -134,12 +133,6 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { return createLinphoneFriend(null); } - public static boolean hasNeonInCpuFeatures() - { - CpuUtils cpu = new CpuUtils(); - return cpu.isCpuNeon(); - } - public static boolean isArmv7() { return System.getProperty("os.arch").contains("armv7"); diff --git a/mediastreamer2 b/mediastreamer2 index a77698c85..043c6b924 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a77698c854a728bbee194988683e94009b8561e9 +Subproject commit 043c6b9244fa28ce70b3fe3f3bdb4297a0fb7afd From 2f17787d93d16609f044c18c8af43d78867ae415 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 2 Oct 2013 17:20:32 +0200 Subject: [PATCH 738/909] Recover on xml parsing error. --- tools/genwrappers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc index 96755ac56..a009a83d9 100644 --- a/tools/genwrappers.cc +++ b/tools/genwrappers.cc @@ -401,7 +401,7 @@ static int parse_file(Project *proj, const char *filename){ /*parse the file and get the DOM */ - doc = xmlReadFile(filename, NULL, 0); + doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER); if (doc == NULL) { cerr<<"xmlReadFile failed."< Date: Wed, 2 Oct 2013 17:26:24 +0200 Subject: [PATCH 739/909] install xml documentation generated by doxygen --- coreapi/help/Makefile.am | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index d9320afd3..9d35b40a4 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -10,6 +10,7 @@ if HAVE_DOXYGEN # docdir & pkgdocdir are not always defined by automake pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION) doc_htmldir=$(pkgdocdir)/html +doc_xmldir=$(pkgdocdir)/xml doc_html_DATA = $(top_builddir)/coreapi/help/doc/html/html.tar @@ -20,11 +21,21 @@ $(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 From 7d7bce3534a54a452b45d86375490a505d13975a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 3 Oct 2013 09:52:57 +0200 Subject: [PATCH 740/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 043c6b924..c29dffec2 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 043c6b9244fa28ce70b3fe3f3bdb4297a0fb7afd +Subproject commit c29dffec2d9d1b5eafdafc1da83e4e990dcbfd8a From 7bff917e4e7b105d9c047b35b1586821d8b9dc4f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 3 Oct 2013 09:57:12 +0200 Subject: [PATCH 741/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c29dffec2..d7f50cdff 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c29dffec2d9d1b5eafdafc1da83e4e990dcbfd8a +Subproject commit d7f50cdff8aefaa7bc2208edb743726bf940ff87 From ebb0699eec6237c3bb678ade660197d6230215e1 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 3 Oct 2013 16:29:17 +0200 Subject: [PATCH 742/909] Update flexisip.conf with client auth --- tester/flexisip.conf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 3a0431440..3ebbeb7be 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -18,7 +18,7 @@ auto-respawn=true # List of white space separated host names pointing to this machine. # This is to prevent loops while routing SIP messages. # Default value: localhost -aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.example.org +aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.example.org client.example.org # List of white space separated SIP uris where the proxy must listen.Wildcard # (*) can be used to mean 'all local ip addresses'. If 'transport' @@ -37,11 +37,11 @@ aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.exa # transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 # Default value: sip:* #transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 -transports=sip:*:5060 sips:*:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:*:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname +transports=sip:*:5060 sips:*:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:*:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:*:5063;require-peer-certificate=1 # An absolute path of a directory where TLS server certificate and # private key can be found, concatenated inside an 'agent.pem' file. # Default value: /etc/flexisip/tls -#tls-certificates-dir=/etc/flexisip/tls +tls-certificates-dir=/etc/flexisip/tls/certificates/cn #tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip ## @@ -135,6 +135,9 @@ filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains ' # 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= From 946bb087335a6602fcbb1ae08b6ca707653617b4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 3 Oct 2013 16:40:35 +0200 Subject: [PATCH 743/909] Name ffmpeg and linphone shared libraries according to arch ABI. --- build/android/Android.mk | 1 + .../core/LinphoneCoreFactoryImpl.java | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 0ed92396c..819b50fcb 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES += \ endif LOCAL_MODULE := liblinphone +LOCAL_MODULE_FILENAME := liblinphone-$(TARGET_ARCH_ABI) include $(BUILD_SHARED_LIBRARY) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index bd850d1df..54032a2f6 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -38,12 +38,23 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } static { - System.loadLibrary("neon"); + String eabi = "arm"; + if (Version.isX86()) { + eabi = "x86"; + } else if (Version.isArmv7()) { + eabi = "armeabi-v7a"; + } // FFMPEG (audio/video) - loadOptionalLibrary("avutil-linphone"); - loadOptionalLibrary("swscale-linphone"); - loadOptionalLibrary("avcodec-linphone"); + if (Version.isX86()) { + loadOptionalLibrary("avutil-linphone-x86"); + loadOptionalLibrary("swscale-linphone-x86"); + loadOptionalLibrary("avcodec-linphone-x86"); + } else if (Version.isArmv7()) { + loadOptionalLibrary("avutil-linphone-arm"); + loadOptionalLibrary("swscale-linphone-arm"); + loadOptionalLibrary("avcodec-linphone-arm"); + } // OPENSSL (cryptography) // lin prefix avoids collision with libs in /system/lib @@ -61,7 +72,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("bcg729"); //Main library - System.loadLibrary("linphone"); + System.loadLibrary("linphone-" + eabi); Version.dumpCapabilities(); } From 9680b2915adcb22a1d14a7c2c7b691c49fa91a3a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 3 Oct 2013 17:33:16 +0200 Subject: [PATCH 744/909] Use shared library arch ABI suffixes on Android. --- build/android/common.mk | 35 +++---------------- .../core/LinphoneCoreFactoryImpl.java | 10 +++--- oRTP | 2 +- 3 files changed, 10 insertions(+), 37 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index ee4832ea1..7e902c05e 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -184,40 +184,13 @@ 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), arm) -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto - LOCAL_SHARED_LIBRARIES += libzrtpcpp - endif - - ifeq ($(BUILD_SRTP),1) - LOCAL_SHARED_LIBRARIES += libsrtp - endif -else - LOCAL_LDLIBS += -lz - #LOCAL_STATIC_LIBRARIES += libz libdl - - ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_STATIC_LIBRARIES += libzrtpcpp-static - LOCAL_STATIC_LIBRARIES += \ - libssl-static libcrypto-static - endif - - ifeq ($(BUILD_SRTP),1) - LOCAL_STATIC_LIBRARIES += libsrtp-static - endif +ifeq ($(BUILD_GPLV3_ZRTP),1) + LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone + LOCAL_SHARED_LIBRARIES += libzrtpcpp endif -endif -ifeq ($(TARGET_ARCH), x86) - ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto - LOCAL_SHARED_LIBRARIES += libzrtpcpp - endif - ifeq ($(BUILD_SRTP),1) +ifeq ($(BUILD_SRTP),1) LOCAL_SHARED_LIBRARIES += libsrtp - endif endif ifeq ($(BUILD_REMOTE_PROVISIONING),1) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 54032a2f6..4df1bd364 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -57,13 +57,13 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } // OPENSSL (cryptography) - // lin prefix avoids collision with libs in /system/lib - loadOptionalLibrary("lincrypto"); - loadOptionalLibrary("linssl"); + // linphone suffix avoids collision with libs in /system/lib + loadOptionalLibrary("crypto-linphone-" + eabi); + loadOptionalLibrary("ssl-linphone-" + eabi); // Secure RTP and key negotiation - loadOptionalLibrary("srtp"); - loadOptionalLibrary("zrtpcpp"); // GPLv3+ + loadOptionalLibrary("srtp-" + eabi); + loadOptionalLibrary("zrtpcpp" + eabi); // GPLv3+ // Tunnel loadOptionalLibrary("tunnelclient"); diff --git a/oRTP b/oRTP index 6b89540de..890e2306f 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 6b89540de309274bb7fdf10493879dd35c2792e1 +Subproject commit 890e2306fca77146648f061ae754bec18304d4b7 From 3c772ea1fef925eef9fd665fbd6e64bcf3360274 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 3 Oct 2013 17:52:27 +0200 Subject: [PATCH 745/909] Use tunnelclient and bcg729 static libraries on Android. --- build/android/common.mk | 7 +------ java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 6 ------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/build/android/common.mk b/build/android/common.mk index 7e902c05e..c027002a4 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -111,11 +111,7 @@ 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 @@ -150,8 +146,7 @@ endif ifeq ($(BUILD_G729),1) LOCAL_CFLAGS += -DHAVE_G729 -LOCAL_SHARED_LIBRARIES += libbcg729 -LOCAL_STATIC_LIBRARIES += libmsbcg729 +LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729 endif ifeq ($(_BUILD_VIDEO),1) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 4df1bd364..b03d9ba90 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -65,12 +65,6 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("srtp-" + eabi); loadOptionalLibrary("zrtpcpp" + eabi); // GPLv3+ - // Tunnel - loadOptionalLibrary("tunnelclient"); - - // g729 A implementation - loadOptionalLibrary("bcg729"); - //Main library System.loadLibrary("linphone-" + eabi); From 03723b2225dd654c83336f1018a19f9ac7498e77 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 3 Oct 2013 22:22:05 +0200 Subject: [PATCH 746/909] fix mistake in eabi when loading libs --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index b03d9ba90..0b850c88a 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -38,7 +38,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } static { - String eabi = "arm"; + String eabi = "armeabi"; if (Version.isX86()) { eabi = "x86"; } else if (Version.isArmv7()) { From b8453d1bc16ab5bac06255bc8467bed0c60bcc3a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 4 Oct 2013 11:49:10 +0200 Subject: [PATCH 747/909] Added JNI bindings for LpConfig + extended java LpConfig --- coreapi/linphonecore_jni.cc | 95 ++++++++++++++++++- java/common/org/linphone/core/LpConfig.java | 82 +++++++++++++++- java/impl/org/linphone/core/LpConfigImpl.java | 60 +++++++++++- 3 files changed, 234 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 5e1699900..501357aed 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3034,7 +3034,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv 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); @@ -3061,6 +3061,99 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setInt(JNIEnv *env, jobject env->ReleaseStringUTFChars(key, ckey); } +extern "C" jint Java_org_linphone_core_LpConfigImpl_getInt(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int returnValue = lp_config_get_int((LpConfig *)lpc, csection, ckey, (int) defaultValue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jint) returnValue; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setFloat(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jfloat value) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_float((LpConfig *)lpc, csection, ckey, (float) value); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jfloat Java_org_linphone_core_LpConfigImpl_getFloat(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jfloat defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + float returnValue = lp_config_get_float((LpConfig *)lpc, csection, ckey, (float) defaultValue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jfloat) returnValue; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setBool(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jboolean value) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_int((LpConfig *)lpc, csection, ckey, value ? 1 : 0); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jboolean Java_org_linphone_core_LpConfigImpl_getBool(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jboolean defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int returnValue = lp_config_get_int((LpConfig *)lpc, csection, ckey, defaultValue ? 1 : 0); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jboolean) returnValue == 1; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setString(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jstring value) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + const char *cvalue = env->GetStringUTFChars(value, NULL); + lp_config_set_string((LpConfig *)lpc, csection, ckey, cvalue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + env->ReleaseStringUTFChars(value, cvalue); +} + +extern "C" jstring Java_org_linphone_core_LpConfigImpl_getString(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jstring defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + const char *cvalue = env->GetStringUTFChars(defaultValue, NULL); + const char *returnValue = lp_config_get_string((LpConfig *)lpc, csection, ckey, cvalue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + env->ReleaseStringUTFChars(defaultValue, cvalue); + return returnValue ? env->NewStringUTF(returnValue) : NULL; +} +extern "C" void Java_org_linphone_core_LpConfigImpl_setIntRange(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint min, jint max) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_range((LpConfig *)lpc, csection, ckey, min, max); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jintArray Java_org_linphone_core_LpConfigImpl_getIntRange(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint defaultmin, jint defaultmax) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int *values = (int*)calloc(2, sizeof(int)); + lp_config_get_range((LpConfig *)lpc, csection, ckey, &values[0], &values[1], defaultmin, defaultmax); + jintArray returnValues = env->NewIntArray(2); + env->SetIntArrayRegion(returnValues, 0, 2, values); + ms_free(values); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return returnValues; +} + static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content){ jclass contentClass; jmethodID ctor; 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/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); + } + } From c1968e3fd831a0e7a3c9decafac3f19a227ce921 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 4 Oct 2013 17:41:55 +0200 Subject: [PATCH 748/909] Normalize linphone_proxy_config_set_expires() name. --- console/commands.c | 2 +- coreapi/linphonecore.h | 3 ++- coreapi/linphonecore_jni.cc | 2 +- coreapi/proxy.c | 2 +- gtk/propertybox.c | 2 +- gtk/setupwizard.c | 2 +- tester/register_tester.c | 2 +- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/console/commands.c b/console/commands.c index 99effcfcc..09fc9c324 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1616,7 +1616,7 @@ linphonec_proxy_add(LinphoneCore *lc) continue; } - linphone_proxy_config_expires(cfg, expires); + linphone_proxy_config_set_expires(cfg, expires); linphonec_out("Expiration: %d seconds\n", linphone_proxy_config_get_expires (cfg)); free(input); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5b06847cb..f3c2a070d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -658,7 +658,8 @@ LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void); LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); -LINPHONE_PUBLIC void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires); +LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int expires); +#define linphone_proxy_config_expires linphone_proxy_config_set_expires /** * Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig . *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 501357aed..7a587ce83 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2600,7 +2600,7 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getState(JNIEnv* 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_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { diff --git a/coreapi/proxy.c b/coreapi/proxy.c index cafef59d0..94ea34908 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -227,7 +227,7 @@ void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){ /** * Sets the registration expiration time in seconds. **/ -void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){ +void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int val){ if (val<0) val=600; obj->expires=val; } diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 9467d109c..22c3813c4 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -738,7 +738,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){ gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); linphone_proxy_config_set_contact_parameters(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")))); - linphone_proxy_config_expires(cfg, + 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, diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index 439f9c89f..47a9074f8 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -416,7 +416,7 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page linphone_proxy_config_set_identity(cfg, creator->username); linphone_proxy_config_set_server_addr(cfg, creator->domain); linphone_proxy_config_set_route(cfg, creator->route); - linphone_proxy_config_expires(cfg, 3600); + linphone_proxy_config_set_expires(cfg, 3600); linphone_proxy_config_enable_publish(cfg, FALSE); linphone_proxy_config_enable_register(cfg, TRUE); diff --git a/tester/register_tester.c b/tester/register_tester.c index c899403be..7ec8881e0 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -87,7 +87,7 @@ static void register_with_refresh_base_3(LinphoneCore* lc server_addr = linphone_address_get_domain(from); linphone_proxy_config_enable_register(proxy_cfg,TRUE); - linphone_proxy_config_expires(proxy_cfg,1); + 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); From f779be584cb9f12a30300300a2ba5797da7637b0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 10:57:25 +0200 Subject: [PATCH 749/909] Deprecate linphone_call_is_in_conference() and linphone_proxy_config_is_registered(). --- coreapi/linphonecall.c | 4 ---- coreapi/linphonecore.h | 7 ++++--- coreapi/proxy.c | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3f2102445..103492b4f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2530,10 +2530,6 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat } } -/** - * 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; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f3c2a070d..4fc6205b4 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -573,10 +573,11 @@ LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); /** * Return TRUE if this call is currently part of a conference - *@param call #LinphoneCall - *@return TRUE if part of a conference. + * @param call #LinphoneCall + * @return TRUE if part of a conference. * - @ingroup call_control + * @deprecated + * @ingroup call_control */ LINPHONE_PUBLIC bool_t linphone_call_is_in_conference(const LinphoneCall *call); /** diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 94ea34908..fcfdc6697 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -93,6 +93,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ /** * Returns a boolean indicating that the user is sucessfully registered on the proxy. + * @deprecated Use linphone_proxy_config_get_state() instead. **/ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ return obj->state == LinphoneRegistrationOk; From 73864e11381e7105cf543a85315910f277c656db Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 10:58:20 +0200 Subject: [PATCH 750/909] Document lpconfig_read_file(). --- coreapi/lpconfig.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index aa65fb38f..869d572eb 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -88,7 +88,13 @@ LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); */ LINPHONE_PUBLIC LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); -int lp_config_read_file(LpConfig *lpconfig, const char *filename); +/** + * Reads a user config file and fill the LpConfig with the read config values. + * @ingroup misc + * @param lpconfig The LpConfig object to fill with the content of the file + * @param filename The filename of the config file to read to fill the LpConfig + */ +LINPHONE_PUBLIC int lp_config_read_file(LpConfig *lpconfig, const char *filename); /** * Retrieves a configuration item as a string, given its section, key, and default value. @@ -178,21 +184,21 @@ LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, * * @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. From d10ab0a250f311eded2b1cb5a00bf614fd176dc6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 11:20:04 +0200 Subject: [PATCH 751/909] Getter functions need to start with "get". --- coreapi/friend.c | 2 +- coreapi/linphonecore_jni.cc | 42 +++++++++---------- coreapi/linphonepresence.h | 14 +++---- coreapi/presence.c | 28 ++++++------- .../org/linphone/core/PresenceModel.java | 6 +-- .../org/linphone/core/PresencePerson.java | 6 +-- .../org/linphone/core/PresenceService.java | 2 +- .../org/linphone/core/PresenceModelImpl.java | 18 ++++---- .../org/linphone/core/PresencePersonImpl.java | 18 ++++---- .../linphone/core/PresenceServiceImpl.java | 6 +-- 10 files changed, 71 insertions(+), 71 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 8493cda88..5e48b227e 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -300,7 +300,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ if (lf->presence != NULL) { basic_status = linphone_presence_model_get_basic_status(lf->presence); - nb_activities = linphone_presence_model_nb_activities(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; diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 7a587ce83..23d32d13b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3550,12 +3550,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_setActivity(JNIE /* * Class: org_linphone_core_PresenceModelImpl - * Method: nbActivities + * Method: getNbActivities * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbActivities(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; - return (jlong)linphone_presence_model_nb_activities(model); + return (jlong)linphone_presence_model_get_nb_activities(model); } /* @@ -3630,12 +3630,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearNotes(JNIEn /* * Class: org_linphone_core_PresenceModelImpl - * Method: nbServices + * Method: getNbServices * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbServices(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbServices(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; - return (jlong)linphone_presence_model_nb_services(model); + return (jlong)linphone_presence_model_get_nb_services(model); } /* @@ -3671,12 +3671,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearServices(JN /* * Class: org_linphone_core_PresenceModelImpl - * Method: nbPersons + * Method: getNbPersons * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_nbPersons(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbPersons(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; - return (jlong)linphone_presence_model_nb_persons(model); + return (jlong)linphone_presence_model_get_nb_persons(model); } /* @@ -3886,12 +3886,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setContact(JNI /* * Class: org_linphone_core_PresenceServiceImpl - * Method: nbNotes + * Method: getNbNotes * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_nbNotes(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_getNbNotes(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresenceService *service = (LinphonePresenceService *)ptr; - return (jlong)linphone_presence_service_nb_notes(service); + return (jlong)linphone_presence_service_get_nb_notes(service); } /* @@ -3975,12 +3975,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_setId(JNIEnv *e /* * Class: org_linphone_core_PresencePersonImpl - * Method: nbActivities + * Method: getNbActivities * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbActivities(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbActivities(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; - return (jlong)linphone_presence_person_nb_activities(person); + return (jlong)linphone_presence_person_get_nb_activities(person); } /* @@ -4016,12 +4016,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearActivities /* * Class: org_linphone_core_PresencePersonImpl - * Method: nbNotes + * Method: getNbNotes * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbNotes(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbNotes(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; - return (jlong)linphone_presence_person_nb_notes(person); + return (jlong)linphone_presence_person_get_nb_notes(person); } /* @@ -4057,12 +4057,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearNotes(JNIE /* * Class: org_linphone_core_PresencePersonImpl - * Method: nbActivitiesNotes + * Method: getNbActivitiesNotes * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_nbActivitiesNotes(JNIEnv *env, jobject jobj, jlong ptr) { +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbActivitiesNotes(JNIEnv *env, jobject jobj, jlong ptr) { LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; - return (jlong)linphone_presence_person_nb_activities_notes(person); + return (jlong)linphone_presence_person_get_nb_activities_notes(person); } /* diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 6973c6eca..b4e220e9d 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -286,7 +286,7 @@ LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel * * @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_nb_activities(const LinphonePresenceModel *model); +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model); /** * Gets the nth activity of a presence model. @@ -357,7 +357,7 @@ LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); * @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_nb_services(const LinphonePresenceModel *model); +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_services(const LinphonePresenceModel *model); /** * Gets the nth service of a presence model. @@ -387,7 +387,7 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel * @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_nb_persons(const LinphonePresenceModel *model); +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_persons(const LinphonePresenceModel *model); /** * Gets the nth person of a presence model. @@ -482,7 +482,7 @@ LINPHONE_PUBLIC int linphone_presence_service_set_contact(LinphonePresenceServic * @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_nb_notes(const LinphonePresenceService *service); +LINPHONE_PUBLIC unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service); /** * Gets the nth note of a presence service. @@ -541,7 +541,7 @@ LINPHONE_PUBLIC int linphone_presence_person_set_id(LinphonePresencePerson *pers * @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_nb_activities(const LinphonePresencePerson *person); +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePerson *person); /** * Gets the nth activity of a presence person. @@ -571,7 +571,7 @@ LINPHONE_PUBLIC int linphone_presence_person_clear_activities(LinphonePresencePe * @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_nb_notes(const LinphonePresencePerson *person); +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson *person); /** * Gets the nth note of a presence person. @@ -601,7 +601,7 @@ LINPHONE_PUBLIC int linphone_presence_person_clear_notes(LinphonePresencePerson * @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_nb_activities_notes(const LinphonePresencePerson *person); +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePresencePerson *person); /** * Gets the nth activities note of a presence person. diff --git a/coreapi/presence.c b/coreapi/presence.c index 877a1e3e7..1db9697ae 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -435,7 +435,7 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP } -unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model) { +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; @@ -444,7 +444,7 @@ unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel * 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_nb_activities(model))) + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_activities(model))) return NULL; memset(&st, 0, sizeof(st)); @@ -651,12 +651,12 @@ LinphonePresenceModel * linphone_presence_model_new(void) { return model; } -unsigned int linphone_presence_model_nb_services(const LinphonePresenceModel *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_nb_services(model))) + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_services(model))) return NULL; return (LinphonePresenceService *)ms_list_nth_data(model->services, idx); @@ -677,12 +677,12 @@ int linphone_presence_model_clear_services(LinphonePresenceModel *model) { return 0; } -unsigned int linphone_presence_model_nb_persons(const LinphonePresenceModel *model) { +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_nb_persons(model))) + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_persons(model))) return NULL; return (LinphonePresencePerson *)ms_list_nth_data(model->persons, idx); @@ -766,12 +766,12 @@ int linphone_presence_service_set_contact(LinphonePresenceService *service, cons return 0; } -unsigned int linphone_presence_service_nb_notes(const LinphonePresenceService *service) { +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_nb_notes(service))) + if ((service == NULL) || (idx >= linphone_presence_service_get_nb_notes(service))) return NULL; return (LinphonePresenceNote *)ms_list_nth_data(service->notes, idx); @@ -818,13 +818,13 @@ int linphone_presence_person_set_id(LinphonePresencePerson *person, const char * return 0; } -unsigned int linphone_presence_person_nb_activities(const LinphonePresencePerson *person) { +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_nb_activities(person))) + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities(person))) return NULL; return (LinphonePresenceActivity *)ms_list_nth_data(person->activities, idx); } @@ -843,13 +843,13 @@ int linphone_presence_person_clear_activities(LinphonePresencePerson *person) { return 0; } -unsigned int linphone_presence_person_nb_notes(const LinphonePresencePerson *person) { +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_nb_notes(person))) + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_notes(person))) return NULL; return (LinphonePresenceNote *)ms_list_nth_data(person->notes, idx); } @@ -868,13 +868,13 @@ int linphone_presence_person_clear_notes(LinphonePresencePerson *person) { return 0; } -unsigned int linphone_presence_person_nb_activities_notes(const LinphonePresencePerson *person) { +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_nb_activities_notes(person))) + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities_notes(person))) return NULL; return (LinphonePresenceNote *)ms_list_nth_data(person->activities_notes, idx); } diff --git a/java/common/org/linphone/core/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java index b225e6606..78bc264c2 100644 --- a/java/common/org/linphone/core/PresenceModel.java +++ b/java/common/org/linphone/core/PresenceModel.java @@ -73,7 +73,7 @@ public interface PresenceModel { * @brief Gets the number of activities included in the presence model. * @return The number of activities included in the #PresenceModel object. */ - long nbActivities(); + long getNbActivities(); /** * @brief Gets the nth activity of a presence model. @@ -122,7 +122,7 @@ public interface PresenceModel { * @brief Gets the number of services included in the presence model. * @return The number of services included in the #PresenceModel object. */ - long nbServices(); + long getNbServices(); /** * @brief Gets the nth service of a presence model. @@ -148,7 +148,7 @@ public interface PresenceModel { * @brief Gets the number of persons included in the presence model. * @return The number of persons included in the #PresenceModel object. */ - long nbPersons(); + long getNbPersons(); /** * @brief Gets the nth person of a presence model. diff --git a/java/common/org/linphone/core/PresencePerson.java b/java/common/org/linphone/core/PresencePerson.java index 0e9822a60..730aafe77 100644 --- a/java/common/org/linphone/core/PresencePerson.java +++ b/java/common/org/linphone/core/PresencePerson.java @@ -38,7 +38,7 @@ public interface PresencePerson { * @brief Gets the number of activities included in the presence person. * @return The number of activities included in the #PresencePerson object. */ - long nbActivities(); + long getNbActivities(); /** * @brief Gets the nth activity of a presence person. @@ -64,7 +64,7 @@ public interface PresencePerson { * @brief Gets the number of notes included in the presence person. * @return The number of notes included in the #PresencePerson object. */ - long nbNotes(); + long getNbNotes(); /** * @brief Gets the nth note of a presence person. @@ -90,7 +90,7 @@ public interface PresencePerson { * @brief Gets the number of activities notes included in the presence person. * @return The number of activities notes included in the #PresencePerson object. */ - long nbActivitiesNotes(); + long getNbActivitiesNotes(); /** * @brief Gets the nth activities note of a presence person. diff --git a/java/common/org/linphone/core/PresenceService.java b/java/common/org/linphone/core/PresenceService.java index 082f7d5fd..3e06b6774 100644 --- a/java/common/org/linphone/core/PresenceService.java +++ b/java/common/org/linphone/core/PresenceService.java @@ -64,7 +64,7 @@ public interface PresenceService { * @brief Gets the number of notes included in the presence service. * @return The number of notes included in the #PresenceService object. */ - long nbNotes(); + long getNbNotes(); /** * @brief Gets the nth note of a presence service. diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java index 30cc4751e..b70ab6bd5 100644 --- a/java/impl/org/linphone/core/PresenceModelImpl.java +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -88,10 +88,10 @@ public class PresenceModelImpl implements PresenceModel { return setActivity(mNativePtr, activity.toInt(), description); } - private native long nbActivities(long nativePtr); + private native long getNbActivities(long nativePtr); @Override - public long nbActivities() { - return nbActivities(mNativePtr); + public long getNbActivities() { + return getNbActivities(mNativePtr); } private native Object getNthActivity(long nativePtr, long idx); @@ -130,10 +130,10 @@ public class PresenceModelImpl implements PresenceModel { return clearNotes(mNativePtr); } - private native long nbServices(long nativePtr); + private native long getNbServices(long nativePtr); @Override - public long nbServices() { - return nbServices(mNativePtr); + public long getNbServices() { + return getNbServices(mNativePtr); } private native Object getNthService(long nativePtr, long idx); @@ -154,10 +154,10 @@ public class PresenceModelImpl implements PresenceModel { return clearServices(mNativePtr); } - private native long nbPersons(long nativePtr); + private native long getNbPersons(long nativePtr); @Override - public long nbPersons() { - return nbPersons(mNativePtr); + public long getNbPersons() { + return getNbPersons(mNativePtr); } private native Object getNthPerson(long nativePtr, long idx); diff --git a/java/impl/org/linphone/core/PresencePersonImpl.java b/java/impl/org/linphone/core/PresencePersonImpl.java index ab4d85ceb..7b7a336ac 100644 --- a/java/impl/org/linphone/core/PresencePersonImpl.java +++ b/java/impl/org/linphone/core/PresencePersonImpl.java @@ -48,10 +48,10 @@ public class PresencePersonImpl implements PresencePerson { return setId(mNativePtr, id); } - private native long nbActivities(long nativePtr); + private native long getNbActivities(long nativePtr); @Override - public long nbActivities() { - return nbActivities(mNativePtr); + public long getNbActivities() { + return getNbActivities(mNativePtr); } private native Object getNthActivity(long nativePtr, long idx); @@ -72,10 +72,10 @@ public class PresencePersonImpl implements PresencePerson { return clearActivities(mNativePtr); } - private native long nbNotes(long nativePtr); + private native long getNbNotes(long nativePtr); @Override - public long nbNotes() { - return nbNotes(mNativePtr); + public long getNbNotes() { + return getNbNotes(mNativePtr); } private native Object getNthNote(long nativePtr, long idx); @@ -96,10 +96,10 @@ public class PresencePersonImpl implements PresencePerson { return clearNotes(mNativePtr); } - private native long nbActivitiesNotes(long nativePtr); + private native long getNbActivitiesNotes(long nativePtr); @Override - public long nbActivitiesNotes() { - return nbActivitiesNotes(mNativePtr); + public long getNbActivitiesNotes() { + return getNbActivitiesNotes(mNativePtr); } private native Object getNthActivitiesNote(long nativePtr, long idx); diff --git a/java/impl/org/linphone/core/PresenceServiceImpl.java b/java/impl/org/linphone/core/PresenceServiceImpl.java index bbca443ab..29cd930e4 100644 --- a/java/impl/org/linphone/core/PresenceServiceImpl.java +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -72,10 +72,10 @@ public class PresenceServiceImpl implements PresenceService { return setContact(mNativePtr, contact); } - private native long nbNotes(long nativePtr); + private native long getNbNotes(long nativePtr); @Override - public long nbNotes() { - return nbNotes(mNativePtr); + public long getNbNotes() { + return getNbNotes(mNativePtr); } private native Object getNthNote(long nativePtr, long idx); From 8bd7346eda362236e05213003b00ebd7645e3b73 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 11:38:11 +0200 Subject: [PATCH 752/909] Increment presence objects count reference when adding them to other presence objects. --- coreapi/presence.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index 1db9697ae..40cd9df25 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -664,7 +664,7 @@ LinphonePresenceService * linphone_presence_model_get_nth_service(const Linphone int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) { if ((model == NULL) || (service == NULL)) return -1; - model->services = ms_list_append(model->services, service); + model->services = ms_list_append(model->services, linphone_presence_service_ref(service)); return 0; } @@ -690,7 +690,7 @@ LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePr int linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { if ((model == NULL) || (person == NULL)) return -1; - model->persons = ms_list_append(model->persons, person); + model->persons = ms_list_append(model->persons, linphone_presence_person_ref(person)); return 0; } @@ -779,7 +779,7 @@ LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePres int linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { if ((service == NULL) || (note == NULL)) return -1; - service->notes = ms_list_append(service->notes, note); + service->notes = ms_list_append(service->notes, linphone_presence_note_ref(note)); return 0; } @@ -831,7 +831,7 @@ LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const Linph int linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) { if ((person == NULL) || (activity == NULL)) return -1; - person->activities = ms_list_append(person->activities, activity); + person->activities = ms_list_append(person->activities, linphone_presence_activity_ref(activity)); return 0; } @@ -856,7 +856,7 @@ LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePrese int linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { if ((person == NULL) || (note == NULL)) return -1; - person->notes = ms_list_append(person->notes, note); + person->notes = ms_list_append(person->notes, linphone_presence_note_ref(note)); return 0; } @@ -881,7 +881,7 @@ LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const Li 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, note); + person->notes = ms_list_append(person->activities_notes, linphone_presence_note_ref(note)); return 0; } From 470227cf85c4758eae07af53b86a23cdc9aa56f1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 7 Oct 2013 11:48:51 +0200 Subject: [PATCH 753/909] fix ICE crash fix potential crash when opening property box --- coreapi/callbacks.c | 3 +-- coreapi/misc.c | 6 ++++++ gtk/propertybox.c | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7d437cf69..d41091834 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -121,8 +121,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia } ms_message("No need to restart streams, SDP is unchanged."); return; - } - else { + }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); diff --git a/coreapi/misc.c b/coreapi/misc.c index e88538fb3..671a719a2 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -962,6 +962,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_check_list_set_state(cl, ICL_Failed); } else if (stream->rtp_port == 0) { ice_session_remove_check_list(call->ice_session, cl); +#ifdef VIDEO_ENABLED + if (stream->type==SalVideo && call->videostream){ + video_stream_stop(call->videostream); + call->videostream=NULL; + } +#endif } else { if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 22c3813c4..bcdb52812 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1051,6 +1051,7 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ 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(); @@ -1067,10 +1068,10 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ 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) - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),i); + active=i; } ms_list_free(l); - + if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } void linphone_gtk_show_parameters(void){ From 13442d397b8a8e5c8c95bb525fa0491d0ad1599b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 7 Oct 2013 16:35:05 +0200 Subject: [PATCH 754/909] Allow null strings in LpConfig.getString --- coreapi/linphonecore_jni.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 23d32d13b..9384d3dd1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3122,13 +3122,21 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setString(JNIEnv *env, jobje 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 *csection = env->GetStringUTFChars(section, NULL); const char *ckey = env->GetStringUTFChars(key, NULL); - const char *cvalue = env->GetStringUTFChars(defaultValue, NULL); - const char *returnValue = lp_config_get_string((LpConfig *)lpc, csection, ckey, cvalue); + const char *cvalue; + if (defaultValue == NULL) { + cvalue = NULL; + } else { + cvalue = env->GetStringUTFChars(defaultValue, NULL); + } + + const char *returnValue = lp_config_get_string((LpConfig *)lpc, csection, ckey, cvalue); + env->ReleaseStringUTFChars(section, csection); env->ReleaseStringUTFChars(key, ckey); - env->ReleaseStringUTFChars(defaultValue, cvalue); + if (cvalue) + env->ReleaseStringUTFChars(defaultValue, cvalue); return returnValue ? env->NewStringUTF(returnValue) : NULL; } extern "C" void Java_org_linphone_core_LpConfigImpl_setIntRange(JNIEnv *env, jobject thiz, jlong lpc, From 9b5d44b8db18e6f1920b90b6393c56f2a01abb02 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 17:42:12 +0200 Subject: [PATCH 755/909] Fix typo. --- coreapi/linphonecore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4fc6205b4..b148bf57a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -983,7 +983,7 @@ typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneF * @param url of the subscriber * Callback prototype */ -typedef void (*LinphoneCoreNewSubscribtionRequestCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +typedef void (*LinphoneCoreNewSubscriptionRequestCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); /** * Callback for requesting authentication information to application or user. * @param lc the LinphoneCore @@ -1066,7 +1066,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreRegistrationStateChangedCb registration_state_changed;/** Date: Mon, 7 Oct 2013 17:55:15 +0200 Subject: [PATCH 756/909] Remove unused code. --- coreapi/linphonecore.c | 15 --------------- coreapi/linphonecore.h | 4 ---- coreapi/private.h | 1 - 3 files changed, 20 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 97f063b00..5d661aeed 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4437,21 +4437,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){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b148bf57a..c700c344f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1476,10 +1476,6 @@ LINPHONE_PUBLIC void linphone_core_set_firewall_policy(LinphoneCore *lc, Linphon LINPHONE_PUBLIC 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); - /* sound functions */ /* returns a null terminated static array of string describing the sound devices */ const char** linphone_core_get_sound_devices(LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index 191105a09..57228ad3c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -496,7 +496,6 @@ typedef struct net_config char *stun_server; struct addrinfo *stun_addrinfo; unsigned long stun_res_id; - char *relay; int download_bw; int upload_bw; int mtu; From c9b4bd9e8d04598ae2a1c251ab4bf39a6209e8b6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Oct 2013 17:55:25 +0200 Subject: [PATCH 757/909] Property getters can start by 'is'. --- tools/software-desc.hh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/software-desc.hh b/tools/software-desc.hh index f5a1a180b..770818e4b 100644 --- a/tools/software-desc.hh +++ b/tools/software-desc.hh @@ -211,6 +211,12 @@ private: mPropertyName[0]=tolower(mPropertyName[0]); mPropertyBehaviour=Read; } + }else if (mName.find("is")==0 && mArgs.size()==0){ + mPropertyName=mName.substr(2,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Read; + } }else if (mName.find("enable")==0 && mArgs.size()==1){ mPropertyName=mName.substr(6,string::npos); if (!mPropertyName.empty()){ From 25cc96a51b0595de6a2defbf6dc27472482ee56e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 8 Oct 2013 09:42:51 +0200 Subject: [PATCH 758/909] fix liblinphone tester android build file --- build/android/liblinphone_tester.mk | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index b606c6066..cc314fc63 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -11,12 +11,21 @@ common_SRC_FILES := \ eventapi_tester.c # neon +common_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../coreapi \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include + include $(CLEAR_VARS) ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) LOCAL_MODULE := liblinphone_tester LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_C_INCLUDES = $(common_C_INCLUDES) +LOCAL_CFLAGS = -DIN_LINPHONE LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := cunit liblinphone @@ -32,9 +41,11 @@ ifeq ($(TARGET_ARCH_ABI),armeabi) LOCAL_MODULE_FILENAME := liblinphone_testerarmv5 endif LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_C_INCLUDES = $(common_C_INCLUDES) +LOCAL_CFLAGS = -DIN_LINPHONE LOCAL_LDLIBS := -llog -LOCAL_SHARED_LIBRARIES := cunit liblinphonenoneon +LOCAL_SHARED_LIBRARIES := cunit liblinphone include $(BUILD_SHARED_LIBRARY) #end From 5a92742e56ade67b79400246a7f13b238960745f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 8 Oct 2013 12:35:59 +0200 Subject: [PATCH 759/909] propagate android build changes to liblinphone_tester --- build/android/liblinphone_tester.mk | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index cc314fc63..5d9c7a469 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -10,7 +10,6 @@ common_SRC_FILES := \ upnp_tester.c \ eventapi_tester.c -# neon common_C_INCLUDES += \ $(LOCAL_PATH) \ $(LOCAL_PATH)/../include \ @@ -21,25 +20,8 @@ common_C_INCLUDES += \ include $(CLEAR_VARS) -ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) LOCAL_MODULE := liblinphone_tester -LOCAL_SRC_FILES += $(common_SRC_FILES) -LOCAL_C_INCLUDES = $(common_C_INCLUDES) -LOCAL_CFLAGS = -DIN_LINPHONE -LOCAL_LDLIBS := -llog - -LOCAL_SHARED_LIBRARIES := cunit liblinphone -include $(BUILD_SHARED_LIBRARY) -endif - -# noneon - -include $(CLEAR_VARS) - -LOCAL_MODULE := liblinphone_testernoneon -ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_MODULE_FILENAME := liblinphone_testerarmv5 -endif +LOCAL_MODULE_FILENAME := liblinphone_tester-$(TARGET_ARCH_ABI) LOCAL_SRC_FILES += $(common_SRC_FILES) LOCAL_C_INCLUDES = $(common_C_INCLUDES) LOCAL_CFLAGS = -DIN_LINPHONE From 3573ab67d3eb18ccf608426720629af2937ba570 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Oct 2013 12:46:49 +0200 Subject: [PATCH 760/909] Create constructor methods starting with 'new' instead of 'create'. --- tools/software-desc.hh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/software-desc.hh b/tools/software-desc.hh index 770818e4b..2d454e502 100644 --- a/tools/software-desc.hh +++ b/tools/software-desc.hh @@ -240,8 +240,12 @@ private: } } } - if (mPropertyBehaviour==None) + if (mPropertyBehaviour==None) { mPropertyName=""; + if (mName.find("create")==0) { + mName="new"+mName.substr(6,string::npos); + } + } } string mUid; Argument *mReturn; From 10734524fe6c377d6cce1b34e71b826774fb3fe7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Oct 2013 14:27:22 +0200 Subject: [PATCH 761/909] Add factory functions to create common linphone objects. --- coreapi/address.c | 4 +++ coreapi/authentication.c | 4 +++ coreapi/friend.c | 8 +++++ coreapi/linphonecore.c | 6 +++- coreapi/linphonecore.h | 46 ++++++++++++++++++++++---- coreapi/linphonefriend.h | 23 ++++++++++--- coreapi/linphonepresence.h | 67 ++++++++++++++++++++++++++++++++++++++ coreapi/presence.c | 28 ++++++++++++++++ 8 files changed, 174 insertions(+), 12 deletions(-) diff --git a/coreapi/address.c b/coreapi/address.c index 15f3a4062..cd2542808 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -182,4 +182,8 @@ int linphone_address_get_port(const LinphoneAddress *u) { return sal_address_get_port(u); } +LinphoneAddress * linphone_core_create_address(LinphoneCore *lc, const char *address) { + return linphone_address_new(address); +} + /** @} */ diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 57af57927..6095b1bc6 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -281,6 +281,10 @@ static void write_auth_infos(LinphoneCore *lc){ linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */ } +LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm) { + return linphone_auth_info_new(username, userid, passwd, ha1, realm); +} + /** * Adds authentication information to the LinphoneCore. * diff --git a/coreapi/friend.c b/coreapi/friend.c index 5e48b227e..22a2a24c2 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -427,6 +427,14 @@ void linphone_friend_done(LinphoneFriend *fr){ linphone_friend_apply(fr,fr->lc); } +LinphoneFriend * linphone_core_create_friend(LinphoneCore *lc) { + return linphone_friend_new(); +} + +LinphoneFriend * linphone_core_create_friend_with_address(LinphoneCore *lc, const char *address) { + return linphone_friend_new_with_address(address); +} + void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) { ms_return_if_fail(lf->lc==NULL); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5d661aeed..1868d1db5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5570,10 +5570,14 @@ void ui_config_uninit(LinphoneCore* lc) * sections and pairs of key=value in the configuration file. * **/ -LpConfig *linphone_core_get_config(LinphoneCore *lc){ +LpConfig * linphone_core_get_config(LinphoneCore *lc){ return lc->config; } +LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename) { + return lp_config_new(filename); +} + static void linphone_core_uninit(LinphoneCore *lc) { linphone_core_free_hooks(lc); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c700c344f..96942b099 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -50,6 +50,8 @@ typedef struct _LinphoneCore LinphoneCore; struct _LpConfig; +typedef struct _LpConfig LpConfig; + /** * Disable a sip transport @@ -194,6 +196,15 @@ LINPHONE_PUBLIC char *linphone_address_as_string_uri_only(const LinphoneAddress LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); 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; @@ -814,7 +825,7 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i /* you don't need those function*/ void linphone_auth_info_destroy(LinphoneAuthInfo *info); -LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos); +LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); struct _LinphoneChatRoom; @@ -1169,7 +1180,7 @@ LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable * callbacks) using linphone_core_get_user_data(). * @see linphone_core_new **/ -LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata); +LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, LpConfig *config, void *userdata); /* function to be periodically called in a main loop */ /* For ICE to work properly it should be called every 20ms */ @@ -1331,10 +1342,10 @@ LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneC LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); /** - * @ingroup proxy - *Create a proxy config with default value from Linphone core. - *@param lc #LinphoneCore object - *@return #LinphoneProxyConfig with defualt value set + * Create a proxy config with default values from Linphone core. + * @param[in] lc #LinphoneCore object + * @return #LinphoneProxyConfig with default values set + * @ingroup proxy */ LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); @@ -1352,6 +1363,19 @@ void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); LINPHONE_PUBLIC int linphone_core_get_default_proxy(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 + * @param[in] passwd String containing the password part of the authentication credentials + * @param[in] ha1 String containing a hash of the password + * @param[in] realm String used to discriminate different SIP domains + * @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); + LINPHONE_PUBLIC void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); @@ -1652,7 +1676,15 @@ LINPHONE_PUBLIC void linphone_core_set_user_data(LinphoneCore *lc, void *userdat /* returns LpConfig object to read/write to the config file: usefull if you wish to extend the config file with your own sections */ -LINPHONE_PUBLIC 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, LinphoneCoreWaitingCallback cb, void *user_context); diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 6b07069f6..6dd1ae662 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -265,7 +265,22 @@ LINPHONE_PUBLIC const char *linphone_online_status_to_string(LinphoneOnlineStatu /** - * @brief Set my presence status + * 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[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 @@ -275,14 +290,14 @@ LINPHONE_PUBLIC const char *linphone_online_status_to_string(LinphoneOnlineStatu LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); /** - * @brief Set my presence status + * 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); /** - * @brief Get my presence status + * Get my presence status * @param[in] lc #LinphoneCore object * @return #LinphoneOnlineStatus * @deprecated Use linphone_core_get_presence_model() instead @@ -290,7 +305,7 @@ LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, Linphone LINPHONE_PUBLIC LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); /** - * @brief Get my presence status + * Get my presence model * @param[in] lc #LinphoneCore object * @return A #LinphonePresenceModel object, or NULL if no presence model has been set. */ diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index b4e220e9d..dd2045262 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -867,6 +867,73 @@ void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user void * linphone_presence_note_get_user_data(LinphonePresenceNote *note); +/***************************************************************************** + * LINPHONE CORE FUNCTIONS RELATED TO PRESENCE * + ****************************************************************************/ + +/** + * Create a LinphonePresenceActivity with the given type and description. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created #LinphonePresenceActivity object. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_core_create_presence_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description); + +/** + * Create a default LinphonePresenceModel. + * @param[in] lc #LinphoneCore object. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model(LinphoneCore *lc); + +/** + * Create a LinphonePresenceModel with the given activity type and activity description. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity of the created model. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model_with_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description); + +/** + * Create a LinphonePresenceModel with the given activity type, activity description, note content and note language. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity of the created model. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @param[in] note The content of the note to be added to the created model. + * @param[in] lang The language of the note to be added to the created model. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model_with_activity_and_note(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang); + +/** + * Create a LinphonePresenceNote with the given content and language. + * @param[in] lc #LinphoneCore object. + * @param[in] content The content of the note to be created. + * @param[in] lang The language of the note to be created. + * @returns The created #LinphonePresenceNote object. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_core_create_presence_note(LinphoneCore *lc, const char *content, const char *lang); + +/** + * Create a LinphonePresencePerson with the given id. + * @param[in] lc #LinphoneCore object + * @param[in] id The id of the person to be created. + * @returns The created #LinphonePresencePerson object. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_core_create_presence_person(LinphoneCore *lc, const char *id); + +/** + * Create a LinphonePresenceService with the given id, basic status and contact. + * @param[in] lc #LinphoneCore object. + * @param[in] id The id of the service to be created. + * @param[in] basic_status The basic status of the service to be created. + * @param[in] contact A string containing a contact information corresponding to the service to be created. + * @returns The created #LinphonePresenceService object. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_core_create_presence_service(LinphoneCore *lc, const char *id, LinphonePresenceBasicStatus basic_status, const char *contact); + /** * @} */ diff --git a/coreapi/presence.c b/coreapi/presence.c index 40cd9df25..1e204316a 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1984,3 +1984,31 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){ ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op)); } } + +LinphonePresenceActivity * linphone_core_create_presence_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description) { + return linphone_presence_activity_new(acttype, description); +} + +LinphonePresenceModel * linphone_core_create_presence_model(LinphoneCore *lc) { + return linphone_presence_model_new(); +} + +LinphonePresenceModel * linphone_core_create_presence_model_with_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description) { + return linphone_presence_model_new_with_activity(acttype, description); +} + +LinphonePresenceModel * linphone_core_create_presence_model_with_activity_and_note(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang) { + return linphone_presence_model_new_with_activity_and_note(acttype, description, note, lang); +} + +LinphonePresenceNote * linphone_core_create_presence_note(LinphoneCore *lc, const char *content, const char *lang) { + return linphone_presence_note_new(content, lang); +} + +LinphonePresencePerson * linphone_core_create_presence_person(LinphoneCore *lc, const char *id) { + return linphone_presence_person_new(id); +} + +LinphonePresenceService * linphone_core_create_presence_service(LinphoneCore *lc, const char *id, LinphonePresenceBasicStatus basic_status, const char *contact) { + return linphone_presence_service_new(id, basic_status, contact); +} From ba0cead0ade1b1b1f4b1da81800b56fef3eef39e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Oct 2013 15:01:25 +0200 Subject: [PATCH 762/909] Fix compilation. --- coreapi/linphonecore.h | 6 ++---- coreapi/lpconfig.h | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 96942b099..d0936136c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -30,6 +30,8 @@ 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 @@ -48,10 +50,6 @@ struct _LinphoneCore; */ typedef struct _LinphoneCore LinphoneCore; -struct _LpConfig; - -typedef struct _LpConfig LpConfig; - /** * Disable a sip transport diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 869d572eb..f413bf7a6 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -24,9 +24,13 @@ #ifndef LPCONFIG_H #define LPCONFIG_H -#include "linphonecore.h" /*to get LINPHONE_PUBLIC, maybe we can include less stuff*/ +#include #include +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC +#endif + /** * The LpConfig object is used to manipulate a configuration file. * From adb3413ca5b7e3ecc6d27359b03791fa6ac8596e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Oct 2013 15:55:03 +0200 Subject: [PATCH 763/909] Remove useless @brief tags in the documentation. --- coreapi/linphonecore.h | 2 +- coreapi/linphonefriend.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d0936136c..69064cb75 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1618,7 +1618,7 @@ int linphone_core_get_device_rotation(LinphoneCore *lc ); void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); /** - * @brief Get the camera sensor rotation. + * Get the camera sensor rotation. * * This is needed on some mobile platforms to get the number of degrees the camera sensor * is rotated relative to the screen. diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 6dd1ae662..becd6290a 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -226,7 +226,7 @@ LINPHONE_PUBLIC void linphone_friend_edit(LinphoneFriend *fr); LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); /** - * @brief Get the status of a friend + * Get the status of a friend * @param[in] lf A #LinphoneFriend object * @return #LinphoneOnlineStatus * @deprecated Use linphone_friend_get_presence_model() instead @@ -234,7 +234,7 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); /** - * @brief Get the presence information of a friend + * 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) */ From 863770bebb7193963df5af36d30c968bb053d50e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 8 Oct 2013 16:37:26 +0200 Subject: [PATCH 764/909] Fix zrtp library link in Android --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 0b850c88a..fcca97e3b 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -63,7 +63,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { // Secure RTP and key negotiation loadOptionalLibrary("srtp-" + eabi); - loadOptionalLibrary("zrtpcpp" + eabi); // GPLv3+ + loadOptionalLibrary("zrtpcpp-" + eabi); // GPLv3+ //Main library System.loadLibrary("linphone-" + eabi); From 933513b7768cb8aa39fff35c81cfedf14e9fd587 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Oct 2013 16:36:03 +0200 Subject: [PATCH 765/909] Add some documentation. --- coreapi/linphonecore.h | 83 +++++++++++++++++++++++++++++++++++++--- coreapi/linphonefriend.h | 21 ++++++++-- 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 69064cb75..6e4d0b53a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1541,7 +1541,20 @@ LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *rin 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. + * @returns TRUE if the echo limiter is enabled, FALSE otherwise. + * @ingroup media_parameters +**/ LINPHONE_PUBLIC bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); void linphone_core_enable_agc(LinphoneCore *lc, bool_t val); @@ -1599,11 +1612,36 @@ LINPHONE_PUBLIC int linphone_core_set_video_device(LinphoneCore *lc, const char LINPHONE_PUBLIC const char *linphone_core_get_video_device(const LinphoneCore *lc); /* Set and get static picture to be used when "Static picture" is the video device */ +/** + * Set the path to the image file to stream when "Static picture" is set as the video device. + * @param[in] lc #LinphoneCore object. + * @param[in] path The path to the image file to use. + * @ingroup media_parameters + */ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); + +/** + * Get the path to the image file streamed when "Static picture" is set as the video device. + * @param[in] lc #LinphoneCore object. + * @returns The path to the image file streamed when "Static picture" is set as the video device. + * @ingroup media_parameters + */ const char *linphone_core_get_static_picture(LinphoneCore *lc); -/* Set and get frame rate for static picture */ +/** + * Set the frame rate for static picture. + * @param[in] lc #LinphoneCore object. + * @param[in] fps The new frame rate to use for static picture. + * @ingroup media_parameters + */ int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); + +/** + * Get the frame rate for static picture + * @param[in] lc #LinphoneCore object. + * @return The frame rate used for static picture. + * @ingroup media_parameters + */ float linphone_core_get_static_picture_fps(LinphoneCore *lc); /*function to be used for eventually setting window decorations (icons, title...)*/ @@ -1721,9 +1759,22 @@ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc); */ LINPHONE_PUBLIC void linphone_core_refresh_registers(LinphoneCore* lc); -/* Path to the file storing secrets cache */ +/** + * Set the path to the file storing the zrtp secrets cache. + * @param[in] lc #LinphoneCore object + * @param[in] file The path to the file to use to store the zrtp secrets cache. + * @ingroup initializing + */ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); + +/** + * Get the path to the file storing the zrtp secrets cache. + * @param[in] lc #LinphoneCore object. + * @returns The path to the file storing the zrtp secrets cache. + * @ingroup initializing + */ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); + /** * Search from the list of current calls if a remote address match uri * @ingroup call_control @@ -1765,15 +1816,35 @@ LINPHONE_PUBLIC bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); /** - * Choose media encryption policy to be used for RTP packets + * Choose the media encryption policy to be used for RTP packets. + * @param[in] lc #LinphoneCore object. + * @param[in] menc The media encryption policy to be used. + * @returns 0 if successful, any other value otherwise. + * @ingroup media_parameters */ LINPHONE_PUBLIC int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); + +/** + * Get the media encryption policy being used for RTP packets. + * @param[in] lc #LinphoneCore object. + * @returns The media encryption policy being used. + * @ingroup media_parameters + */ LINPHONE_PUBLIC LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); -LINPHONE_PUBLIC 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. + * @returns TRUE means the call will fail; FALSE means an INVITE will be resent with encryption disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc); + +/** + * Define behaviour when encryption parameters negociation fails on outgoing call. + * @param[in] lc #LinphoneCore object. + * @param[in] m If set to TRUE call will fail; if set to FALSE will resend an INVITE with encryption disabled. + * @ingroup media_parameters */ LINPHONE_PUBLIC void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index becd6290a..864555c33 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -338,19 +338,32 @@ LINPHONE_PUBLIC void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFrien LINPHONE_PUBLIC void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); /** - * get Buddy list of LinphoneFriend + * Get Buddy list of LinphoneFriend * @param lc #LinphoneCore object - * */ + */ LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); /** - * notify all friends that have subscribed + * Notify all friends that have subscribed * @param lc #LinphoneCore object * @param presence #LinphonePresenceModel to notify - * */ + */ LINPHONE_PUBLIC void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); +/** + * Search a LinphoneFriend by its address. + * @param[in] lc #LinphoneCore object. + * @param[in] addr The address to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given address. + */ LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); + +/** + * Search a LinphoneFriend by its reference key. + * @param[in] lc #LinphoneCore object. + * @param[in] key The reference key to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given reference key. + */ LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); /** From 2f6854ca8ad61599298aba9f705c39d0302e73e4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 10:44:09 +0200 Subject: [PATCH 766/909] Add documentation for enums that were not documented. --- coreapi/linphonecall.c | 4 ++-- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 45 ++++++++++++++++++++++------------------ coreapi/linphonefriend.h | 5 ++--- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 103492b4f..8036c7f10 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1144,14 +1144,14 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ /** * Returns kind of media encryption selected for the call. **/ -enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { +LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { return cp->media_encryption; } /** * Set requested media encryption for a call. **/ -void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) { +void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e) { cp->media_encryption = e; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1868d1db5..0ce449e03 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6085,7 +6085,7 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone return FALSE; } -int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc) { +int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc) { const char *type="none"; int ret=0; if (menc == LinphoneMediaEncryptionSRTP){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6e4d0b53a..92045740f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -242,17 +242,19 @@ typedef struct _LinphoneCallLog LinphoneCallLog; /** * Enum describing type of media encryption types. + * @ingroup media_parameters **/ -enum LinphoneMediaEncryption { - LinphoneMediaEncryptionNone, - LinphoneMediaEncryptionSRTP, - LinphoneMediaEncryptionZRTP +enum _LinphoneMediaEncryption { + LinphoneMediaEncryptionNone, /**< No media encryption is used */ + LinphoneMediaEncryptionSRTP, /**< Use SRTP media encryption */ + LinphoneMediaEncryptionZRTP /**< Use ZRTP media encryption */ }; /** * Enum describing type of media encryption types. + * @ingroup media_parameters **/ -typedef enum LinphoneMediaEncryption LinphoneMediaEncryption; +typedef enum _LinphoneMediaEncryption LinphoneMediaEncryption; /*public: */ LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl); @@ -845,14 +847,14 @@ typedef struct _LinphoneChatMessage LinphoneChatMessage; typedef struct _LinphoneChatRoom LinphoneChatRoom; /** - *LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. + * LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. */ -typedef enum _LinphoneChatMessageStates { - LinphoneChatMessageStateIdle, /** 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 @@ -50,7 +49,7 @@ typedef enum { * Automatically accepts a subscription request. */ LinphoneSPAccept -}LinphoneSubscribePolicy; +} LinphoneSubscribePolicy; /** * Enum describing remote friend status From 9a3d935bb352403b487e44a7fe4bb55211519c0e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 11:33:52 +0200 Subject: [PATCH 767/909] Generate javascript functions to get the values of enums as strings. --- tools/generator.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/generator.cc b/tools/generator.cc index b03c907f6..82f50c660 100644 --- a/tools/generator.cc +++ b/tools/generator.cc @@ -259,6 +259,24 @@ void JavascriptGenerator::writeEnum(Class *klass){ 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(); } From 41d60df07029f182588d5f2841983fb4ebc6083b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 14:13:11 +0200 Subject: [PATCH 768/909] Normalize event callbacks names. --- console/linphonec.c | 4 ++-- coreapi/event.h | 2 +- coreapi/help/buddy_status.c | 8 ++++---- coreapi/linphonecore.h | 8 ++++---- coreapi/linphonecore_jni.cc | 8 ++++---- coreapi/linphonefriend.h | 2 +- coreapi/presence.c | 8 ++++---- gtk/main.c | 4 ++-- tester/liblinphone_tester.c | 4 ++-- tester/liblinphone_tester.h | 2 +- tester/presence_tester.c | 2 +- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index f9e329b51..0b0c3a3f4 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -629,8 +629,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; diff --git a/coreapi/event.h b/coreapi/event.h index 8f9f8e6bd..9acb94b2d 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -89,7 +89,7 @@ LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishStat /** * Callback prototype for notifying the application about notification received from the network. **/ -typedef void (*LinphoneCoreIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); +typedef void (*LinphoneCoreNotifyReceivedCb)(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body); /** * Callback prototype for notifying the application about changes of subscription states, including arrival of new subscriptions. diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index bcd71b99f..64f818683 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -59,7 +59,7 @@ static void notify_presence_recv_updated (LinphoneCore *lc, LinphoneFriend *fri ,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)); @@ -106,11 +106,11 @@ int main(int argc, char *argv[]){ #endif /* Fill the LinphoneCoreVTable with application callbacks. - All are optional. Here we only use the both notify_presence_recv and new_subscription_request callbacks + All are optional. Here we only use the both notify_presence_received and new_subscription_requested callbacks in order to get notifications about friend status. */ - vtable.notify_presence_recv=notify_presence_recv_updated; - vtable.new_subscription_request=new_subscription_request; + vtable.notify_presence_received=notify_presence_recv_updated; + vtable.new_subscription_requested=new_subscription_requested; vtable.registration_state_changed=registration_state_changed; /*just in case sip proxy is used*/ /* diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 92045740f..68e120bb9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -994,7 +994,7 @@ typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneF * @param url of the subscriber * Callback prototype */ -typedef void (*LinphoneCoreNewSubscriptionRequestCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); /** * Callback for requesting authentication information to application or user. * @param lc the LinphoneCore @@ -1076,8 +1076,8 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreGlobalStateChangedCb global_state_changed; /**NewStringUTF(authentication_token) : NULL); } - static void notify_presence_recv (LinphoneCore *lc, LinphoneFriend *my_friend) { + static void notify_presence_received(LinphoneCore *lc, LinphoneFriend *my_friend) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { @@ -490,7 +490,7 @@ public: ,lcData->core ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)); } - static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) { + static void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 0e2bc4c5e..438c1ba0c 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -37,7 +37,7 @@ extern "C" { 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, diff --git a/coreapi/presence.c b/coreapi/presence.c index 1e204316a..e4cd069b9 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1524,9 +1524,9 @@ void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalO linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept); fl->inc_subscribe_pending=TRUE; lc->subscribers=ms_list_append(lc->subscribers,(void *)fl); - if (lc->vtable.new_subscription_request!=NULL) { + if (lc->vtable.new_subscription_requested!=NULL) { char *tmp=linphone_address_as_string(fl->uri); - lc->vtable.new_subscription_request(lc,fl,tmp); + lc->vtable.new_subscription_requested(lc,fl,tmp); ms_free(tmp); } } @@ -1958,8 +1958,8 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa } lf->presence = presence; lf->subscribe_active=TRUE; - if (lc->vtable.notify_presence_recv) - lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); + if (lc->vtable.notify_presence_received) + lc->vtable.notify_presence_received(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); diff --git a/gtk/main.c b/gtk/main.c index 9f781d2cd..c14b0c75f 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -237,8 +237,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; - vtable.notify_presence_recv=linphone_gtk_notify_recv; - vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber; + vtable.notify_presence_received=linphone_gtk_notify_recv; + vtable.new_subscription_requested=linphone_gtk_new_unknown_subscriber; vtable.auth_info_requested=linphone_gtk_auth_info_requested; vtable.display_status=linphone_gtk_display_status; vtable.display_message=linphone_gtk_display_message; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index d9d004c05..6492af82c 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -187,8 +187,8 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; mgr->v_table.message_received=message_received; - mgr->v_table.new_subscription_request=new_subscribtion_request; - mgr->v_table.notify_presence_recv=notify_presence_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; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index ae5143671..fa8c7a632 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -194,7 +194,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); -void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 688a8b5fc..bb3033f92 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -31,7 +31,7 @@ static LinphoneCoreManager* presence_linphone_core_manager_new(char* username) { linphone_core_set_primary_contact(mgr->lc,identity_char); return mgr; } -void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ +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); From 20829f370099dac5085be574102a1f5fa627cad0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 15:09:49 +0200 Subject: [PATCH 769/909] Add some documentation. --- coreapi/linphonecore.c | 30 --------- coreapi/linphonecore.h | 143 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 134 insertions(+), 39 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0ce449e03..f99763b4e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4092,12 +4092,6 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc){ return lc->video_conf.cams; } -/** - * Update detection of sound devices. - * - * Use this function when the application is notified of USB plug events, so that - * list of available hardwares for sound playback and capture is updated. - **/ void linphone_core_reload_sound_devices(LinphoneCore *lc){ const char *ringer,*playback,*capture; ringer=linphone_core_get_ringer_device(lc); @@ -4110,12 +4104,6 @@ void linphone_core_reload_sound_devices(LinphoneCore *lc){ linphone_core_set_capture_device(lc,capture); } -/** - * Update detection of camera devices. - * - * Use this function when the application is notified of USB plug events, so that - * list of available hardwares for video capture is updated. - **/ void linphone_core_reload_video_devices(LinphoneCore *lc){ const char *devid; devid=linphone_core_get_video_device(lc); @@ -4572,27 +4560,14 @@ void linphone_core_clear_call_logs(LinphoneCore *lc){ call_logs_write_to_config_file(lc); } -/** - * Returns number of missed calls. - * Once checked, this counter can be reset with linphone_core_reset_missed_calls_count(). -**/ int linphone_core_get_missed_calls_count(LinphoneCore *lc) { return lc->missed_calls; } -/** - * Resets the counter of missed calls. -**/ void linphone_core_reset_missed_calls_count(LinphoneCore *lc) { lc->missed_calls=0; } -/** - * Remove a specific call log from call history list. - * This function destroys the call log object. It must not be accessed anymore by the application after calling this function. - * @param lc the linphone core object - * @param a LinphoneCallLog object. -**/ void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *cl){ lc->call_logs = ms_list_remove(lc->call_logs, cl); call_logs_write_to_config_file(lc); @@ -4999,11 +4974,6 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show){ #endif } -/** - * Tells the core to use a separate window for local camera preview video, instead of - * inserting local view within the remote video window. - * -**/ void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){ lc->use_preview_window=yesno; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 68e120bb9..cf2926467 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1236,6 +1236,14 @@ LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, Linp LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); +/** + * Redirect the specified call to the given redirect URI. + * @param[in] lc #LinphoneCore object. + * @param[in] call The #LinphoneCall to redirect. + * @param[in] redirect_uri The URI to redirect the call to. + * @returns 0 if successful, -1 on error. + * @ingroup call_control + */ LINPHONE_PUBLIC int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri); LINPHONE_PUBLIC int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); @@ -1305,14 +1313,22 @@ LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); -LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); /** - * Enable payload type - * @param linphone core - * @param pt payload type to enable, can be retrieve from #linphone_core_find_payload_type - * @param TRUE if enabled - * @return 0 if succed - * + * Tells whether the specified payload type is enabled. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #PayloadType we want to know is enabled or not. + * @returns TRUE if the payload type is enabled, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); + +/** + * Enable or disable the use of the specified payload type. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #PayloadType to enable or disable. It can be retrieved using #linphone_core_find_payload_type + * @param[in] enable TRUE to enable the payload type, FALSE to disable it. + * @return 0 if successful, any other value otherwise. + * @ingroup media_parameters */ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); @@ -1391,16 +1407,40 @@ void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *inf LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc); +/** + * Enable or disable the audio adaptive jitter compensation. + * @param[in] lc #LinphoneCore object + * @param[in] enable TRUE to enable the audio adaptive jitter compensation, FALSE to disable it. + * @ingroup media_parameters + */ void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +/** + * Tells whether the audio adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @returns TRUE if the audio adaptive jitter compensation is enabled, FALSE otherwise. + * @ingroup media_parameters + */ bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc); int linphone_core_get_audio_jittcomp(LinphoneCore *lc); void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); +/** + * Enable or disable the video adaptive jitter compensation. + * @param[in] lc #LinphoneCore object + * @param[in] enable TRUE to enable the video adaptive jitter compensation, FALSE to disable it. + * @ingroup media_parameters + */ void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +/** + * Tells whether the video adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @returns TRUE if the video adaptive jitter compensation is enabled, FALSE otherwise. + * @ingroup media_parameters + */ bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc); int linphone_core_get_video_jittcomp(LinphoneCore *lc); @@ -1462,8 +1502,20 @@ LINPHONE_PUBLIC void linphone_core_set_delayed_timeout(LinphoneCore *lc, int sec LINPHONE_PUBLIC int linphone_core_get_delayed_timeout(LinphoneCore *lc); +/** + * 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); +/** + * Get the STUN server address being used. + * @param[in] lc #LinphoneCore object + * @returns The STUN server address being used. + * @ingroup network_parameters + */ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *lc); /** @@ -1495,18 +1547,52 @@ LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); */ const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); +/** + * Set the public IP address of NAT when using the firewall policy is set to use NAT. + * @param[in] lc #LinphoneCore object. + * @param[in] addr The public IP address of NAT to use. + * @ingroup network_parameters + */ void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); +/** + * Get the public IP address of NAT being used. + * @param[in] lc #LinphoneCore object. + * @returns The public IP address of NAT being used. + * @ingroup network_parameters + */ const char *linphone_core_get_nat_address(const LinphoneCore *lc); +/** + * 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); +/** + * Get the policy that is used to pass through firewalls. + * @param[in] lc #LinphoneCore object. + * @returns The #LinphoneFirewallPolicy that is being used. + * @ingroup network_parameters + */ LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); /* sound functions */ /* returns a null terminated static array of string describing the sound devices */ const char** linphone_core_get_sound_devices(LinphoneCore *lc); + +/** + * Update detection of sound devices. + * + * Use this function when the application is notified of USB plug events, so that + * list of available hardwares for sound playback and capture is updated. + * @param[in] lc #LinphoneCore object. + * @ingroup media_parameters + **/ void linphone_core_reload_sound_devices(LinphoneCore *lc); + bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device); bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device); LINPHONE_PUBLIC int linphone_core_get_ring_level(LinphoneCore *lc); @@ -1582,8 +1668,30 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val); /* returns a list of LinphoneCallLog */ LINPHONE_PUBLIC const MSList * linphone_core_get_call_logs(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_clear_call_logs(LinphoneCore *lc); + +/** + * Get the number of missed calls. + * Once checked, this counter can be reset with linphone_core_reset_missed_calls_count(). + * @param[in] lc #LinphoneCore object. + * @returns The number of missed calls. + * @ingroup call_logs +**/ LINPHONE_PUBLIC int linphone_core_get_missed_calls_count(LinphoneCore *lc); + +/** + * Reset the counter of missed calls. + * @param[in] lc #LinphoneCore object. + * @ingroup call_logs +**/ LINPHONE_PUBLIC void linphone_core_reset_missed_calls_count(LinphoneCore *lc); + +/** + * Remove a specific call log from call history list. + * This function destroys the call log object. It must not be accessed anymore by the application after calling this function. + * @param[in] lc #LinphoneCore object + * @param[in] call_log #LinphoneCallLog object to remove. + * @ingroup call_logs +**/ LINPHONE_PUBLIC void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); /* video support */ @@ -1610,8 +1718,17 @@ 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); -/* returns a null terminated static array of string describing the webcams */ +/** + * Update detection of camera devices. + * + * Use this function when the application is notified of USB plug events, so that + * list of available hardwares for video capture is updated. + * @param[in] lc #LinphoneCore object. + * @ingroup media_parameters + **/ void linphone_core_reload_video_devices(LinphoneCore *lc); + +/* returns a null terminated static array of string describing the webcams */ 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); @@ -1656,7 +1773,15 @@ LINPHONE_PUBLIC void linphone_core_set_native_video_window_id(LinphoneCore *lc, LINPHONE_PUBLIC unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); -void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); +/** + * 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); + int linphone_core_get_device_rotation(LinphoneCore *lc ); void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); From 9139a6bd70bdca9751d34566a2cf971c1c40033c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 15:19:39 +0200 Subject: [PATCH 770/909] Deprecate linphone_core_is_mic_muted() and linphone_core_mute_mic(). Introduce linphone_core_enable_mic() and linphone_core_mic_enabled() to replace them. --- console/commands.c | 2 +- coreapi/callbacks.c | 2 +- coreapi/linphonecore.c | 19 ++++++++++--------- coreapi/linphonecore.h | 27 +++++++++++++++++++++++---- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/console/commands.c b/console/commands.c index 09fc9c324..540b0e636 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2031,7 +2031,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" , diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index d41091834..844a06e47 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -113,7 +113,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia /*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 ); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f99763b4e..48e3d88f1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4276,11 +4276,6 @@ bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){ return lc->sound_conf.ea; } -/** - * Mutes or unmutes the local microphone. - * - * @ingroup media_parameters -**/ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ LinphoneCall *call=linphone_core_get_current_call(lc); AudioStream *st=NULL; @@ -4303,9 +4298,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ } } -/** - * Returns whether microphone is muted. -**/ + bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { LinphoneCall *call=linphone_core_get_current_call(lc); if (linphone_core_is_in_conference(lc)){ @@ -4317,13 +4310,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)){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index cf2926467..d0b609d19 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1651,14 +1651,33 @@ 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); -LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); /** - * return mic state. - * - * @ingroup media_parameters + * @deprecated Use #linphone_core_enable_mic instead. +**/ +LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); + +/** + * Get mic state. + * @deprecated Use #linphone_core_is_mic_enabled instead **/ LINPHONE_PUBLIC bool_t linphone_core_is_mic_muted(LinphoneCore *lc); +/** + * Enable or disable the microphone. + * @param[in] lc #LinphoneCore object + * @param[in] enable TRUE to enable the microphone, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether the microphone is enabled. + * @param[in] lc #LinphoneCore object + * @returns TRUE if the microphone is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_mic_enabled(LinphoneCore *lc); + bool_t linphone_core_is_rtp_muted(LinphoneCore *lc); bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc); From eeb36479d5f6eb5697fd8aa16fba6f5dee15cb78 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 15:50:45 +0200 Subject: [PATCH 771/909] Deprecate linphone_core_enable_video() and linphone_core_video_enabled(). Introduce linphone_core_enable_video_capture(), linphone_core_enable_video_display(), linphone_core_video_capture_enabled() and linphone_core_video_display_enabled() instead. --- console/linphonec.c | 3 +- coreapi/linphonecore.c | 84 ++++++++++++++++++++++++------------------ coreapi/linphonecore.h | 59 +++++++++++++++++++++++++++++ gtk/main.c | 6 ++- tester/call_tester.c | 18 ++++++--- 5 files changed, 125 insertions(+), 45 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 0b0c3a3f4..6564bcb5b 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -735,7 +735,8 @@ linphonec_init(int argc, char **argv) */ linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL); linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets); - linphone_core_enable_video(linphonec,vcap_enabled,display_enabled); + linphone_core_enable_video_capture(linphonec, vcap_enabled); + linphone_core_enable_video_display(linphonec, display_enabled); if (display_enabled && window_id != 0) { printf ("Setting window_id: 0x%x\n", window_id); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 48e3d88f1..1a879c4a8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -956,7 +956,8 @@ static void video_config_read(LinphoneCore *lc){ 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); - linphone_core_enable_video(lc,capture,display); + linphone_core_enable_video_capture(lc, capture); + linphone_core_enable_video_display(lc, display); linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0)); linphone_core_enable_self_view(lc,self_view); linphone_core_set_video_policy(lc,&vpol); @@ -4597,37 +4598,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; @@ -4636,14 +4606,56 @@ bool_t linphone_core_video_supported(LinphoneCore *lc){ #endif } -/** - * Returns TRUE if video is enabled, FALSE otherwise. - * @ingroup media_parameters -**/ +void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled) { + linphone_core_enable_video_capture(lc, vcap_enabled); + linphone_core_enable_video_display(lc, display_enabled); +} + bool_t linphone_core_video_enabled(LinphoneCore *lc){ return (lc->video_conf.display || lc->video_conf.capture); } +static void reapply_network_bandwidth_settings(LinphoneCore *lc) { + linphone_core_set_download_bandwidth(lc, linphone_core_get_download_bandwidth(lc)); + linphone_core_set_upload_bandwidth(lc, linphone_core_get_upload_bandwidth(lc)); +} + +void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable) { +#ifndef VIDEO_ENABLED + if (enable == TRUE) { + ms_warning("Cannot enable video capture, this version of linphone was built without video support."); + } +#endif + lc->video_conf.capture = enable; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "video", "capture", lc->video_conf.capture); + } + /* Need to re-apply network bandwidth settings. */ + reapply_network_bandwidth_settings(lc); +} + +void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable) { +#ifndef VIDEO_ENABLED + if (enable == TRUE) { + ms_warning("Cannot enable video display, this version of linphone was built without video support."); + } +#endif + lc->video_conf.display = enable; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "video", "display", lc->video_conf.display); + } + /* Need to re-apply network bandwidth settings. */ + reapply_network_bandwidth_settings(lc); +} + +bool_t linphone_core_video_capture_enabled(LinphoneCore *lc) { + return lc->video_conf.capture; +} + +bool_t linphone_core_video_display_enabled(LinphoneCore *lc) { + return lc->video_conf.display; +} + /** * Sets the default policy for video. * This policy defines whether: diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d0b609d19..1421e74aa 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1715,8 +1715,67 @@ LINPHONE_PUBLIC void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCal /* video support */ LINPHONE_PUBLIC bool_t linphone_core_video_supported(LinphoneCore *lc); + +/** + * Enables video globally. + * + * This function does not have any effect during calls. It just indicates LinphoneCore to + * initiate future calls with video or not. The two boolean parameters indicate in which + * direction video is enabled. Setting both to false disables video entirely. + * + * @param lc The LinphoneCore object + * @param vcap_enabled indicates whether video capture is enabled + * @param display_enabled indicates whether video display should be shown + * @ingroup media_parameters + * @deprecated Use #linphone_core_enable_video_capture and #linphone_core_enable_video_display instead. +**/ LINPHONE_PUBLIC void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled); + +/** + * Returns TRUE if video is enabled, FALSE otherwise. + * @ingroup media_parameters + * @deprecated Use #linphone_core_video_capture_enabled and #linphone_core_video_display_enabled instead. +**/ LINPHONE_PUBLIC bool_t linphone_core_video_enabled(LinphoneCore *lc); + +/** + * Enable or disable video capture. + * + * This function does not have any effect during calls. It just indicates the #LinphoneCore to + * initiate future calls with video capture or not. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable video capture, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable); + +/** + * Enable or disable video display. + * + * This function does not have any effect during calls. It just indicates the #LinphoneCore to + * initiate future calls with video display or not. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable video display, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether video capture is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if video capture is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_capture_enabled(LinphoneCore *lc); + +/** + * Tells whether video display is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if video display is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_display_enabled(LinphoneCore *lc); + LINPHONE_PUBLIC void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); LINPHONE_PUBLIC const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc); diff --git a/gtk/main.c b/gtk/main.c index c14b0c75f..1de976c9e 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -259,7 +259,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); linphone_core_set_zrtp_secrets_file(the_core,secrets_file); g_free(secrets_file); - linphone_core_enable_video(the_core,TRUE,TRUE); + linphone_core_enable_video_capture(the_core, TRUE); + linphone_core_enable_video_display(the_core, TRUE); if (no_video) { _linphone_gtk_enable_video(FALSE); linphone_gtk_set_ui_config_int("videoselfview",0); @@ -886,7 +887,8 @@ void linphone_gtk_answer_clicked(GtkWidget *button){ void _linphone_gtk_enable_video(gboolean val){ LinphoneVideoPolicy policy={0}; policy.automatically_initiate=policy.automatically_accept=val; - linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE); + linphone_core_enable_video_capture(linphone_gtk_get_core(), TRUE); + linphone_core_enable_video_display(linphone_gtk_get_core(), TRUE); linphone_core_set_video_policy(linphone_gtk_get_core(),&policy); if (val){ diff --git a/tester/call_tester.c b/tester/call_tester.c index df88321b6..281539d54 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -642,8 +642,10 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) LinphoneCall* call_obj; caller_policy.automatically_accept=TRUE; caller_policy.automatically_initiate=TRUE; - linphone_core_enable_video(callee->lc,TRUE,TRUE); - linphone_core_enable_video(caller->lc,TRUE,FALSE); + linphone_core_enable_video_capture(callee->lc, TRUE); + linphone_core_enable_video_display(callee->lc, TRUE); + linphone_core_enable_video_capture(caller->lc, TRUE); + linphone_core_enable_video_display(caller->lc, FALSE); linphone_core_set_video_policy(caller->lc,&caller_policy); stats initial_caller_stat=caller->stat; stats initial_callee_stat=callee->stat; @@ -693,8 +695,10 @@ static void call_with_declined_video(void) { LinphoneCall* marie_call; LinphoneCall* pauline_call; - linphone_core_enable_video(marie->lc,TRUE,TRUE); - linphone_core_enable_video(pauline->lc,TRUE,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); caller_params=linphone_core_create_default_call_parameters(marie->lc); linphone_call_params_enable_video(caller_params,TRUE); @@ -724,8 +728,10 @@ static void video_call(void) { LinphoneCall* marie_call; LinphoneCall* pauline_call; - linphone_core_enable_video(marie->lc,TRUE,TRUE); - linphone_core_enable_video(pauline->lc,TRUE,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); caller_params=linphone_core_create_default_call_parameters(marie->lc); linphone_call_params_enable_video(caller_params,TRUE); From 7a07ad2446c09aa7dcf7425ec704722cbccaa166 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 9 Oct 2013 16:50:41 +0200 Subject: [PATCH 772/909] Add some documentation. --- coreapi/linphonecore.h | 40 ++++++++++++++++++++++++++++++++++++++++ coreapi/linphonefriend.h | 18 ++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1421e74aa..4b2d34a9b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -305,7 +305,23 @@ LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const Linphone LINPHONE_PUBLIC void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path); LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); + +/** + * Add a custom SIP header in the INVITE for a call. + * @param[in] params 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. + * @ingroup call_control +**/ LINPHONE_PUBLIC void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value); + +/** + * Get a custom SIP header. + * @param[in] params The #LinphoneCallParams to get the custom SIP header from. + * @param[in] header_name The name of the header to get. + * @returns The content of the header or NULL if not found. + * @ingroup call_control +**/ LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name); /** @@ -693,8 +709,20 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *o LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); +/** + * Get the registration state of the given proxy config. + * @param[in] obj #LinphoneProxyConfig object. + * @returns The registration state of the proxy config. +**/ LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); + LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); + +/** + * Get the domain name of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @returns The domain name of the proxy config. +**/ LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); @@ -706,12 +734,24 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProx LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); + +/** + * Get the #LinphoneCore object to which is associated the #LinphoneProxyConfig. + * @param[in] obj #LinphoneProxyConfig object. + * @returns The #LinphoneCore object to which is associated the #LinphoneProxyConfig. +**/ LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); +/** + * Get the reason why registration failed when the proxy config state is LinphoneRegistrationFailed. + * @param[in] cfg #LinphoneProxyConfig object. + * @returns The reason why registration failed for this proxy config. +**/ LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); + /* * return the transport from either : service route, route, or addr * @returns cfg object diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 438c1ba0c..101c9f62f 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -250,8 +250,26 @@ LINPHONE_PUBLIC void linphone_friend_set_user_data(LinphoneFriend *lf, void *dat LINPHONE_PUBLIC void* linphone_friend_get_user_data(const LinphoneFriend *lf); LINPHONE_PUBLIC BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); + +/** + * Set the reference key of a friend. + * @param[in] lf #LinphoneFriend object. + * @param[in] key The reference key to use for the friend. +**/ LINPHONE_PUBLIC void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); + +/** + * Get the reference key of a friend. + * @param[in] lf #LinphoneFriend object. + * @returns The reference key of the friend. +**/ LINPHONE_PUBLIC const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); + +/** + * Check that the given friend is in a friend list. + * @param[in] lf #LinphoneFriend object. + * @returns TRUE if the friend is in a friend list, FALSE otherwise. +**/ LINPHONE_PUBLIC bool_t linphone_friend_in_list(const LinphoneFriend *lf); From c344f32c1e0db5da3d596f741a330dea28fc5639 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 10 Oct 2013 12:57:05 +0200 Subject: [PATCH 773/909] Updated JNI interface and LinphoneAuthInfo java class --- coreapi/linphonecore_jni.cc | 16 ++++++++++++++++ java/common/org/linphone/core/LinphoneCore.java | 5 +++++ .../org/linphone/core/LinphoneAuthInfoImpl.java | 8 +++++++- .../impl/org/linphone/core/LinphoneCoreImpl.java | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 9d9c264ea..74eb70ac7 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -814,6 +814,22 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } +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" void Java_org_linphone_core_LinphoneCoreImpl_clearAuthInfos(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_all_auth_info((LinphoneCore*)lc); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index ccadcd35e..821532c68 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -384,6 +384,11 @@ public interface LinphoneCore { */ public LinphoneProxyConfig getDefaultProxyConfig() ; + /** + * Returns an array with all the auth infos stored in LinphoneCore + */ + LinphoneAuthInfo[] getAuthInfosList(); + /** * clear all the added auth info */ diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java index dee96fe5d..feea5a3df 100644 --- a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java @@ -33,6 +33,7 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { private native String getUserId(long ptr); private native String getHa1(long ptr); + boolean ownPtr = false; protected LinphoneAuthInfoImpl(String username,String password, String realm) { this(username,null,password,null,null); } @@ -42,9 +43,14 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { this.setUserId(userid); this.setPassword(passwd); this.setHa1(ha1); + ownPtr = true; + } + protected LinphoneAuthInfoImpl(long aNativePtr) { + nativePtr = aNativePtr; + ownPtr = false; } protected void finalize() throws Throwable { - delete(nativePtr); + if (ownPtr) delete(nativePtr); } public String getPassword() { return getPassword (nativePtr); diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index d5314b479..ac4cb73d5 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -103,6 +103,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setRootCA(long nativePtr, String path); private native long[] listVideoPayloadTypes(long nativePtr); private native long[] getProxyConfigList(long nativePtr); + private native long[] getAuthInfosList(long nativePtr); private native long[] listAudioPayloadTypes(long nativePtr); private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); @@ -1007,4 +1008,17 @@ class LinphoneCoreImpl implements LinphoneCore { return proxies; } + @Override + public LinphoneAuthInfo[] getAuthInfosList() { + long[] typesPtr = getAuthInfosList(nativePtr); + if (typesPtr == null) return null; + + LinphoneAuthInfo[] authInfos = new LinphoneAuthInfo[typesPtr.length]; + + for (int i=0; i < authInfos.length; i++) { + authInfos[i] = new LinphoneAuthInfoImpl(typesPtr[i]); + } + + return authInfos; + } } From 64789a3b60c05f12792100aeba144675d2f5ff0a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 10 Oct 2013 16:44:26 +0200 Subject: [PATCH 774/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d7f50cdff..617f25b37 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d7f50cdff8aefaa7bc2208edb743726bf940ff87 +Subproject commit 617f25b37cc358b8c648ec32babb3765ab3ef8d8 From 5e6693d30ada71da175715ff147aab33452a1f24 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 10 Oct 2013 16:58:21 +0200 Subject: [PATCH 775/909] Fix compilation. --- coreapi/proxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index fcfdc6697..b7edfdb81 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -278,14 +278,14 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ const char *localip = NULL; char *tmp; - + LinphoneAddress *contact; if (obj->contact_params) tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params); else tmp = strdup(obj->reg_identity); - LinphoneAddress *contact = linphone_address_new(tmp); + contact = linphone_address_new(tmp); if (!contact) { ms_error("No valid contact_params for [%s]",linphone_address_get_domain(proxy)); return NULL; From a5c40facf6fb830efd56f4b7e4de7d400d785030 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 11 Oct 2013 10:31:03 +0200 Subject: [PATCH 776/909] add tests to make sure unsuccesfull incall transactions do not abort the call. --- coreapi/bellesip_sal/sal_impl.c | 3 + coreapi/bellesip_sal/sal_op_call.c | 3 +- coreapi/bellesip_sal/sal_op_impl.c | 7 ++ coreapi/callbacks.c | 25 +++++++ coreapi/linphonecall.c | 4 +- coreapi/linphonecore.c | 4 +- coreapi/linphonecore.h | 3 +- coreapi/misc.c | 5 ++ coreapi/sal.c | 1 + include/sal/sal.h | 9 ++- tester/call_tester.c | 106 ++++++++++++++++++++++++++++- tester/liblinphone_tester.c | 7 +- tester/liblinphone_tester.h | 2 +- tester/marie_early_rc | 2 +- tester/marie_no_sdp_rc | 2 +- tester/marie_rc | 2 +- tester/message_tester.c | 52 ++++++++------ tester/multi_account_lrc | 8 +-- tester/pauline_rc | 2 +- 19 files changed, 207 insertions(+), 40 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f5235c808..f1ce73599 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -848,3 +848,6 @@ void sal_resolve_cancel(Sal *sal, unsigned long id){ belle_sip_stack_resolve_cancel(sal->stack,id); } +void sal_enable_unconditional_answer(Sal *sal,int value) { + belle_sip_provider_enable_unconditional_answer(sal->prov,value); +} diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 66aaa4890..80173e95d 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -570,7 +570,8 @@ static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* respon set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); }else{ - if (op->sdp_answer==NULL) sdp_process(op); + if (op->sdp_answer==NULL) + sdp_process(op); if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 13b3ba004..3bf2e5ea6 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -351,6 +351,9 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonUnauthorized: ret=401; break; + case SalReasonNotAcceptable: + ret=488; + break; } return ret; } @@ -390,6 +393,10 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal break; case 487: break; + case 488: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNotAcceptable; + break; case 491: *sal_err=SalErrorFailure; *sal_reason=SalReasonRequestPending; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 844a06e47..fe57a5dfd 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -477,6 +477,16 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ } static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){ + /*first check if media capabilities are compatible*/ + SalMediaDescription* md; + linphone_call_make_local_media_description(lc,call); + sal_call_set_local_media_description(call->op,call->localdesc); + md=sal_call_get_final_media_description(call->op); + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); + return; + } + if(lc->vtable.display_status) lc->vtable.display_status(lc,_("Call is updated by remote.")); call->defer_update=FALSE; @@ -637,8 +647,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); break; + case SalReasonNotAcceptable: case SalReasonRequestPending: /*restore previous state, the application will decide to resubmit the action if relevant*/ + call->reason=linphone_reason_from_sal(sr); linphone_call_set_state(call,call->prevstate,msg); return; break; @@ -648,6 +660,19 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } } + /*some call error are not fatal*/ + switch (call->state) { + case LinphoneCallUpdating: + case LinphoneCallPausing: + case LinphoneCallResuming: + ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); + call->reason=linphone_reason_from_sal(sr); + linphone_call_set_state(call, call->prevstate,msg); + return; + default: + break; /*nothing to do*/ + } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 8036c7f10..6b27f1333 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -705,8 +705,10 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const return; } } + ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state), - linphone_call_state_to_string(cstate)); + linphone_call_state_to_string(cstate)); + if (cstate!=LinphoneCallRefered){ /*LinphoneCallRefered is rather an event, not a state. Indeed it does not change the state of the call (still paused or running)*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1a879c4a8..3f6e79ae0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5877,7 +5877,9 @@ const char *linphone_reason_to_string(LinphoneReason err){ case LinphoneReasonDoNotDisturb: return "Do not distrub"; case LinphoneReasonUnauthorized: - return "Unauthorized"; + return "Unauthorized"; + case LinphoneReasonNotAcceptable: + return "Not acceptable here"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4b2d34a9b..dbf3779ec 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -150,7 +150,8 @@ enum _LinphoneReason{ LinphoneReasonMedia, /**lc)); + if (linphone_core_get_current_call(mgr->lc)) + CU_ASSERT_EQUAL(linphone_call_get_state(linphone_core_get_current_call(mgr->lc)),state); +} +static void call_established_with_rejected_info(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + int dummy=0; + + CU_ASSERT_TRUE(call(pauline,marie)); + + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + + wait_for_until(marie->lc,pauline->lc,&dummy,1,1000); /*just to sleep while iterating 1s*/ + + sal_enable_unconditional_answer(marie->lc->sal,FALSE); + + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_inforeceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_inforeceived,1); + + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void call_established_with_rejected_reinvite(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNotAcceptable); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_established_with_rejected_reinvite_with_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*add PCMA*/ + + + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNone); /*might be change later*/ + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + #ifdef VIDEO_ENABLED #endif @@ -1252,7 +1353,10 @@ test_t call_tests[] = { { "Unattended call transfer with error", unattended_call_transfer_with_error }, { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, { "Call with ICE", call_with_ice }, - { "Call with custom headers",call_with_custom_headers} + { "Call with custom headers",call_with_custom_headers}, + { "Call established with rejected INFO",call_established_with_rejected_info}, + { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, + { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error} }; test_suite_t call_test_suite = { diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 6492af82c..7b34e7f45 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -153,7 +153,7 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { else return TRUE; } -static void enable_codec(LinphoneCore* lc,const char* type,int rate) { +static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t enable) { MSList* codecs=ms_list_copy(linphone_core_get_audio_codecs(lc)); MSList* codecs_it; PayloadType* pt; @@ -161,11 +161,14 @@ static void enable_codec(LinphoneCore* lc,const char* type,int rate) { 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, 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; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index fa8c7a632..8d80eb2b6 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -155,7 +155,7 @@ typedef struct _stats { const LinphonePresenceModel *last_received_presence; int number_of_inforeceived; - int number_of_inforeceived_with_body; + LinphoneInfoMessage* last_received_info_message; int number_of_LinphoneSubscriptionIncomingReceived; int number_of_LinphoneSubscriptionOutgoingInit; diff --git a/tester/marie_early_rc b/tester/marie_early_rc index 65934c3f3..36c302a4f 100644 --- a/tester/marie_early_rc +++ b/tester/marie_early_rc @@ -11,7 +11,7 @@ incoming_calls_early_media=1 username=marie userid=marie passwd=secret -realm="sip.example.org" +realm=sip.example.org [proxy_0] diff --git a/tester/marie_no_sdp_rc b/tester/marie_no_sdp_rc index a3733dd83..50a740dca 100644 --- a/tester/marie_no_sdp_rc +++ b/tester/marie_no_sdp_rc @@ -11,7 +11,7 @@ sdp_200_ack=1 username=marie userid=marie passwd=secret -realm="sip.example.org" +realm=sip.example.org [proxy_0] diff --git a/tester/marie_rc b/tester/marie_rc index e221f6fad..d5b7d7c87 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -10,7 +10,7 @@ register_only_when_network_is_up=0 username=marie userid=marie passwd=secret -realm="sip.example.org" +realm=sip.example.org [proxy_0] diff --git a/tester/message_tester.c b/tester/message_tester.c index f5388b0ab..5b111a302 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -198,23 +198,12 @@ static const char *info_content="blabla"; void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneInfoMessage *msg){ stats* counters = get_stats(lc); - const char *hvalue=linphone_info_message_get_header(msg, "Weather"); - const LinphoneContent *content=linphone_info_message_get_content(msg); - CU_ASSERT_PTR_NOT_NULL_FATAL(hvalue); - CU_ASSERT_TRUE(strcmp(hvalue,"still bad")==0); - - if (!content){ - counters->number_of_inforeceived++; - }else{ - CU_ASSERT_PTR_NOT_NULL_FATAL(content->data); - CU_ASSERT_PTR_NOT_NULL_FATAL(content->type); - CU_ASSERT_PTR_NOT_NULL_FATAL(content->subtype); - CU_ASSERT_TRUE(strcmp(content->type,"application")==0); - CU_ASSERT_TRUE(strcmp(content->subtype,"somexml")==0); - CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); - CU_ASSERT_EQUAL(content->size,strlen(info_content)); - counters->number_of_inforeceived_with_body++; + + 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++; } @@ -223,9 +212,11 @@ static void info_message_with_args(bool_t with_content) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneInfoMessage *info; - + const LinphoneContent *content; + const char *hvalue; + CU_ASSERT_TRUE(call(pauline,marie)); - + info=linphone_core_create_info_message(marie->lc); linphone_info_message_add_header(info,"Weather","still bad"); if (with_content) { @@ -238,11 +229,28 @@ static void info_message_with_args(bool_t with_content) { } linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),info); linphone_info_message_destroy(info); - + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + + CU_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_info_message); + hvalue=linphone_info_message_get_header(pauline->stat.last_received_info_message, "Weather"); + content=linphone_info_message_get_content(pauline->stat.last_received_info_message); + + CU_ASSERT_PTR_NOT_NULL(hvalue); + if (hvalue) + CU_ASSERT_TRUE(strcmp(hvalue,"still bad")==0); + if (with_content){ - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived_with_body,1)); - }else{ - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + CU_ASSERT_PTR_NOT_NULL(content); + if (content) { + CU_ASSERT_PTR_NOT_NULL(content->data); + CU_ASSERT_PTR_NOT_NULL(content->type); + CU_ASSERT_PTR_NOT_NULL(content->subtype); + if (content->type) CU_ASSERT_TRUE(strcmp(content->type,"application")==0); + if (content->subtype) CU_ASSERT_TRUE(strcmp(content->subtype,"somexml")==0); + if (content->data)CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); + CU_ASSERT_EQUAL(content->size,strlen(info_content)); + } } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc index 23705a733..a78a5bc16 100644 --- a/tester/multi_account_lrc +++ b/tester/multi_account_lrc @@ -8,25 +8,25 @@ default_proxy=0 username=liblinphone_tester userid=liblinphone_tester passwd=secret -realm="auth.example.org" +realm=auth.example.org [auth_info_1] username=pauline userid=pauline passwd=secret -realm="sip.example.org" +realm=sip.example.org [auth_info_2] username=liblinphone_tester userid=liblinphone_tester passwd=secret -realm="auth1.example.org" +realm=auth1.example.org [auth_info_3] username=marie userid=marie passwd=secret -realm="sip.example.org" +realm=sip.example.org [proxy_0] reg_proxy=sip2.linphone.org;transport=tls diff --git a/tester/pauline_rc b/tester/pauline_rc index 1589d2cdb..204486f66 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -10,7 +10,7 @@ register_only_when_network_is_up=0 username=pauline userid=pauline passwd=secret -realm="sip.example.org" +realm=sip.example.org [proxy_0] From db78dd7fb3b5486e87b424f38111fd8743cb1cb9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 11 Oct 2013 10:51:07 +0200 Subject: [PATCH 777/909] change h264 profile level id to allow working with HD resolutions. --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3f6e79ae0..1b349677d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1263,7 +1263,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta 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_h264,102,"profile-level-id=42801F"); linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL); linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL); /* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */ From bcd22f8a741f83a78631b547c71ead9d26d065bb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 11 Oct 2013 15:29:10 +0200 Subject: [PATCH 778/909] Added JNI API to delete one ProxyConfig and one AuthInfo --- coreapi/linphonecore_jni.cc | 8 ++++++++ java/common/org/linphone/core/LinphoneCore.java | 13 +++++++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 12 +++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 74eb70ac7..06d4d36a3 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -814,6 +814,14 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeProxyConfig(JNIEnv* env, jobject thiz, jlong lc, jlong proxy) { + linphone_core_remove_proxy_config((LinphoneCore*)lc, (LinphoneProxyConfig*)proxy); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeAuthInfo(JNIEnv* env, jobject thiz, jlong lc, jlong authInfo) { + linphone_core_remove_auth_info((LinphoneCore*)lc, (LinphoneAuthInfo*)authInfo); +} + extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getAuthInfosList(JNIEnv* env, jobject thiz,jlong lc) { const MSList* authInfos = linphone_core_get_auth_info_list((LinphoneCore*)lc); int listCount = ms_list_size(authInfos); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 821532c68..f478d7ecf 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -369,6 +369,13 @@ public interface LinphoneCore { * @throws LinphoneCoreException */ public void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException; + + /** + * Removes a proxy configuration. + * @param proxyCfg + */ + public void removeProxyConfig(LinphoneProxyConfig proxyCfg); + /** * Sets the default proxy. *
@@ -389,6 +396,12 @@ public interface LinphoneCore { */ LinphoneAuthInfo[] getAuthInfosList(); + /** + * Removes a auth info. + * @param authInfo + */ + public void removeAuthInfo(LinphoneAuthInfo authInfo); + /** * clear all the added auth info */ diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index ac4cb73d5..866f1e5fe 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -44,10 +44,12 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setDefaultProxyConfig(long nativePtr,long proxyCfgNativePtr); private native int addProxyConfig(LinphoneProxyConfig jprtoxyCfg,long nativePtr,long proxyCfgNativePtr); + private native void removeProxyConfig(long nativePtr, long proxyCfg); private native void clearAuthInfos(long nativePtr); private native void clearProxyConfigs(long nativePtr); private native void addAuthInfo(long nativePtr,long authInfoNativePtr); + private native void removeAuthInfo(long nativePtr, long authInfoNativePtr); private native Object invite(long nativePtr,String uri); private native void terminateCall(long nativePtr, long call); private native long getRemoteAddress(long nativePtr); @@ -168,6 +170,11 @@ class LinphoneCoreImpl implements LinphoneCore { addAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr); } + public synchronized void removeAuthInfo(LinphoneAuthInfo info) { + isValid(); + removeAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr); + } + public synchronized LinphoneProxyConfig getDefaultProxyConfig() { isValid(); long lNativePtr = getDefaultProxyConfig(nativePtr); @@ -198,10 +205,13 @@ class LinphoneCoreImpl implements LinphoneCore { throw new LinphoneCoreException("bad proxy config"); } } + public synchronized void removeProxyConfig(LinphoneProxyConfig proxyCfg) { + isValid(); + removeProxyConfig(nativePtr, ((LinphoneProxyConfigImpl)proxyCfg).nativePtr); + } public synchronized void clearAuthInfos() { isValid(); clearAuthInfos(nativePtr); - } public synchronized void clearProxyConfigs() { isValid(); From 873072d4602b43766d2655e82200b7d6a871822f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 14 Oct 2013 14:18:33 +0200 Subject: [PATCH 779/909] Added JNI API to set expires on given proxy config --- coreapi/linphonecore_jni.cc | 5 +++++ java/common/org/linphone/core/LinphoneProxyConfig.java | 6 ++++++ java/impl/org/linphone/core/LinphoneProxyConfigImpl.java | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 06d4d36a3..6f63a2809 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2623,10 +2623,15 @@ 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_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" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { return (jint)linphone_call_get_duration((LinphoneCall *) ptr); } diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 2db0756b6..83e8bbd5d 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -134,6 +134,12 @@ public interface LinphoneProxyConfig { */ void setExpires(int delay); + /** + * Gets the registration expiration time. + * @return delay expiration time in seconds. + */ + int getExpires(); + /** * Sets parameters for the contact * @param parameters to add diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 903d2a1c6..25168ea57 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -30,6 +30,7 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native int getState(long nativePtr); private native void setExpires(long nativePtr, int delay); + private native int getExpires(long nativePtr); boolean ownPtr = false; protected LinphoneProxyConfigImpl(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException { @@ -143,6 +144,9 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public void setExpires(int delay) { setExpires(nativePtr, delay); } + public int getExpires() { + return getExpires(nativePtr); + } public boolean publishEnabled() { return publishEnabled(nativePtr); } From ac3615363a3f51a2ed99b2f2b08424f692d870eb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 14 Oct 2013 14:24:03 +0200 Subject: [PATCH 780/909] Update ms2 submodule for fix in X11 display filter. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 617f25b37..4749e8333 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 617f25b37cc358b8c648ec32babb3765ab3ef8d8 +Subproject commit 4749e833304efb1835bf4a5bcb584d6118945fef From 539ae4bb567fae8929a872d7d123e3a9a2baad5f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 14 Oct 2013 14:23:24 +0200 Subject: [PATCH 781/909] Added JNI API to know if ipv6 is enabled in lc --- coreapi/linphonecore_jni.cc | 4 ++++ java/common/org/linphone/core/LinphoneCore.java | 3 +++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 6f63a2809..fd7d939ab 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2674,6 +2674,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableIpv6(JNIEnv* env,j linphone_core_enable_ipv6((LinphoneCore*)lc,enable); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isIpv6Enabled(JNIEnv* env,jobject thiz, jlong lc) { + return (jboolean)linphone_core_ipv6_enabled((LinphoneCore*)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_adjustSoftwareVolume(JNIEnv* env,jobject thiz ,jlong ptr, jint db) { linphone_core_set_playback_gain_db((LinphoneCore *) ptr, db); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index f478d7ecf..518137ca0 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -937,6 +937,9 @@ public interface LinphoneCore { boolean needsEchoCalibration(); void enableIpv6(boolean enable); + + boolean isIpv6Enabled(); + /** * @deprecated * @param i diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 866f1e5fe..c9257d8c1 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -113,6 +113,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native int getSignalingTransportPort(long nativePtr, int code); private native void setSignalingTransportPorts(long nativePtr, int udp, int tcp, int tls); private native void enableIpv6(long nativePtr,boolean enable); + private native boolean isIpv6Enabled(long nativePtr); private native int pauseCall(long nativePtr, long callPtr); private native int pauseAllCalls(long nativePtr); private native int resumeCall(long nativePtr, long callPtr); @@ -558,6 +559,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(). } From fc61fbd1aab9d5cf715682bd16d30399df46da48 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 14 Oct 2013 14:39:21 +0200 Subject: [PATCH 782/909] Added JNI API to get default username and displayname --- coreapi/linphonecore_jni.cc | 12 ++++++++++++ java/common/org/linphone/core/LinphoneCore.java | 10 ++++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 10 ++++++++++ 3 files changed, 32 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index fd7d939ab..c98390f3c 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -769,6 +769,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv env->ReleaseStringUTFChars(jusername, username); } +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneAddress* identity = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + const char * username = linphone_address_get_username(identity); + return username ? env->NewStringUTF(username) : NULL; +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactDisplayName(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneAddress* identity = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + const char * displayname = linphone_address_get_display_name(identity); + return displayname ? env->NewStringUTF(displayname) : NULL; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearProxyConfigs(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_proxy_config((LinphoneCore*)lc); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 518137ca0..564cd1b45 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1280,6 +1280,16 @@ public interface LinphoneCore { */ void setPrimaryContact(String displayName, String username); + /** + * Returns the username used if no LinphoneProxyConfig configured + */ + String getPrimaryContactUsername(); + + /** + * Returns the display name used if no LinphoneProxyConfig configured + */ + String getPrimaryContactDisplayName(); + /** * Enable/Disable the use of SIP INFO for DTMFs */ diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index c9257d8c1..874281134 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -138,6 +138,8 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setIncomingTimeout(long nativePtr, int timeout); private native void setInCallTimeout(long nativePtr, int timeout); private native void setPrimaryContact(long nativePtr, String displayName, String username); + private native String getPrimaryContactUsername(long nativePtr); + private native String getPrimaryContactDisplayName(long nativePtr); private native void setChatDatabasePath(long nativePtr, String path); private native long[] getChatRooms(long nativePtr); @@ -894,6 +896,14 @@ class LinphoneCoreImpl implements LinphoneCore { setPrimaryContact(nativePtr, displayName, username); } + public synchronized String getPrimaryContactUsername() { + return getPrimaryContactUsername(nativePtr); + } + + public synchronized String getPrimaryContactDisplayName() { + return getPrimaryContactDisplayName(nativePtr); + } + private native void setUseSipInfoForDtmfs(long ptr, boolean use); public synchronized void setUseSipInfoForDtmfs(boolean use) { setUseSipInfoForDtmfs(nativePtr, use); From d48286fc97c29a66bac76d3a9d432d2baef81f8d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Oct 2013 15:29:54 +0200 Subject: [PATCH 783/909] add new test for early media and forking --- coreapi/chat.c | 14 ++------ coreapi/linphonecall.c | 4 ++- tester/call_tester.c | 78 ++++++++++++++++++++++++++++++++++++++++++ tester/marie_early_rc | 6 ++-- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 71ff7c423..a84c1c5c1 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -60,8 +60,8 @@ LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char * return NULL; } -static int chat_room_compare(LinphoneChatRoom* room, const char* to) { - return strcmp(linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room)), to); /*return 0 if equals*/ +bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ + return linphone_address_weak_equal(cr->peer_url,from); } /** @@ -72,10 +72,8 @@ static int chat_room_compare(LinphoneChatRoom* room, const char* to) { */ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) { MSList* found; -if (ms_list_size(lc->chatrooms) == 0) - return linphone_core_create_chat_room(lc, to); - found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) chat_room_compare, to); + found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) linphone_chat_room_matches, to); if (found != NULL) { return (LinphoneChatRoom*)found->data; } else { @@ -150,12 +148,6 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { _linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg)); } -bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ - if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) && - strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE; - return FALSE; -} - void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){ if (msg->message) //legacy API diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6b27f1333..56e8075df 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1595,6 +1595,7 @@ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ return !linphone_core_is_in_conference(lc) && (current==NULL || current==call); } + static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) { int i; for(i=0; icore; int used_pt=-1; @@ -2370,7 +2372,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse int disconnect_timeout = linphone_core_get_nortp_timeout(call->core); bool_t disconnected=FALSE; - if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){ + if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) && one_second_elapsed){ float audio_load=0, video_load=0; if (call->audiostream!=NULL){ if (call->audiostream->ms.ticker) diff --git a/tester/call_tester.c b/tester/call_tester.c index 54bef00d7..48c54a6a5 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -196,6 +196,7 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr 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); } @@ -1006,6 +1007,82 @@ static void early_media_call(void) { linphone_core_manager_destroy(pauline); } +static void early_media_call_forking(void) { + LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + MSList *lcs=NULL; + LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc); + LinphoneVideoPolicy pol; + LinphoneCall *marie1_call; + LinphoneCall *marie2_call; + LinphoneCall *pauline_call; + int dummy=0; + + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_set_user_agent(marie1->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + + linphone_core_enable_video(marie1->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie1->lc,&pol); + + 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); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000)); + + pauline_call=linphone_core_get_current_call(pauline->lc); + marie1_call=linphone_core_get_current_call(marie1->lc); + marie2_call=linphone_core_get_current_call(marie2->lc); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,3000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); + + linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*marie2 should get her call terminated*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,1000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} + static void simple_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1332,6 +1409,7 @@ test_t call_tests[] = { { "Call with media relay", call_with_media_relay}, { "Simple call compatibility mode", simple_call_compatibility_mode }, { "Early-media call", early_media_call }, + { "Early-media call forking", early_media_call_forking }, { "Call terminated by caller", call_terminated_by_caller }, { "Call without SDP", call_with_no_sdp}, { "Call paused resumed", call_paused_resumed }, diff --git a/tester/marie_early_rc b/tester/marie_early_rc index 36c302a4f..844959eae 100644 --- a/tester/marie_early_rc +++ b/tester/marie_early_rc @@ -1,7 +1,7 @@ [sip] -sip_port=5082 -sip_tcp_port=5082 -sip_tls_port=5083 +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 From 0e9de476d131cf2e2a39bf6bdf686a451e04d876 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 14 Oct 2013 16:54:57 +0200 Subject: [PATCH 784/909] add support for Kindle Fire --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4749e8333..9ca8792ce 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4749e833304efb1835bf4a5bcb584d6118945fef +Subproject commit 9ca8792ce66d5415253fe2201d67f95e8de48d05 From 054ecbbe901c207a776a0eb9c7e6cb0dc090875a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 15 Oct 2013 09:32:16 +0200 Subject: [PATCH 785/909] fix crash in case of out of dialog NOTIFY rejected by application because unknown from --- coreapi/address.c | 3 ++- coreapi/bellesip_sal/sal_op_presence.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/address.c b/coreapi/address.c index cd2542808..bb50fe30a 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; } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 836cc11c6..c7f548e18 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -201,8 +201,9 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req){ } else { sub_state=SalSubscribeActive; } + resp = sal_op_create_response_from_request(op, req, 200); /*answer first because the op may be destroyed by notify_presence */ op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); - resp = sal_op_create_response_from_request(op, req, 200); + } else { /* Formatting error in presence notification body. */ ms_error("Wrongly formatted presence notification received"); From d21c1a917f047de2a6deda8db576a3bea46283c9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 15 Oct 2013 10:40:17 +0200 Subject: [PATCH 786/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 9ca8792ce..ed8a6bd62 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9ca8792ce66d5415253fe2201d67f95e8de48d05 +Subproject commit ed8a6bd62f563fa29c139809e2eaf133fca9cf7a From 08c59397cbb5e34786f6cfb8187675ad501929ea Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 15 Oct 2013 12:04:23 +0200 Subject: [PATCH 787/909] Added JNI API to read video policies --- coreapi/linphonecore_jni.cc | 16 ++++++++++++++++ java/common/org/linphone/core/LinphoneCore.java | 17 +++++++++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 14 ++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index c98390f3c..87c6aa4c0 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1110,6 +1110,12 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv ,jboolean enable) { return (jint)linphone_core_enable_payload_type((LinphoneCore*)lc,(PayloadType*)pt,enable); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isPayloadTypeEnabled(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt) { + return (jboolean) linphone_core_payload_type_enabled((LinphoneCore*)lc, (PayloadType*)pt); +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableEchoCancellation(JNIEnv* env ,jobject thiz ,jlong lc @@ -2938,6 +2944,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); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 564cd1b45..af054d1d5 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -638,6 +638,12 @@ public interface LinphoneCore { * */ void enablePayloadType(PayloadType pt, boolean enable) throws LinphoneCoreException; + + /** + * Returns whether or not the payload is enabled in linphonecore. + */ + boolean isPayloadTypeEnabled(PayloadType pt); + /** * Enables or disable echo cancellation. * @param enable @@ -1162,6 +1168,17 @@ public interface LinphoneCore { * @param autoAccept video shall be accepter by default for incoming calls **/ void setVideoPolicy(boolean autoInitiate, boolean autoAccept); + + /** + * Gets the policy for the autoInitiate video + */ + boolean getVideoAutoInitiatePolicy(); + + /** + * Gets the policy for the autoAccept video + */ + boolean getVideoAutoAcceptPolicy(); + /** Set static picture to be used when "Static picture" is the video device * @param path to the static picture file * */ diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 874281134..d9856294e 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -72,6 +72,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native boolean isMicMuted(long nativePtr); private native long findPayloadType(long nativePtr, String mime, int clockRate, int channels); private native int enablePayloadType(long nativePtr, long payloadType, boolean enable); + private native boolean isPayloadTypeEnabled(long nativePtr, long payloadType); private native void enableEchoCancellation(long nativePtr,boolean enable); private native boolean isEchoCancellationEnabled(long nativePtr); private native Object getCurrentCall(long nativePtr) ; @@ -321,6 +322,10 @@ class LinphoneCoreImpl implements LinphoneCore { } } + public synchronized boolean isPayloadTypeEnabled(PayloadType pt) { + isValid(); + return isPayloadTypeEnabled(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } public synchronized void enableEchoCancellation(boolean enable) { isValid(); enableEchoCancellation(nativePtr, enable); @@ -788,6 +793,15 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void setVideoPolicy(boolean autoInitiate, boolean autoAccept) { setVideoPolicy(nativePtr, autoInitiate, autoAccept); } + private native boolean getVideoAutoInitiatePolicy(long nativePtr); + public synchronized boolean getVideoAutoInitiatePolicy() { + return getVideoAutoInitiatePolicy(nativePtr); + } + private native boolean getVideoAutoAcceptPolicy(long nativePtr); + public synchronized boolean getVideoAutoAcceptPolicy() { + return getVideoAutoAcceptPolicy(nativePtr); + } + private native void setStaticPicture(long nativePtr, String path); public synchronized void setStaticPicture(String path) { setStaticPicture(nativePtr, path); From 712dd480ca6d9ce3c28e4089d3fe1ed5ee437e61 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 15 Oct 2013 15:55:20 +0200 Subject: [PATCH 788/909] Added JNI API to search a LinphoneAuthInfo from username and realm --- coreapi/linphonecore_jni.cc | 12 ++++++++++++ java/common/org/linphone/core/LinphoneCore.java | 4 ++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 10 +++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 87c6aa4c0..853760bcb 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -850,6 +850,18 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getAuthInfosList(J return jAuthInfos; } +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_findAuthInfos(JNIEnv* env, jobject thiz, jlong lc, jstring jusername, jstring jrealm) { + const char* username = env->GetStringUTFChars(jusername, NULL); + const char* realm = jrealm ? env->GetStringUTFChars(jrealm, NULL) : NULL; + const LinphoneAuthInfo *authInfo = linphone_core_find_auth_info((LinphoneCore*)lc, realm, username); + + if (realm) + env->ReleaseStringUTFChars(jrealm, realm); + env->ReleaseStringUTFChars(jusername, username); + + return (jlong) authInfo; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearAuthInfos(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_all_auth_info((LinphoneCore*)lc); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index af054d1d5..9cf3adf9e 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -396,6 +396,10 @@ public interface LinphoneCore { */ LinphoneAuthInfo[] getAuthInfosList(); + /** + * Returns a matching auth info or null if no match found + */ + LinphoneAuthInfo findAuthInfo(String username, String realm); /** * Removes a auth info. * @param authInfo diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index d9856294e..2096ea3ee 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -107,6 +107,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native long[] listVideoPayloadTypes(long nativePtr); private native long[] getProxyConfigList(long nativePtr); private native long[] getAuthInfosList(long nativePtr); + private native long findAuthInfos(long nativePtr, String username, String realm); private native long[] listAudioPayloadTypes(long nativePtr); private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); @@ -1046,7 +1047,6 @@ class LinphoneCoreImpl implements LinphoneCore { return proxies; } - @Override public LinphoneAuthInfo[] getAuthInfosList() { long[] typesPtr = getAuthInfosList(nativePtr); if (typesPtr == null) return null; @@ -1059,4 +1059,12 @@ class LinphoneCoreImpl implements LinphoneCore { return authInfos; } + + public LinphoneAuthInfo findAuthInfo(String username, String realm) { + long ptr = findAuthInfos(nativePtr, username, realm); + if (ptr == 0) + return null; + + return new LinphoneAuthInfoImpl(ptr); + } } From aaf2c2d0e8f16f7204e3a055d1f04e8645f071eb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 15 Oct 2013 17:14:38 +0200 Subject: [PATCH 789/909] Added JNI API to get DTMF policy --- coreapi/linphonecore_jni.cc | 8 ++++++++ java/common/org/linphone/core/LinphoneCore.java | 10 ++++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 853760bcb..be6923cc5 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2638,10 +2638,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); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 9cf3adf9e..91ada7ac3 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1316,10 +1316,20 @@ public interface LinphoneCore { */ 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 diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 2096ea3ee..f41d9a973 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -924,10 +924,20 @@ class LinphoneCoreImpl implements LinphoneCore { 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() { From d02090876a21e5fee957f8fbd2b2fe34285ad7c2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 15 Oct 2013 17:36:14 +0200 Subject: [PATCH 790/909] remove some codecs on mobile platforms because they are not supported. --- coreapi/linphonecore.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1b349677d..674b8e3d8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -833,6 +833,13 @@ static codec_desc_t codec_pref_order[]={ static int find_codec_rank(const char *mime, int clock_rate){ int i; + +#ifdef __arm__ + /*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/ + if (strcasecmp(mime,"opus")==0){ + if (ms_get_cpu_count()==1) return RANK_END; + } +#endif for(i=0;codec_pref_order[i].name!=NULL;++i){ if (strcasecmp(codec_pref_order[i].name,mime)==0 && clock_rate==codec_pref_order[i].rate) return i; @@ -1137,6 +1144,14 @@ const char * linphone_core_get_version(void){ static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){ PayloadType *pt; + +#ifdef ANDROID + if (const_pt->channels==2){ + ms_message("Stereo %s codec not supported on this platform.",const_pt->mime_type); + return; + } +#endif + pt=payload_type_clone(const_pt); if (number==-1){ /*look for a free number */ @@ -1259,12 +1274,17 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif #ifdef VIDEO_ENABLED +/* we disable H263 on mobiles because this codec only supports CIF family sizes, and number of cameras don't support it. */ +#if !defined(ANDROID) && !defined(__ios) linphone_core_assign_payload_type(lc,&payload_type_h263,34,NULL); - linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); linphone_core_assign_payload_type(lc,&payload_type_h263_1998,98,"CIF=1;QCIF=1"); +#endif + linphone_core_assign_payload_type(lc,&payload_type_mp4v,99,"profile-level-id=3"); linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=42801F"); linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL); + + linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL); /* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */ /* linphone_core_assign_payload_type(&payload_type_h264,-1,"packetization-mode=1;profile-level-id=428014");*/ From f04dab8f103d7be12ad9b72bdfef87b37aea458e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 16 Oct 2013 09:45:04 +0200 Subject: [PATCH 791/909] Added JNI API to get proxyconfigs' prefix & escape plus --- coreapi/linphonecore_jni.cc | 11 +++++++++++ .../org/linphone/core/LinphoneProxyConfig.java | 12 ++++++++++++ .../org/linphone/core/LinphoneProxyConfigImpl.java | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index be6923cc5..12c210b44 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1462,10 +1462,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 @@ -1474,6 +1479,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 diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 83e8bbd5d..f06df31b9 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -84,6 +84,12 @@ public interface LinphoneProxyConfig { * @param prefix */ public void setDialPrefix(String prefix); + + /** + * Returns the automatically added international prefix to e164 phone numbers + */ + public String getDialPrefix(); + /** * * Sets whether liblinphone should replace "+" by "00" in dialed numbers (passed to * {@link LinphoneCore#invite(String)}). @@ -91,6 +97,12 @@ public interface LinphoneProxyConfig { */ public void setDialEscapePlus(boolean value); + /** + * Whether liblinphone should replace "+" by "00" in dialed numbers (passed to + * {@link LinphoneCore#invite(String)}). + */ + public boolean getDialEscapePlus(); + /** * get domain host name or ip * @return may be null diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 25168ea57..a62db0b85 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -65,12 +65,14 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native boolean isRegistered(long ptr); private native void setDialPrefix(long ptr, String prefix); + private native String getDialPrefix(long ptr); private native String normalizePhoneNumber(long ptr,String number); private native String getDomain(long ptr); private native void setDialEscapePlus(long ptr, boolean value); + private native boolean getDialEscapePlus(long ptr); private native String getRoute(long ptr); private native int setRoute(long ptr,String uri); @@ -108,12 +110,18 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public void setDialPrefix(String prefix) { setDialPrefix(nativePtr, prefix); } + public String getDialPrefix() { + return getDialPrefix(nativePtr); + } public String getDomain() { return getDomain(nativePtr); } public void setDialEscapePlus(boolean value) { setDialEscapePlus(nativePtr,value); } + public boolean getDialEscapePlus() { + return getDialEscapePlus(nativePtr); + } public String getIdentity() { return getIdentity(nativePtr); } From eea8bd18fe930f6ee4cc0bf9e5dd3e2c5f446c56 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 16 Oct 2013 12:09:25 +0200 Subject: [PATCH 792/909] do not display_warning() for bad uris --- coreapi/linphonecore.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 674b8e3d8..1b504d499 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2315,10 +2315,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) if (uri!=NULL){ return uri; } - /* else we could not do anything with url given by user, so display an error */ - if (lc->vtable.display_warning!=NULL){ - lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain")); - } + return NULL; } From eb9886df65cb7f9c5cc513b98e3844c385779af6 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 16 Oct 2013 12:20:14 +0200 Subject: [PATCH 793/909] accept in Wizzard usernames with digits --- gtk/setupwizard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index 47a9074f8..6b596dcc3 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -59,7 +59,7 @@ static int all_account_information_entered(GtkWidget *w) { if (gtk_entry_get_text_length(username) > 0 && gtk_entry_get_text_length(domain) > 0 && - g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{2,}$", gtk_entry_get_text(username), 0, 0) && + g_regex_match_simple("^[a-zA-Z0-9]+[a-zA-Z0-9.\\-_]{2,}$", gtk_entry_get_text(username), 0, 0) && g_regex_match_simple("^(sip:)?([a-zA-Z0-9]+([\\.-][a-zA-Z0-9]+)*)$", gtk_entry_get_text(domain), 0, 0)) { return 1; } From 5c6c5073dd716c5f9a9cbac8808f3df0aa0e2533 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 16 Oct 2013 12:39:42 +0200 Subject: [PATCH 794/909] Fix crash when entry in linphonerc is empty + don't convert commented entries --- tools/lpc2xml.c | 12 +++++++++--- tools/xml2lpc.c | 14 ++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index 39fd62b0e..77cd0cb1a 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -93,12 +93,18 @@ 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 *comment = "#"; + if (strncmp(comment, entry, strlen(comment)) == 0) { + lpc2xml_log(ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry); + return 0; + } + 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; diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c index c9a5c94e2..d02133674 100644 --- a/tools/xml2lpc.c +++ b/tools/xml2lpc.c @@ -114,15 +114,18 @@ static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) { static void dumpNode(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name); + xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name); } static void dumpAttr(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content); + xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content); } static void dumpContent(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content); + if (node->children) + xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content); + else + xml2lpc_log(ctx, XML2LPC_DEBUG, "content: "); } static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_context *ctx) { @@ -142,8 +145,11 @@ static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_co } } - value = (const char *)element->children->content; dumpContent((xmlNode *)element, ctx); + if (element->children) + value = (const char *)element->children->content; + else + value = ""; if(name != NULL) { const char *str = lp_config_get_string(ctx->lpc, sectionName, name, NULL); From a216dc8fb0ecae3b42a51f9d7bc3c098a053b41b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 16 Oct 2013 12:48:42 +0200 Subject: [PATCH 795/909] Fix for skipping commented entries --- tools/lpc2xml.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index 77cd0cb1a..46a71a2b9 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -93,12 +93,6 @@ 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 *comment = "#"; - if (strncmp(comment, entry, strlen(comment)) == 0) { - lpc2xml_log(ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry); - return 0; - } - const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL); if (content == NULL) { lpc2xml_log(ctx, LPC2XML_ERROR, "Issue when reading the lpc"); @@ -119,6 +113,13 @@ struct __processSectionCtx { static void processSection_cb(const char *entry, struct __processSectionCtx *ctx) { if(ctx->ret == 0) { + const char *comment = "#"; + if (strncmp(comment, entry, strlen(comment)) == 0) { + lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry); + ctx->ret = 0; + return; + } + xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL); if(node == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"entry\" element"); From 107fb22c07a2372cdaf4d02687d828ec8f044170 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 16 Oct 2013 14:53:32 +0200 Subject: [PATCH 796/909] Fix XML2LPC and LPC2XML converters JNI log callbacks --- tools/lpc2xml_jni.cc | 13 +++++++++---- tools/xml2lpc_jni.cc | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) 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/xml2lpc_jni.cc b/tools/xml2lpc_jni.cc index fd72c6895..a242e7ce8 100644 --- a/tools/xml2lpc_jni.cc +++ b/tools/xml2lpc_jni.cc @@ -26,6 +26,7 @@ extern "C" { #endif #include +#include "mediastreamer2/mscommon.h" struct jni_xml2lpc_ctx { JNIEnv *env; @@ -52,9 +53,13 @@ extern "C" void Java_org_linphone_tools_Xml2Lpc_callback (void *ctx, xml2lpc_log char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); - jstring javaString = env->NewStringUTF(buffer); - jint javaLevel = level; - my_jni::callVoidMethod(env, obj, "Xml2Lpc", "printLog", "(ILjava/lang/String;)V", javaLevel, javaString); + + if (level == XML2LPC_ERROR) + ms_error("%s", buffer); + else if (level == XML2LPC_WARNING) + ms_warning("%s", buffer); + else + ms_message("%s", buffer); } } From db7c47f3e8754b52226a06169061401e36e375b2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 17 Oct 2013 15:27:24 +0200 Subject: [PATCH 797/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index ed8a6bd62..b3fcffa61 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ed8a6bd62f563fa29c139809e2eaf133fca9cf7a +Subproject commit b3fcffa61d18859dc69350c44adf98f841b9245d From 5cfb2710b1775688ff5ac133f4a7bd6ff9048e20 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Oct 2013 15:31:08 +0200 Subject: [PATCH 798/909] Fix guess_contact_for_register when identity contains display name --- coreapi/proxy.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index b7edfdb81..3e692c44b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -275,15 +275,28 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ host=linphone_address_get_domain (proxy); if (host!=NULL){ int localport = -1; - const char *localip = NULL; char *tmp; + char *tmp2; + LinphoneAddress *identity; LinphoneAddress *contact; - if (obj->contact_params) - tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params); - else + if (obj->contact_params) { + // We want to add a list of contacts params to the linphone address + // We remove the display name in the identity (if present) to prevent a failure in the parsing of the address due to the quotes + identity = linphone_address_new(obj->reg_identity); + if (identity) { + tmp2 = linphone_address_as_string_uri_only(identity); + tmp = ms_strdup_printf("%s;%s", tmp2, obj->contact_params); + linphone_address_destroy(identity); + ms_free(tmp2); + } else { + tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params); + } + } + else { tmp = strdup(obj->reg_identity); + } contact = linphone_address_new(tmp); if (!contact) { From 08d5cbbe2c5bb72b3c9c210afc28b853b041941c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 18 Oct 2013 10:24:40 +0200 Subject: [PATCH 799/909] fix big crash in linphone_core_get_or_create_chat_room() --- coreapi/chat.c | 19 ++++++++++++------- coreapi/linphonecore.c | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index a84c1c5c1..d220b0119 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -71,14 +71,19 @@ bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *f * @return #LinphoneChatRoom where messaging can take place. */ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) { - MSList* found; - - found = ms_list_find_custom(lc->chatrooms, (MSCompareFunc) linphone_chat_room_matches, to); - if (found != NULL) { - return (LinphoneChatRoom*)found->data; - } else { - return linphone_core_create_chat_room(lc, to); + LinphoneAddress *to_addr=linphone_core_interpret_url(lc,to); + LinphoneChatRoom *ret; + + if (to_addr==NULL){ + ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s",to); + return NULL; } + ret=linphone_core_get_chat_room(lc,to_addr); + linphone_address_destroy(to_addr); + if (!ret){ + ret=linphone_core_create_chat_room(lc,to); + } + return ret; } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1b504d499..c95bfc69a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5797,7 +5797,7 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) } /** - * Specifiies a ring back tone to be played to far end during incoming calls. + * Specifies a ring back tone to be played to far end during incoming calls. **/ void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){ if (lc->sound_conf.ringback_tone){ From c5dc16ed5de0c2666b2664c445578d0d93a7160b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 18 Oct 2013 11:21:41 +0200 Subject: [PATCH 800/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b3fcffa61..756e3d94b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b3fcffa61d18859dc69350c44adf98f841b9245d +Subproject commit 756e3d94b1711a82723779e0583019cec580596d From 5f32fd7e429a65eb658a8a87ad0b3f04d62cea94 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 18 Oct 2013 22:15:34 +0200 Subject: [PATCH 801/909] stop refreshing register when network is off. --- coreapi/linphonecore.c | 1 + coreapi/private.h | 1 + coreapi/proxy.c | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c95bfc69a..ab5897400 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5665,6 +5665,7 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu 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; diff --git a/coreapi/private.h b/coreapi/private.h index 57228ad3c..1c670ce93 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -240,6 +240,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj); void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); /* * returns service route as defined in as defined by rfc3608, might be a list instead of just one. diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 3e692c44b..dd34e49fe 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -266,6 +266,17 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){ linphone_proxy_config_done(obj); } +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj){ + if (obj->publish_op){ + sal_op_release(obj->publish_op); + obj->publish_op=NULL; + } + if (obj->op){ + sal_op_release(obj->op); + obj->op=NULL; + } +} + LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *ret=NULL; LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); From 6781e3cdd65ab53240514073b785b0fdcade7251 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 21 Oct 2013 17:38:45 +0200 Subject: [PATCH 802/909] Android.mk in one file. --- build/android/Android.mk | 190 ++++++++++++++++++++++++++++++++++- build/android/common.mk | 211 --------------------------------------- 2 files changed, 189 insertions(+), 212 deletions(-) delete mode 100644 build/android/common.mk diff --git a/build/android/Android.mk b/build/android/Android.mk index 819b50fcb..f88c0e117 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -23,7 +23,195 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi include $(CLEAR_VARS) -include $(linphone-root-dir)/submodules/linphone/build/android/common.mk +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 \ + bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_call_transfer.c \ + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_events.c \ + bellesip_sal/sal_sdp.c \ + sal.c \ + offeranswer.c \ + callbacks.c \ + linphonecall.c \ + conference.c \ + ec-calibrator.c \ + linphone_tunnel_config.c \ + message_storage.c \ + info.c \ + event.c + +ifndef LINPHONE_VERSION +LINPHONE_VERSION = "Devel" +endif + +LOCAL_CFLAGS += \ + -D_BYTE_ORDER=_LITTLE_ENDIAN \ + -DORTP_INET6 \ + -DINET6 \ + -DENABLE_TRACE \ + -DHAVE_CONFIG_H \ + -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ + -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ + -DUSE_BELLESIP + +LOCAL_CFLAGS += -DIN_LINPHONE + +ifeq ($(_BUILD_VIDEO),1) +LOCAL_CFLAGS += -DVIDEO_ENABLED +ifeq ($(BUILD_X264),1) +LOCAL_CFLAGS += -DHAVE_X264 +endif +endif + +ifeq ($(USE_JAVAH),1) +LOCAL_CFLAGS += -DUSE_JAVAH +endif + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../build/android \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include \ + $(LOCAL_PATH)/../../belle-sip/include \ + $(LOCAL_PATH)/../../../gen \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 + +LOCAL_LDLIBS += -llog -ldl + +LOCAL_STATIC_LIBRARIES := \ + cpufeatures \ + libmediastreamer2 \ + libortp \ + libbellesip \ + libgsm \ + liblpxml2 + + +ifeq ($(BUILD_TUNNEL),1) +LOCAL_CFLAGS +=-DTUNNEL_ENABLED +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src +LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc +LOCAL_STATIC_LIBRARIES += libtunnelclient +else +LOCAL_SRC_FILES += linphone_tunnel_stubs.c +endif + + +_BUILD_AMR=0 +ifneq ($(BUILD_AMRNB), 0) +_BUILD_AMR=1 +endif + +ifneq ($(BUILD_AMRWB), 0) +_BUILD_AMR=1 +endif + +ifneq ($(_BUILD_AMR), 0) +LOCAL_CFLAGS += -DHAVE_AMR +LOCAL_STATIC_LIBRARIES += \ + libmsamr \ + libopencoreamr +endif + +ifneq ($(BUILD_AMRWB), 0) +LOCAL_STATIC_LIBRARIES += \ + libvoamrwbenc +endif + + +ifeq ($(BUILD_SILK),1) +LOCAL_CFLAGS += -DHAVE_SILK +LOCAL_STATIC_LIBRARIES += libmssilk +endif + +ifeq ($(BUILD_G729),1) +LOCAL_CFLAGS += -DHAVE_G729 +LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729 +endif + +ifeq ($(_BUILD_VIDEO),1) +LOCAL_LDLIBS += -lGLESv2 +LOCAL_STATIC_LIBRARIES += libvpx +ifeq ($(BUILD_X264),1) +LOCAL_STATIC_LIBRARIES += \ + libmsx264 \ + libx264 +endif +endif + +ifeq ($(BUILD_UPNP),1) +LOCAL_CFLAGS += -DBUILD_UPNP +LOCAL_SRC_FILES += upnp.c +endif + +LOCAL_STATIC_LIBRARIES += libspeex + +ifeq ($(BUILD_SRTP), 1) + LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) +endif + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_CFLAGS += -DHAVE_ILBC=1 +LOCAL_STATIC_LIBRARIES += libmsilbc +endif + +LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) +LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) +LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) + +ifeq ($(BUILD_GPLV3_ZRTP),1) + LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone + LOCAL_SHARED_LIBRARIES += libzrtpcpp +endif + +ifeq ($(BUILD_SRTP),1) + LOCAL_SHARED_LIBRARIES += libsrtp +endif + +ifeq ($(BUILD_REMOTE_PROVISIONING),1) +LOCAL_SRC_FILES += ../tools/xml2lpc.c \ + ../tools/xml2lpc_jni.cc \ + ../tools/lpc2xml.c \ + ../tools/lpc2xml_jni.cc + +endif + +ifeq ($(BUILD_SQLITE),1) +LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED +LOCAL_STATIC_LIBRARIES += liblinsqlite +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../externals/sqlite3/ +endif + +ifeq ($(BUILD_OPUS),1) +LOCAL_STATIC_LIBRARIES += libopus +endif +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ diff --git a/build/android/common.mk b/build/android/common.mk deleted file mode 100644 index c027002a4..000000000 --- a/build/android/common.mk +++ /dev/null @@ -1,211 +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 \ - bellesip_sal/sal_address_impl.c \ - bellesip_sal/sal_impl.c \ - bellesip_sal/sal_op_call.c \ - bellesip_sal/sal_op_call_transfer.c \ - bellesip_sal/sal_op_impl.c \ - bellesip_sal/sal_op_message.c \ - bellesip_sal/sal_op_presence.c \ - bellesip_sal/sal_op_registration.c \ - bellesip_sal/sal_op_publish.c \ - bellesip_sal/sal_op_info.c \ - bellesip_sal/sal_op_events.c \ - bellesip_sal/sal_sdp.c \ - sal.c \ - offeranswer.c \ - callbacks.c \ - linphonecall.c \ - conference.c \ - ec-calibrator.c \ - linphone_tunnel_config.c \ - message_storage.c \ - info.c \ - event.c - -ifndef LINPHONE_VERSION -LINPHONE_VERSION = "Devel" -endif - -LOCAL_CFLAGS += \ - -D_BYTE_ORDER=_LITTLE_ENDIAN \ - -DORTP_INET6 \ - -DINET6 \ - -DENABLE_TRACE \ - -DHAVE_CONFIG_H \ - -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ - -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -DUSE_BELLESIP - -LOCAL_CFLAGS += -DIN_LINPHONE - -ifeq ($(_BUILD_VIDEO),1) -LOCAL_CFLAGS += -DVIDEO_ENABLED -ifeq ($(BUILD_X264),1) -LOCAL_CFLAGS += -DHAVE_X264 -endif -endif - -ifeq ($(USE_JAVAH),1) -LOCAL_CFLAGS += -DUSE_JAVAH -endif - -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH) \ - $(LOCAL_PATH)/../include \ - $(LOCAL_PATH)/../build/android \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../belle-sip/include \ - $(LOCAL_PATH)/../../../gen \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 - -LOCAL_LDLIBS += -llog -ldl - -LOCAL_STATIC_LIBRARIES := \ - cpufeatures \ - libmediastreamer2 \ - libortp \ - libbellesip \ - libgsm \ - liblpxml2 - - -ifeq ($(BUILD_TUNNEL),1) -LOCAL_CFLAGS +=-DTUNNEL_ENABLED -LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src -LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc -LOCAL_STATIC_LIBRARIES += libtunnelclient -else -LOCAL_SRC_FILES += linphone_tunnel_stubs.c -endif - - -_BUILD_AMR=0 -ifneq ($(BUILD_AMRNB), 0) -_BUILD_AMR=1 -endif - -ifneq ($(BUILD_AMRWB), 0) -_BUILD_AMR=1 -endif - -ifneq ($(_BUILD_AMR), 0) -LOCAL_CFLAGS += -DHAVE_AMR -LOCAL_STATIC_LIBRARIES += \ - libmsamr \ - libopencoreamr -endif - -ifneq ($(BUILD_AMRWB), 0) -LOCAL_STATIC_LIBRARIES += \ - libvoamrwbenc -endif - - -ifeq ($(BUILD_SILK),1) -LOCAL_CFLAGS += -DHAVE_SILK -LOCAL_STATIC_LIBRARIES += libmssilk -endif - -ifeq ($(BUILD_G729),1) -LOCAL_CFLAGS += -DHAVE_G729 -LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729 -endif - -ifeq ($(_BUILD_VIDEO),1) -LOCAL_LDLIBS += -lGLESv2 -LOCAL_STATIC_LIBRARIES += libvpx -ifeq ($(BUILD_X264),1) -LOCAL_STATIC_LIBRARIES += \ - libmsx264 \ - libx264 -endif -endif - -ifeq ($(BUILD_UPNP),1) -LOCAL_CFLAGS += -DBUILD_UPNP -LOCAL_SRC_FILES += upnp.c -endif - -LOCAL_STATIC_LIBRARIES += libspeex - -ifeq ($(BUILD_SRTP), 1) - LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) -endif - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_CFLAGS += -DHAVE_ILBC=1 -LOCAL_STATIC_LIBRARIES += libmsilbc -endif - -LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) -LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) -LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) - -ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone - LOCAL_SHARED_LIBRARIES += libzrtpcpp -endif - -ifeq ($(BUILD_SRTP),1) - LOCAL_SHARED_LIBRARIES += libsrtp -endif - -ifeq ($(BUILD_REMOTE_PROVISIONING),1) -LOCAL_SRC_FILES += ../tools/xml2lpc.c \ - ../tools/xml2lpc_jni.cc \ - ../tools/lpc2xml.c \ - ../tools/lpc2xml_jni.cc - -endif - -ifeq ($(BUILD_SQLITE),1) -LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED -LOCAL_STATIC_LIBRARIES += liblinsqlite -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH)/../../externals/sqlite3/ -endif - -ifeq ($(BUILD_SQLITE),1) -LOCAL_STATIC_LIBRARIES += libopus -endif -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) -LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) - From 20b887e7286fa49c65d2f53e246ba5f52a89e6bf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 21 Oct 2013 17:39:00 +0200 Subject: [PATCH 803/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 756e3d94b..3118df10d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 756e3d94b1711a82723779e0583019cec580596d +Subproject commit 3118df10d465c60244646d7c6a43321bfc595e92 From 340b212cc98c73667f28bb754f76568ad3207b17 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 22 Oct 2013 10:44:15 +0200 Subject: [PATCH 804/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3118df10d..eebfb6836 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3118df10d465c60244646d7c6a43321bfc595e92 +Subproject commit eebfb6836cd9326a89593bf837ac2790900357cd From c795fdf0291db3f9adb4fcc27fb1ef84a8f3c8af Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 22 Oct 2013 10:50:06 +0200 Subject: [PATCH 805/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index eebfb6836..60e63c3dd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit eebfb6836cd9326a89593bf837ac2790900357cd +Subproject commit 60e63c3dd114ac1b86faf424a5b9ce31750a1ae3 From 0a02112486f8c3ab6ef242b6be7f65cb99e9d40a Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 23 Oct 2013 14:50:13 +0200 Subject: [PATCH 806/909] Update oRTP submodule to support iSAC --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 890e2306f..e96c55df4 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 890e2306fca77146648f061ae754bec18304d4b7 +Subproject commit e96c55df4436db74656d5feedf3e8fd12adb74e4 From 2bb4f7f66265dc6dc5a722e30260fa3c55c8c054 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 23 Oct 2013 14:50:53 +0200 Subject: [PATCH 807/909] Added iSAC payload type support in linphone --- coreapi/linphonecore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ab5897400..94a242a6e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1311,6 +1311,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=1"); + linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL); linphone_core_handle_static_payloads(lc); ms_init(); From c7d6cf0e5595996c87833bf66fcb9b046bd02a67 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 23 Oct 2013 15:13:31 +0200 Subject: [PATCH 808/909] implement uri headers --- coreapi/bellesip_sal/sal_op_impl.c | 8 +++--- coreapi/bellesip_sal/sal_op_presence.c | 2 +- tester/call_tester.c | 28 +++++++++++++++----- tester/certificates/{ => altname}/cacert.pem | 0 tester/certificates/cn/cacert.pem | 20 ++++++++++++++ tester/flexisip.conf | 2 +- tester/liblinphone_tester.c | 2 +- tester/presence_tester.c | 11 ++++++-- tester/register_tester.c | 8 +++--- 9 files changed, 61 insertions(+), 20 deletions(-) rename tester/certificates/{ => altname}/cacert.pem (100%) create mode 100644 tester/certificates/cn/cacert.pem diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 3bf2e5ea6..f22530892 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -128,12 +128,12 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { } else { from_header=belle_sip_header_from_create2("Anonymous ",belle_sip_random_token(token,sizeof(token))); } - to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); - req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); - - + /*make sure to preserve components like headers or port*/ + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)))); belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op)); + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); + req=belle_sip_request_create( req_uri, method, diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index c7f548e18..bdc58388b 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -201,7 +201,7 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req){ } else { sub_state=SalSubscribeActive; } - resp = sal_op_create_response_from_request(op, req, 200); /*answer first because the op may be destroyed by notify_presence */ + 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 { diff --git a/tester/call_tester.c b/tester/call_tester.c index 48c54a6a5..38133ee11 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -166,12 +166,16 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); if (!linphone_core_get_current_call_remote_address(callee_mgr->lc)) return 0; - if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { - CU_ASSERT_TRUE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); - } else { - CU_ASSERT_FALSE(linphone_address_weak_equal(caller_mgr->identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + else { + LinphoneAddress* callee_from=linphone_address_clone(caller_mgr->identity); + linphone_address_set_port(callee_from,0); /*remove port because port is never present in from header*/ + if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { + CU_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } else { + CU_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } + linphone_address_destroy(callee_from); } - if (callee_params) linphone_core_accept_call_with_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc),callee_params); else @@ -541,6 +545,13 @@ static void call_with_custom_headers(void) { LinphoneCallParams *params; const LinphoneCallParams *remote_params; const char *hvalue; + char* tmp=linphone_address_as_string_uri_only(marie->identity); + char tmp2[256]; + snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); + LinphoneAddress* marie_identity=linphone_address_new(tmp2); + ms_free(tmp); + linphone_address_destroy(marie->identity); + marie->identity=marie_identity; params=linphone_core_create_default_call_parameters(marie->lc); linphone_call_params_add_custom_header(params,"Weather","bad"); @@ -558,8 +569,11 @@ static void call_with_custom_headers(void) { remote_params=linphone_call_get_remote_params(c1); hvalue=linphone_call_params_get_custom_header(remote_params,"Weather"); CU_ASSERT_PTR_NOT_NULL(hvalue); - CU_ASSERT_TRUE(strcmp(hvalue,"bad")==0); - + CU_ASSERT_STRING_EQUAL(hvalue,"bad"); + hvalue=linphone_call_params_get_custom_header(remote_params,"uriHeader"); + CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_remote_contact(c1)); /*just to sleep*/ diff --git a/tester/certificates/cacert.pem b/tester/certificates/altname/cacert.pem similarity index 100% rename from tester/certificates/cacert.pem rename to tester/certificates/altname/cacert.pem diff --git a/tester/certificates/cn/cacert.pem b/tester/certificates/cn/cacert.pem new file mode 100644 index 000000000..2fd957d39 --- /dev/null +++ b/tester/certificates/cn/cacert.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/flexisip.conf b/tester/flexisip.conf index 3ebbeb7be..b4d39a5c0 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -461,7 +461,7 @@ nortpproxy=nortpproxy # Set the RTP direction during early media state (duplex, forward) # Default value: duplex -early-media-rtp-dir=duplex +#early-media-rtp-dir=duplex # The minimal value of SDP port range # Default value: 1024 diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 7b34e7f45..e795ab254 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -108,7 +108,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* sal_enable_test_features(lc->sal,TRUE); #ifndef ANDROID - snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path); + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cacert.pem", path); #else snprintf(rootcapath, sizeof(rootcapath), "%s/cacert.pem", path); #endif diff --git a/tester/presence_tester.c b/tester/presence_tester.c index bb3033f92..3df002b8f 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -153,12 +153,17 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph linphone_core_add_friend(caller_mgr->lc,friend); - result=wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_callee.number_of_LinphonePresenceActivityOnline+1); - result&=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_caller.number_of_LinphonePresenceActivityOnline+1); + result=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_caller.number_of_LinphonePresenceActivityOnline+1); + /*without proxy, callee cannot subscribe to caller + result&=wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_callee.number_of_LinphonePresenceActivityOnline+1); + */ CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1); + /*without proxy, callee cannot subscribe to caller CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1); + */ CU_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1); + ms_free(identity); return result; @@ -204,6 +209,7 @@ static void simple_subscribe(void) { linphone_core_manager_destroy(marie); + /*unsubscribe is not reported ?*/ CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ linphone_core_manager_destroy(pauline); @@ -226,6 +232,7 @@ static void call_with_presence(void) { LinphoneVideoPolicy pol={0}; linphone_core_set_video_policy(marie->lc,&pol); CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + CU_ASSERT_TRUE(subscribe_to_callee_presence(pauline,marie)); CU_ASSERT_TRUE(call(marie,pauline)); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone,1); diff --git a/tester/register_tester.c b/tester/register_tester.c index 7ec8881e0..043b15c3c 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -530,14 +530,14 @@ static void tls_certificate_failure(){ mgr=linphone_core_manager_new2("pauline_rc",FALSE); lc=mgr->lc; - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_set_network_reachable(lc,TRUE); CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); linphone_core_set_root_ca(mgr->lc,NULL); /*no root ca*/ linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,2)); - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); @@ -575,7 +575,7 @@ static void tls_alt_name_register(){ mgr=linphone_core_manager_new2("pauline_alt_rc",FALSE); lc=mgr->lc; - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); @@ -590,7 +590,7 @@ static void tls_wildcard_register(){ mgr=linphone_core_manager_new2("pauline_wild_rc",FALSE); lc=mgr->lc; - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cacert.pem", liblinphone_tester_file_prefix); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,2)); From 9ef261f66e1de84855f9a4fba4d990fff401ead1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 23 Oct 2013 15:57:00 +0200 Subject: [PATCH 809/909] Fix compilation with tunnel on Android. --- coreapi/TunnelManager.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index d88360a9a..e6063878a 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -397,8 +397,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; @@ -408,7 +412,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*/ From 0933640e54f37e3521578f979d44e84ca6e795f7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 24 Oct 2013 15:19:30 +0200 Subject: [PATCH 810/909] Add API to know if tunnel auto detect is enabled. --- coreapi/linphone_tunnel.cc | 7 +++++++ coreapi/linphone_tunnel.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index 079074aa8..151755078 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -36,6 +36,7 @@ LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ struct _LinphoneTunnel { belledonnecomm::TunnelManager *manager; MSList *config_list; + bool_t auto_detect_enabled; }; extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){ @@ -225,6 +226,7 @@ void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ } void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ + tunnel->auto_detect_enabled = FALSE; lp_config_set_int(config(tunnel),"tunnel","enabled",(int)enabled); bcTunnel(tunnel)->enable(enabled); } @@ -311,9 +313,14 @@ void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ } void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ + tunnel->auto_detect_enabled = TRUE; bcTunnel(tunnel)->autoDetect(); } +bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) { + return tunnel->auto_detect_enabled; +} + static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){ ortp_logv(level,fmt,args); } diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index 9f6302eec..cff8fc532 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -195,6 +195,13 @@ LINPHONE_PUBLIC void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); */ LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); +/** + * Tells whether tunnel auto detection is enabled. + * @param[in] tunnel LinphoneTunnel object. + * @return TRUE if auto detection is enabled, FALSE otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel); + /** * Set an optional http proxy to go through when connecting to tunnel server. * @param tunnel LinphoneTunnel object From aa691efabbbbb0738b8acb411a3ba2a10fe5b04d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 28 Oct 2013 10:35:56 +0100 Subject: [PATCH 811/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 60e63c3dd..a10500648 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 60e63c3dd114ac1b86faf424a5b9ce31750a1ae3 +Subproject commit a1050064829f616835ce23f3ed538d10f3456fd5 From 7390fca8b26fdc3eb033fa4d969d68bde9ee401f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 29 Oct 2013 15:44:39 +0100 Subject: [PATCH 812/909] fix clang warnings One can't be fixed: linker complaining about -pthread. This comes from .la files installed by macports. Meanwhile, it is necessary to use --disable-strict on macos until macport moves to clang. --- README.macos | 2 +- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.macos b/README.macos index b69843be1..87817ac54 100644 --- a/README.macos +++ b/README.macos @@ -77,7 +77,7 @@ The softwares below need to be compiled manually. To ensure compatibility with m Then or otherwise, do: - $ ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp && make + $ ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make Install to /opt/local diff --git a/mediastreamer2 b/mediastreamer2 index a10500648..e7483d24d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a1050064829f616835ce23f3ed538d10f3456fd5 +Subproject commit e7483d24d6fb0823b0d72157fa3112104c6ddada diff --git a/oRTP b/oRTP index e96c55df4..120e58e2c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit e96c55df4436db74656d5feedf3e8fd12adb74e4 +Subproject commit 120e58e2c12d608ecb7a2f0c4ae91768cb1862a0 From 61c2fbf964c25f984cbc89c44ad78b828baa79ed Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 29 Oct 2013 16:05:58 +0100 Subject: [PATCH 813/909] use internal linphone_core_send_presence() method to send on-the-phone notification when a call is starting and restore to user's presence when last call is terminated. This allows to use publish if relevant, while previous method could only send NOTIFY. --- coreapi/linphonecall.c | 11 +++++++---- coreapi/linphonecore.c | 12 +++++------- coreapi/private.h | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 56e8075df..695050ea4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -425,9 +425,12 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; - model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); - linphone_core_notify_all_friends(call->core,model); - linphone_presence_model_unref(model); + if (call->core->calls==NULL){ + /*there were no call, and now there is a call, send an on-the-phone presence notification automatically*/ + model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); + linphone_core_send_presence(call->core,model); + linphone_presence_model_unref(model); + } linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ @@ -635,7 +638,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){ } if (ms_list_size(lc->calls)==0) - linphone_core_notify_all_friends(lc,lc->presence_model); + linphone_core_send_presence(lc,lc->presence_model); linphone_core_conference_check_uninit(lc); if (call->ringing_beep){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 94a242a6e..9ac7e8220 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3747,15 +3747,13 @@ void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const c linphone_core_set_presence_model(lc, presence); } -void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence) { - // TODO: Check that the presence timestamp is newer than the last sent presence. +void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence){ linphone_core_notify_all_friends(lc,presence); - /* - 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); +} + +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); diff --git a/coreapi/private.h b/coreapi/private.h index 1c670ce93..bcdc2a565 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -296,6 +296,7 @@ static inline void set_string(char **dest, const char *src){ 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_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); From b012c49dabf1ac94d38bbd5dbf3eaf56269d1fd3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 30 Oct 2013 12:25:05 +0100 Subject: [PATCH 814/909] answer 481 to unmatched CANCELs (instead of 501) --- coreapi/bellesip_sal/sal_impl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f1ce73599..617af211e 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -222,6 +222,10 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve 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")); From ea32e556f37ac04e3ad038c01da4d28759f39ffc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 30 Oct 2013 16:30:03 +0100 Subject: [PATCH 815/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e7483d24d..47b45965f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e7483d24d6fb0823b0d72157fa3112104c6ddada +Subproject commit 47b45965f591b0b09a978b3a525cc91d2bb7cb80 From 23bca78eef25e0bb2fdd54b9525451f837dba412 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 31 Oct 2013 10:20:11 +0100 Subject: [PATCH 816/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 47b45965f..51bd53fd7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 47b45965f591b0b09a978b3a525cc91d2bb7cb80 +Subproject commit 51bd53fd77f032af85dbc03cd81c886c4da364c0 From b47a179309e59b95ac62c5f21fa080d29a024998 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 31 Oct 2013 17:34:58 +0100 Subject: [PATCH 817/909] add linphone_core_find_friend() --- coreapi/friend.c | 42 ++++++++++++---------------------------- coreapi/linphonefriend.h | 9 +++++++++ 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 22a2a24c2..c8417e22c 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -516,40 +516,22 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){ return lf->refkey; } -static bool_t username_match(const char *u1, const char *u2){ - if (u1==NULL && u2==NULL) return TRUE; - if (u1 && u2 && strcasecmp(u1,u2)==0) return TRUE; - return FALSE; +LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneFriend *lf=NULL; + MSList *elem; + for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ + lf=(LinphoneFriend*)elem->data; + if (linphone_address_weak_equal(lf->uri,addr)) + break; + lf=NULL; + } + return lf; } LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){ LinphoneAddress *puri=linphone_address_new(uri); - const MSList *elem; - const char *username; - const char *domain; - 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; } diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 101c9f62f..66fbcea8e 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -372,9 +372,18 @@ LINPHONE_PUBLIC void linphone_core_notify_all_friends(LinphoneCore *lc, Linphone * @param[in] lc #LinphoneCore object. * @param[in] addr The address to use to search the friend. * @returns The #LinphoneFriend object corresponding to the given address. + * @deprecated use linphone_core_find_friend() instead. */ LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); +/** + * Search a LinphoneFriend by its address. + * @param[in] lc #LinphoneCore object. + * @param[in] addr The address to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given address. + */ +LINPHONE_PUBLIC LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr); + /** * Search a LinphoneFriend by its reference key. * @param[in] lc #LinphoneCore object. From 34950ccb8aa3337bae583c73722a8c1030228ee9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 31 Oct 2013 18:06:11 +0100 Subject: [PATCH 818/909] fix problems with chat in GTK interface due to SIP uris not compared properly. --- gtk/chat.c | 10 +++++----- gtk/friendlist.c | 33 ++++++++++++++++++++++----------- gtk/linphone.h | 2 ++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/gtk/chat.c b/gtk/chat.c index b1d0ec320..bfb6529e8 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -76,7 +76,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { } g_hash_table_destroy(table); g_object_set_data(G_OBJECT(w),"cr",NULL); - g_object_set_data(G_OBJECT(friendlist),"from",NULL); + linphone_gtk_friend_list_set_active_address(NULL); gtk_widget_destroy(w); } @@ -467,12 +467,12 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, GtkWidget *w; gboolean send=TRUE; /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ - char *from=linphone_address_as_string_uri_only( linphone_chat_message_get_from ( msg ) ); + const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); if ( w!=NULL ) { - char *from_chatview= ( char * ) g_object_get_data ( G_OBJECT ( friendlist ),"from" ); - if ( g_strcmp0 ( from,from_chatview ) ==0 ) { + const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); + if (linphone_address_weak_equal(from,from_chatview)) { send=TRUE; } else { if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { @@ -487,7 +487,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } w=linphone_gtk_init_chatroom ( room,linphone_chat_message_get_from ( msg ) ); g_object_set_data ( G_OBJECT ( friendlist ),"chatview", ( gpointer ) w ); - g_object_set_data ( G_OBJECT ( friendlist ),"from",from ); + linphone_gtk_friend_list_set_active_address(from); } #ifdef HAVE_GTK_OSX diff --git a/gtk/friendlist.c b/gtk/friendlist.c index ddf324734..523cf13b3 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -197,9 +197,9 @@ void linphone_gtk_delete_history(GtkWidget *button){ gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); linphone_chat_room_delete_history(cr); if(chat_view!=NULL){ - char *from=g_object_get_data(G_OBJECT(friendlist),"from"); - char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); - if(g_strcmp0(from,addr)==0){ + const LinphoneAddress *from=linphone_gtk_friend_list_get_active_address(); + const LinphoneAddress *addr=linphone_friend_get_address(lf); + if(linphone_address_weak_equal(from,addr)){ GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); GtkTextIter start; GtkTextIter end; @@ -246,6 +246,20 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } +void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + LinphoneAddress *old_addr=(LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from"); + g_object_set_data(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL); + if (old_addr) linphone_address_unref(old_addr); +} + +const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + return (const LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from"); +} + void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ GtkTreeIter iter; GtkListStore *store=NULL; @@ -256,12 +270,11 @@ void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ LinphoneFriend *lf=NULL; LinphoneChatRoom *cr=NULL; GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); - char *la_str=linphone_address_as_string(la); - lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),la_str); + lf=linphone_core_find_friend(linphone_gtk_get_core(),la); if(lf==NULL){ cr=linphone_gtk_create_chatroom(la); - g_object_set_data(G_OBJECT(friendlist),"from",la_str); + linphone_gtk_friend_list_set_active_address(la); if(chat_view==NULL){ chat_view=linphone_gtk_init_chatroom(cr,la); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view); @@ -276,17 +289,15 @@ void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ if (gtk_tree_model_get_iter_first(model,&iter)) { do{ const LinphoneAddress *uri; - char *lf_str; gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1); uri=linphone_friend_get_address(lf); - lf_str=linphone_address_as_string(uri); - if( g_strcmp0(lf_str,la_str)==0){ + if (linphone_address_weak_equal(uri,la)){ gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); if(cr==NULL){ cr=linphone_gtk_create_chatroom(uri); gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); } - g_object_set_data(G_OBJECT(friendlist),"from",linphone_address_as_string(uri)); + linphone_gtk_friend_list_set_active_address(uri); if(chat_view==NULL){ chat_view=linphone_gtk_init_chatroom(cr,uri); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view); @@ -345,7 +356,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); } page=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - g_object_set_data(G_OBJECT(friendlist),"from",linphone_address_as_string(uri)); + linphone_gtk_friend_list_set_active_address(uri); if(page==NULL){ page=linphone_gtk_init_chatroom(cr,uri); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)page); diff --git a/gtk/linphone.h b/gtk/linphone.h index f987b2abe..592c61588 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -108,6 +108,8 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, Linpho void linphone_gtk_friend_list_update_chat_picture(); void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); +void linphone_gtk_friend_set_active_address(const LinphoneAddress *addr); +const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void); void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data); void linphone_gtk_show_friends(void); void linphone_gtk_show_contact(LinphoneFriend *lf); From a7b1d33a267a7af20b7bbac41071d2af30e0cdb0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 1 Nov 2013 18:04:30 +0100 Subject: [PATCH 819/909] fix compilation error in gtk --- gtk/linphone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/linphone.h b/gtk/linphone.h index 592c61588..67fa27ebf 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -108,7 +108,7 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, Linpho void linphone_gtk_friend_list_update_chat_picture(); void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); -void linphone_gtk_friend_set_active_address(const LinphoneAddress *addr); +void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr); const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void); void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data); void linphone_gtk_show_friends(void); From 74e889fcc4ae3b61a3d632b108d8493590ccec9d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 4 Nov 2013 11:25:01 +0100 Subject: [PATCH 820/909] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 51bd53fd7..fef98f77e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 51bd53fd77f032af85dbc03cd81c886c4da364c0 +Subproject commit fef98f77eb71b4d985d64d1b9738fc4387e33865 From 2c087aa89ed078b94339afb25c825f5870a24691 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 4 Nov 2013 12:18:30 +0100 Subject: [PATCH 821/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index fef98f77e..c367be6e3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit fef98f77eb71b4d985d64d1b9738fc4387e33865 +Subproject commit c367be6e3c608581b14b66cb77cb173c3f539d72 From 811b453d06d74d0ffb04823ffc6335c7bc0b4085 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 4 Nov 2013 15:00:03 +0100 Subject: [PATCH 822/909] add a domain parameter in LinphoneAuthInfo, to workaround non-unicity of realm in real world. --- console/linphonec.c | 5 +- coreapi/authentication.c | 115 ++++++++++++++++++++------------ coreapi/bellesip_sal/sal_impl.c | 12 +--- coreapi/callbacks.c | 75 ++------------------- coreapi/linphonecore.h | 18 ++--- coreapi/private.h | 1 + coreapi/sal.c | 6 +- gtk/loginframe.c | 2 +- gtk/main.c | 7 +- include/sal/sal.h | 12 +--- tester/liblinphone_tester.c | 2 +- tester/liblinphone_tester.h | 2 +- tester/register_tester.c | 2 +- 13 files changed, 110 insertions(+), 149 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 6564bcb5b..1677760dd 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -117,8 +117,7 @@ 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); @@ -256,7 +255,7 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url * Linphone core callback */ static void -linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username) +linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { /* no prompt possible when using pipes or tcp mode*/ if (unix_socket){ diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 6095b1bc6..fd4e30c1c 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -37,9 +37,7 @@ * 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){ 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); @@ -57,6 +55,7 @@ static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ if (ai->passwd) obj->passwd=ms_strdup(ai->passwd); if (ai->ha1) obj->ha1=ms_strdup(ai->ha1); if (ai->realm) obj->realm=ms_strdup(ai->realm); + if (ai->domain) obj->domain=ms_strdup(ai->domain); obj->works=FALSE; obj->usecount=0; return obj; @@ -83,6 +82,11 @@ const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){ const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i){ return i->realm; } + +const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *i){ + return i->domain; +} + const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i){ return i->ha1; } @@ -121,7 +125,7 @@ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){ } /** - * Sets realm. + * Set realm. **/ void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm){ if (info->realm){ @@ -130,6 +134,19 @@ void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm){ } if (realm && strlen(realm)>0) info->realm=ms_strdup(realm); } + +/** + * Set domain for which this authentication is valid. This should not be necessary because realm is supposed to be unique and sufficient. + * However, many SIP servers don't set realm correctly, then domain has to be used to distinguish between several SIP account bearing the same username. +**/ +void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain){ + if (info->domain){ + ms_free(info->domain); + info->domain=NULL; + } + if (domain && strlen(domain)>0) info->domain=ms_strdup(domain); +} + /** * Sets ha1. **/ @@ -150,6 +167,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); } @@ -181,12 +199,16 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in 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)){ @@ -198,14 +220,10 @@ LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int passwd=lp_config_get_string(config,key,"passwd",NULL); ha1=lp_config_get_string(config,key,"ha1",NULL); realm=lp_config_get_string(config,key,"realm",NULL); - return linphone_auth_info_new(username,userid,passwd,ha1,realm); -} - -static bool_t key_match(const char *tmp1, const char *tmp2){ - if (tmp1==NULL && tmp2==NULL) return TRUE; - if (tmp1!=NULL && tmp2!=NULL && strcmp(tmp1,tmp2)==0) return TRUE; - return FALSE; - + domain=lp_config_get_string(config,key,"domain",NULL); + ret=linphone_auth_info_new(username,userid,passwd,ha1,realm); + linphone_auth_info_set_domain(ret,domain); + return ret; } static char * remove_quotes(char * input){ @@ -234,41 +252,56 @@ 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; + const LinphoneAuthInfo *ret=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; + if (username && pinfo->username && strcmp(username,pinfo->username)==0){ + if (realm && domain){ + if (pinfo->realm && strcmp(realm,pinfo->realm)==0 + && pinfo->domain && strcmp(domain,pinfo->domain)==0){ + return pinfo; } - ret=pinfo; - } - }else{ - /*return the exact authinfo, or an authinfo for which realm was not supplied yet*/ - if (pinfo->realm!=NULL){ - if (realm_match(pinfo->realm,realm) - && key_match(pinfo->username,username)) + }else if (realm){ + if (pinfo->realm && realm_match(realm,pinfo->realm)){ + if (ret!=NULL){ + ms_warning("Non unique realm found for %s",username); + return NULL; + } ret=pinfo; - }else{ - if (key_match(pinfo->username,username)) - candidate=pinfo; - } + } + }else return pinfo; } } - if (ret==NULL && candidate!=NULL) - ret=candidate; return ret; } +/** + * Find authentication info matching realm, username, domain criterias. + * First of all, (realm,username) pair are searched. If multiple results (which should not happen because realm are supposed to be unique), then domain is added to the search. + * @param lc the LinphoneCore + * @param realm the authentication 'realm' (optional) + * @param username the SIP username to be authenticated (mandatory) + * @param domain the SIP domain name (optional) + * @return a #LinphoneAuthInfo +**/ +const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ + const LinphoneAuthInfo *ai=NULL; + if (realm){ + ai=find_auth_info(lc,username,realm,NULL); + if (ai==NULL && domain){ + ai=find_auth_info(lc,username,realm,domain); + + } + } + if (ai==NULL){ + ai=find_auth_info(lc,username,NULL,NULL); + } + return ai; +} + static void write_auth_infos(LinphoneCore *lc){ MSList *elem; int i; @@ -297,7 +330,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) MSList *l; /* find if we are attempting to modify an existing auth info */ - ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); + ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (ai!=NULL){ lc->auth_info=ms_list_remove(lc->auth_info,ai); linphone_auth_info_destroy(ai); @@ -309,7 +342,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) 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); + ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username,info->domain); if (ai){ SalAuthInfo sai; MSList* proxy; @@ -346,7 +379,7 @@ void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *inf **/ void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){ LinphoneAuthInfo *r; - r=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); + r=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (r){ lc->auth_info=ms_list_remove(lc->auth_info,r); /*printf("len=%i newlen=%i\n",len,newlen);*/ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 617af211e..d43bc4878 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -433,15 +433,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ 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_legacy==NULL) - ctx->callbacks.auth_requested_legacy=(SalOnAuthRequestedLegacy)unimplemented_stub; -#ifdef USE_BELLESIP if (ctx->callbacks.auth_failure==NULL) ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub; -#else - if (ctx->callbacks.auth_success==NULL) - ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub; -#endif if (ctx->callbacks.register_success==NULL) ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; if (ctx->callbacks.register_failure==NULL) @@ -702,8 +695,9 @@ const char * sal_get_dns_user_hosts_file(const Sal *sal) { 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->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)); return auth_info; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index fe57a5dfd..ecd9f18a0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -718,68 +718,17 @@ static void call_released(SalOp *op){ }else ms_error("call_released() for already destroyed call ?"); } -static void auth_requested_legacy(SalOp *h, const char *realm, const char *username){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); - LinphoneCall *call=is_a_linphone_call(sal_op_get_user_pointer(h)); - - if (call && call->ping_op==h){ - /*don't request authentication for ping requests. Their purpose is just to get any - * answer to get the Via's received and rport parameters. - */ - ms_message("auth_requested(): ignored for ping request."); - return; - } - - ms_message("auth_requested() for realm=%s, username=%s",realm,username); - - if (ai && ai->works==FALSE && ai->usecount>=3){ - /*case we tried 3 times to authenticate, without success */ - /*Better is to stop (implemeted below in else statement), and retry later*/ - if (ms_time(NULL)-ai->last_use_time>30){ - ai->usecount=0; /*so that we can allow to retry */ - } - } - - if (ai && (ai->works || ai->usecount<3)){ - SalAuthInfo sai; - sai.username=ai->username; - sai.userid=ai->userid; - sai.realm=ai->realm; - sai.password=ai->passwd; - ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username); - sal_op_authenticate(h,&sai); - ai->usecount++; - ai->last_use_time=ms_time(NULL); - }else{ - if (ai && ai->works==FALSE) { - sal_op_cancel_authentication(h); - } - if (lc->vtable.auth_info_requested) - lc->vtable.auth_info_requested(lc,realm,username); - } -} -#ifdef USE_BELLESIP static void auth_failure(SalOp *op, SalAuthInfo* info) { LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (ai){ - ms_message("%s/%s authentication fails.",info->realm,info->username); + ms_message("%s/%s/%s authentication fails.",info->realm,info->username,info->domain); } if (lc->vtable.auth_info_requested) { - lc->vtable.auth_info_requested(lc,info->realm,info->username); + lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain); } } -#else -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; - } -} -#endif + 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); @@ -837,13 +786,6 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const cfg->publish_op=NULL; cfg->send_publish=cfg->publish; } - 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); - } - } } static void vfu_request(SalOp *op){ @@ -961,7 +903,7 @@ static void ping_reply(SalOp *op){ } static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { - LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); + 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; @@ -979,7 +921,7 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { return TRUE; } else { if (lc->vtable.auth_info_requested) { - lc->vtable.auth_info_requested(lc,sai->realm,sai->username); + lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); if (fill_auth_info(lc,sai)) { return TRUE; } @@ -1145,12 +1087,7 @@ SalCallbacks linphone_sal_callbacks={ call_terminated, call_failure, call_released, - auth_requested_legacy, -#ifdef USE_BELLESIP auth_failure, -#else - auth_success, -#endif register_success, register_failure, vfu_request, diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index dbf3779ec..94a4297ec 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -856,12 +856,14 @@ LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); LINPHONE_PUBLIC void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); +LINPHONE_PUBLIC void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain); LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *i); LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); /* you don't need those function*/ @@ -1043,7 +1045,7 @@ typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, Linphon * @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); +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. @@ -1427,10 +1429,10 @@ LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphonePr * 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 - * @param[in] passwd String containing the password part of the authentication credentials - * @param[in] ha1 String containing a hash of the password - * @param[in] realm String used to discriminate different SIP domains + * @param[in] userid String containing the username to use to calculate the authentication digest (optional) + * @param[in] passwd String containing the password of the authentication credentials (optional, either passwd or ha1 must be set) + * @param[in] ha1 String containing a ha1 hash of the password (optional, either passwd or ha1 must be set) + * @param[in] realm String used to discriminate different SIP authentication domains (optional) * @return #LinphoneAuthInfo with default values set * @ingroup authentication */ @@ -1438,13 +1440,13 @@ LINPHONE_PUBLIC LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore * 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); 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); LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index bcdc2a565..20397cefc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -417,6 +417,7 @@ struct _LinphoneAuthInfo char *userid; char *passwd; char *ha1; + char *domain; int usecount; time_t last_use_time; bool_t works; diff --git a/coreapi/sal.c b/coreapi/sal.c index f0d036fe7..49e70b3c6 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -472,16 +472,18 @@ 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); + ms_free(auth_info); } diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 08b90fe45..45da5480f 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -102,7 +102,7 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ linphone_address_set_username(from,username); } - ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from)); + ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from),NULL); /*display the last entered username, if not '?????'*/ if (linphone_address_get_username(from)[0]!='?') gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")), diff --git a/gtk/main.c b/gtk/main.c index 1de976c9e..fbe8dd698 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -55,7 +55,7 @@ static GtkWidget *the_ui=NULL; static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); @@ -1021,7 +1021,7 @@ void linphone_gtk_password_ok(GtkWidget *w){ gtk_widget_destroy(window); } -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){ +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ GtkWidget *w=linphone_gtk_create_window("password"); GtkWidget *label=linphone_gtk_get_widget(w,"message"); LinphoneAuthInfo *info; @@ -1034,12 +1034,13 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm return; } - msg=g_strdup_printf(_("Please enter your password for username %s\n at domain %s:"), + msg=g_strdup_printf(_("Please enter your password for username %s\n at realm %s:"), username,realm); gtk_label_set_markup(GTK_LABEL(label),msg); g_free(msg); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username); info=linphone_auth_info_new(username, NULL, NULL, NULL,realm); + linphone_auth_info_set_domain(info,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); diff --git a/include/sal/sal.h b/include/sal/sal.h index 5871cfdb9..51bb2dcac 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -336,6 +336,7 @@ typedef struct SalAuthInfo{ char *userid; char *password; char *realm; + char *domain; char *ha1; }SalAuthInfo; @@ -356,11 +357,7 @@ typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, co typedef void (*SalOnCallReleased)(SalOp *salop); typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); -#ifndef USE_BELLESIP -typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); -#else typedef void (*SalOnAuthFailure)(SalOp *op, SalAuthInfo* info); -#endif typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); typedef void (*SalOnVfuRequest)(SalOp *op); @@ -395,12 +392,7 @@ typedef struct SalCallbacks{ SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; SalOnCallReleased call_released; - SalOnAuthRequestedLegacy auth_requested_legacy; -#ifdef USE_BELLESIP SalOnAuthFailure auth_failure; -#else - SalOnAuthSuccess auth_success; -#endif SalOnRegisterSuccess register_success; SalOnRegisterFailure register_failure; SalOnVfuRequest vfu_request; @@ -429,7 +421,7 @@ typedef struct SalCallbacks{ SalAuthInfo* sal_auth_info_new(); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); -void sal_auth_info_delete(const SalAuthInfo* auth_info); +void sal_auth_info_delete(SalAuthInfo* auth_info); LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index e795ab254..740d02f4a 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -70,7 +70,7 @@ LinphoneAddress * create_linphone_address(const char * domain) { return addr; } -void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { +void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { stats* counters; LinphoneAuthInfo *info; ms_message("Auth info requested for user id [%s] at realm [%s]\n" diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 8d80eb2b6..ae1fe453d 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -195,7 +195,7 @@ void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const Linph void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); +void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); diff --git a/tester/register_tester.c b/tester/register_tester.c index 043b15c3c..1ee2dc453 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -268,7 +268,7 @@ static void authenticated_register_with_no_initial_credentials(){ linphone_core_manager_destroy(mgr); } -static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username) { +static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { stats* counters; ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username From 50f9d358046b1950e9d0aa3bf1f4527faa79697e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Nov 2013 16:28:50 +0100 Subject: [PATCH 823/909] Changes made to JNI and Java to match previous AuthInfo changes --- .../core/tutorials/TutorialBuddyStatus.java | 2 +- .../core/tutorials/TutorialRegistration.java | 2 +- coreapi/linphonecore_jni.cc | 58 ++++++++++++++----- .../org/linphone/core/LinphoneAuthInfo.java | 17 ++++++ .../org/linphone/core/LinphoneCore.java | 2 +- .../linphone/core/LinphoneCoreFactory.java | 4 +- .../linphone/core/LinphoneAuthInfoImpl.java | 28 ++++++++- .../core/LinphoneCoreFactoryImpl.java | 8 +-- .../org/linphone/core/LinphoneCoreImpl.java | 6 +- 9 files changed, 98 insertions(+), 29 deletions(-) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index 221867898..53b9331fb 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -161,7 +161,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { if (mySipPassword != null) { // create authentication structure from identity and add to linphone - lc.addAuthInfo(lcFactory.createAuthInfo(username, mySipPassword, null)); + lc.addAuthInfo(lcFactory.createAuthInfo(username, mySipPassword, null, domain)); } // create proxy config diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 98b74656c..93aa87d04 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -131,7 +131,7 @@ public class TutorialRegistration implements LinphoneCoreListener { if (password != null) { // create authentication structure from identity and add to linphone - lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null)); + lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null, domain)); } // create proxy config diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 12c210b44..13a3d0183 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -392,7 +392,7 @@ public: static void displayMessageCb(LinphoneCore *lc, const char *message) { } - static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username) { + static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { } static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) { @@ -850,13 +850,16 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getAuthInfosList(J return jAuthInfos; } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_findAuthInfos(JNIEnv* env, jobject thiz, jlong lc, jstring jusername, jstring jrealm) { +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 LinphoneAuthInfo *authInfo = linphone_core_find_auth_info((LinphoneCore*)lc, realm, username); + 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; @@ -870,18 +873,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_refreshRegisters(JNIEnv* linphone_core_refresh_registers((LinphoneCore*)lc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAuthInfo( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAuthInfo(JNIEnv* env ,jobject thiz ,jlong lc ,jlong pc) { linphone_core_add_auth_info((LinphoneCore*)lc,(LinphoneAuthInfo*)pc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate(JNIEnv* env ,jobject thiz ,jlong lc) { linphone_core_iterate((LinphoneCore*)lc); } -extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite(JNIEnv* env ,jobject thiz ,jlong lc ,jstring juri) { @@ -891,7 +894,7 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env env->ReleaseStringUTFChars(juri, uri); return lcd->getCall(env,lCall); } -extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress(JNIEnv* env ,jobject thiz ,jlong lc ,jlong to) { @@ -899,38 +902,38 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv return lcd->getCall(env, linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to)); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call) { linphone_core_terminate_call((LinphoneCore*)lc,(LinphoneCall*)call); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call, jint reason) { linphone_core_decline_call((LinphoneCore*)lc,(LinphoneCall*)call,(LinphoneReason)reason); } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress( JNIEnv* env +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress(JNIEnv* env ,jobject thiz ,jlong lc) { return (jlong)linphone_core_get_current_call_remote_address((LinphoneCore*)lc); } -extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall( JNIEnv* env +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall(JNIEnv* env ,jobject thiz ,jlong lc) { return (jboolean)linphone_core_in_call((LinphoneCore*)lc); } -extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePending( JNIEnv* env +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePending(JNIEnv* env ,jobject thiz ,jlong lc) { return (jboolean)linphone_core_inc_invite_pending((LinphoneCore*)lc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call) { @@ -1523,7 +1526,6 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getPasswor } else { return NULL; } - } /* * Class: org_linphone_core_LinphoneAuthInfoImpl @@ -1538,7 +1540,21 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getRealm } else { return NULL; } +} +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getDomain + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getDomain +(JNIEnv *env , jobject, jlong auth_info) { + const char* domain = linphone_auth_info_get_domain((LinphoneAuthInfo*)auth_info); + if (domain) { + return env->NewStringUTF(domain); + } else { + return NULL; + } } /* @@ -1579,6 +1595,20 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setRealm linphone_auth_info_set_realm((LinphoneAuthInfo*)auth_info,realm); if (realm) env->ReleaseStringUTFChars(jrealm, realm); } + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setDomain + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setDomain +(JNIEnv *env, jobject, jlong auth_info, jstring jdomain) { + const char* domain = jdomain ? env->GetStringUTFChars(jdomain, NULL) : NULL; + linphone_auth_info_set_domain((LinphoneAuthInfo*)auth_info, domain); + if (domain) + env->ReleaseStringUTFChars(jdomain, domain); +} + /* * Class: org_linphone_core_LinphoneAuthInfoImpl * Method: setUsername diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index 0213720eb..5e2744a1e 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -83,6 +83,23 @@ public interface LinphoneAuthInfo { */ void setHa1(String ha1); + /** + * Sets the domain + * @param domain + */ + void setDomain(String domain); + + /** + * Gets the domain + * @return the domain + */ + String getDomain(); + + /** + * Clones a current auth info + * @return the clone auth info + */ + LinphoneAuthInfo clone(); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 91ada7ac3..ef310bc9a 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -399,7 +399,7 @@ public interface LinphoneCore { /** * Returns a matching auth info or null if no match found */ - LinphoneAuthInfo findAuthInfo(String username, String realm); + LinphoneAuthInfo findAuthInfo(String username, String realm, String domain); /** * Removes a auth info. * @param authInfo diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 91f026ae0..dfbeb883b 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -54,7 +54,7 @@ abstract public class LinphoneCoreFactory { * @param userid user id as set in auth header * @param passwd * */ - abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm); + abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm, String domain); /** * create {@link LinphoneAuthInfo} * @param username @@ -63,7 +63,7 @@ abstract public class LinphoneCoreFactory { * @param ha1 * @param realm * */ - abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1,String realm); + abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1, String realm, String domain); abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException; abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException; diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java index feea5a3df..7d2b3dde2 100644 --- a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java @@ -32,17 +32,20 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { private native void setHa1(long ptr, String ha1); private native String getUserId(long ptr); private native String getHa1(long ptr); + private native String getDomain(long ptr); + private native void setDomain(long ptr, String domain); boolean ownPtr = false; - protected LinphoneAuthInfoImpl(String username,String password, String realm) { - this(username,null,password,null,null); + protected LinphoneAuthInfoImpl(String username,String password, String realm, String domain) { + this(username, null, password, null, null, domain); } - protected LinphoneAuthInfoImpl(String username, String userid, String passwd, String ha1,String realm) { + protected LinphoneAuthInfoImpl(String username, String userid, String passwd, String ha1, String realm, String domain) { nativePtr = newLinphoneAuthInfo(); this.setUsername(username); this.setUserId(userid); this.setPassword(passwd); this.setHa1(ha1); + this.setDomain(domain); ownPtr = true; } protected LinphoneAuthInfoImpl(long aNativePtr) { @@ -88,4 +91,23 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { setHa1(nativePtr,ha1); } + @Override + public void setDomain(String domain) { + setDomain(nativePtr, domain); + } + @Override + public String getDomain() { + return getDomain(nativePtr); + } + + public LinphoneAuthInfo clone() { + LinphoneAuthInfo clone = LinphoneCoreFactory.instance().createAuthInfo( + getUsername(), + getUserId(), + getPassword(), + getHa1(), + getRealm(), + getDomain()); + return clone; + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index fcca97e3b..3b242e00a 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -72,8 +72,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @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 @@ -145,8 +145,8 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public LinphoneAuthInfo createAuthInfo(String username, String userid, - String passwd, String ha1, String realm) { - return new LinphoneAuthInfoImpl(username,userid,passwd,ha1,realm); + String passwd, String ha1, String realm, String domain) { + return new LinphoneAuthInfoImpl(username, userid, passwd, ha1, realm, domain); } @Override diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f41d9a973..887c9d3da 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -107,7 +107,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native long[] listVideoPayloadTypes(long nativePtr); private native long[] getProxyConfigList(long nativePtr); private native long[] getAuthInfosList(long nativePtr); - private native long findAuthInfos(long nativePtr, String username, String realm); + private native long findAuthInfos(long nativePtr, String username, String realm, String domain); private native long[] listAudioPayloadTypes(long nativePtr); private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); @@ -1070,8 +1070,8 @@ class LinphoneCoreImpl implements LinphoneCore { return authInfos; } - public LinphoneAuthInfo findAuthInfo(String username, String realm) { - long ptr = findAuthInfos(nativePtr, username, realm); + public LinphoneAuthInfo findAuthInfo(String username, String realm, String domain) { + long ptr = findAuthInfos(nativePtr, username, realm, domain); if (ptr == 0) return null; From 120fbea39e56c4fe8b81f67512de43c5113aa267 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Nov 2013 17:13:53 +0100 Subject: [PATCH 824/909] Fix authInfo research + allow multiples authInfos with same username/password (with different domains) in linphonerc --- coreapi/authentication.c | 30 +++++++++++++++++------------- coreapi/linphonecore.h | 4 ++-- coreapi/linphonecore_jni.cc | 2 +- coreapi/siplogin.c | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index fd4e30c1c..0737ebf6d 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -37,13 +37,14 @@ * 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); + if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); obj->works=FALSE; return obj; } @@ -221,8 +222,7 @@ LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int ha1=lp_config_get_string(config,key,"ha1",NULL); realm=lp_config_get_string(config,key,"realm",NULL); domain=lp_config_get_string(config,key,"domain",NULL); - ret=linphone_auth_info_new(username,userid,passwd,ha1,realm); - linphone_auth_info_set_domain(ret,domain); + ret=linphone_auth_info_new(username,userid,passwd,ha1,realm,domain); return ret; } @@ -264,7 +264,7 @@ static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *user && pinfo->domain && strcmp(domain,pinfo->domain)==0){ return pinfo; } - }else if (realm){ + } else if (realm){ if (pinfo->realm && realm_match(realm,pinfo->realm)){ if (ret!=NULL){ ms_warning("Non unique realm found for %s",username); @@ -272,7 +272,9 @@ static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *user } ret=pinfo; } - }else return pinfo; + } else if (domain && pinfo->domain && strcmp(domain,pinfo->domain)==0){ + return pinfo; + } else return pinfo; } } return ret; @@ -289,13 +291,15 @@ static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *user **/ 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 (domain){ + ai=find_auth_info(lc,username,realm,domain); + if (ai==NULL){ + ai=find_auth_info(lc,username,NULL,domain); } } + if (ai==NULL && realm) { + ai=find_auth_info(lc,username,realm,NULL); + } if (ai==NULL){ ai=find_auth_info(lc,username,NULL,NULL); } @@ -314,8 +318,8 @@ 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) { - return linphone_auth_info_new(username, userid, passwd, ha1, realm); +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); } /** @@ -331,7 +335,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) /* find if we are attempting to modify an existing auth info */ ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); - if (ai!=NULL){ + if (ai!=NULL && ai->domain && strcmp(ai->domain, info->domain)==0){ lc->auth_info=ms_list_remove(lc->auth_info,ai); linphone_auth_info_destroy(ai); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 94a4297ec..af64a7887 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -851,7 +851,7 @@ struct _LinphoneAuthInfo; typedef struct _LinphoneAuthInfo LinphoneAuthInfo; LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm); + const char *passwd, const char *ha1,const char *realm, const char *domain); LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); @@ -1436,7 +1436,7 @@ LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphonePr * @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); +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); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 13a3d0183..b44c61c1a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1506,7 +1506,7 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv* extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env , jobject thiz ) { - return (jlong)linphone_auth_info_new(NULL,NULL,NULL,NULL,NULL); + return (jlong)linphone_auth_info_new(NULL,NULL,NULL,NULL,NULL,NULL); } extern "C" void Java_org_linphone_core_LinphoneAuthInfoImpl_delete(JNIEnv* env , jobject thiz diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index f29398c93..c63d8af1e 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -66,7 +66,7 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char tmp=linphone_address_as_string(parsed_uri); linphone_proxy_config_set_identity(cfg,tmp); if (passwd ) { - auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); From 2db728a6bf030a22374faa79f18026598fc5a354 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Nov 2013 10:49:38 +0100 Subject: [PATCH 825/909] Fix compilation issue --- coreapi/authentication.c | 2 +- coreapi/sipwizard.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 0737ebf6d..977e489f5 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -335,7 +335,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) /* find if we are attempting to modify an existing auth info */ ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); - if (ai!=NULL && ai->domain && strcmp(ai->domain, info->domain)==0){ + 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); } diff --git a/coreapi/sipwizard.c b/coreapi/sipwizard.c index ee268e50c..c81dabf35 100644 --- a/coreapi/sipwizard.c +++ b/coreapi/sipwizard.c @@ -214,7 +214,7 @@ static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const cha tmp=linphone_address_as_string(parsed_uri); linphone_proxy_config_set_identity(cfg,tmp); if (passwd) { - auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); From 263364ac7c4057817f1bb5bcb87f2b69653b749c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Nov 2013 11:37:00 +0100 Subject: [PATCH 826/909] Fix find auth info algorithm --- coreapi/authentication.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 977e489f5..a71e357da 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -256,25 +256,27 @@ static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *user MSList *elem; 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){ + for (elem=lc->auth_info;elem!=NULL;elem=elem->next) { + LinphoneAuthInfo *pinfo = (LinphoneAuthInfo*)elem->data; + if (username && pinfo->username && strcmp(username,pinfo->username)==0) { if (realm && domain){ if (pinfo->realm && strcmp(realm,pinfo->realm)==0 - && pinfo->domain && strcmp(domain,pinfo->domain)==0){ + && pinfo->domain && strcmp(domain,pinfo->domain)==0) { return pinfo; } - } else if (realm){ - if (pinfo->realm && realm_match(realm,pinfo->realm)){ - if (ret!=NULL){ + } 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 (domain && pinfo->domain && strcmp(domain,pinfo->domain)==0){ + } else if (domain && pinfo->domain && strcmp(domain,pinfo->domain)==0) { return pinfo; - } else return pinfo; + } else if (!domain) { + return pinfo; + } } } return ret; @@ -291,14 +293,13 @@ static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *user **/ const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ const LinphoneAuthInfo *ai=NULL; - if (domain){ - ai=find_auth_info(lc,username,realm,domain); - if (ai==NULL){ - ai=find_auth_info(lc,username,NULL,domain); - } - } - if (ai==NULL && realm) { + if (realm){ ai=find_auth_info(lc,username,realm,NULL); + if (ai==NULL && domain){ + ai=find_auth_info(lc,username,realm,domain); + } + } else if (domain != NULL) { + ai=find_auth_info(lc,username,NULL,domain); } if (ai==NULL){ ai=find_auth_info(lc,username,NULL,NULL); From 68a23b44b0ad8d2cf57ff1b93b6abfd510f14779 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Nov 2013 11:56:23 +0100 Subject: [PATCH 827/909] Fix find auth info algorithm for multiples registrations with same username --- coreapi/authentication.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index a71e357da..7690cf28c 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -298,7 +298,8 @@ const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const cha if (ai==NULL && domain){ ai=find_auth_info(lc,username,realm,domain); } - } else if (domain != NULL) { + } + if (ai == NULL && domain != NULL) { ai=find_auth_info(lc,username,NULL,domain); } if (ai==NULL){ From dbba820b5a0b0bf587ed614f6cecd9259f6bae2d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Nov 2013 15:30:35 +0100 Subject: [PATCH 828/909] Route was never set at the proxy config creation + allow linphonecore to init without linphonerc nor factory --- .../org/linphone/core/LinphoneCoreFactoryImpl.java | 4 +++- java/impl/org/linphone/core/LinphoneCoreImpl.java | 10 ++++++---- .../org/linphone/core/LinphoneProxyConfigImpl.java | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 3b242e00a..d2f635d4d 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -97,7 +97,9 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { String userConfig, String factoryConfig, Object userdata) throws LinphoneCoreException { try { - return new LinphoneCoreImpl(listener,new File(userConfig),new File(factoryConfig),userdata); + File user = userConfig == null ? null : new File(userConfig); + File factory = factoryConfig == null ? null : new File(factoryConfig); + return new LinphoneCoreImpl(listener, user, factory, userdata); } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 887c9d3da..f5740ff41 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -145,12 +145,14 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setChatDatabasePath(long nativePtr, String path); private native long[] getChatRooms(long nativePtr); - LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { - mListener=listener; - nativePtr = newLinphoneCore(listener,userConfig.getCanonicalPath(),factoryConfig.getCanonicalPath(),userdata); + LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { + mListener = listener; + String user = userConfig == null ? null : userConfig.getCanonicalPath(); + String factory = factoryConfig == null ? null : factoryConfig.getCanonicalPath(); + nativePtr = newLinphoneCore(listener, user, factory, userdata); } LinphoneCoreImpl(LinphoneCoreListener listener) throws IOException { - mListener=listener; + mListener = listener; nativePtr = newLinphoneCore(listener,null,null,null); } diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index a62db0b85..b2e019cb4 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -37,6 +37,7 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { nativePtr = newLinphoneProxyConfig(); setIdentity(identity); setProxy(proxy); + setRoute(route); enableRegister(enableRegister); ownPtr=true; } From 32efc7939ce2bddb7fff78537e2daada19c6ae91 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 5 Nov 2013 16:15:03 +0100 Subject: [PATCH 829/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c367be6e3..9a9268544 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c367be6e3c608581b14b66cb77cb173c3f539d72 +Subproject commit 9a92685445683036958df701d2e07078119415b9 From 0177c5f876e8b0d15a33a1c77bf704aede036ad3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 5 Nov 2013 22:00:19 +0100 Subject: [PATCH 830/909] fix compilation errors due to signature change in linphone_auth_info_new() fix failed tests in case of failed authentication. --- console/commands.c | 4 +--- console/linphonec.c | 2 +- coreapi/authentication.c | 17 ++++++++++++----- coreapi/bellesip_sal/sal_impl.c | 13 +++++++------ coreapi/bellesip_sal/sal_op_impl.c | 6 ++---- coreapi/bellesip_sal/sal_op_registration.c | 2 ++ coreapi/help/buddy_status.c | 2 +- coreapi/help/notify.c | 2 +- coreapi/help/registration.c | 2 +- coreapi/proxy.c | 4 ++-- gtk/main.c | 3 +-- gtk/setupwizard.c | 2 +- include/sal/sal.h | 2 +- tester/liblinphone_tester.c | 2 +- tester/register_tester.c | 10 +++++----- 15 files changed, 39 insertions(+), 34 deletions(-) diff --git a/console/commands.c b/console/commands.c index 540b0e636..c4e70ba02 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1930,9 +1930,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ LinphoneAddress *from; LinphoneAuthInfo *info; if ((from=linphone_address_new(identity))!=NULL){ - char realm[128]; - snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from)); - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL); + info=linphone_auth_info_new(NULL,NULL,passwd,NULL,NULL,linphone_address_get_username(from)); linphone_core_add_auth_info(lc,info); linphone_address_destroy(from); linphone_auth_info_destroy(info); diff --git a/console/linphonec.c b/console/linphonec.c index 1677760dd..a453e374b 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -271,7 +271,7 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern return; } - pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm); + pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm,domain); auth_stack.elem[auth_stack.nitems++]=pending_auth; } } diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 7690cf28c..bd7849832 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -33,9 +33,17 @@ /** * Create a LinphoneAuthInfo object with supplied information. - * * The object can be created empty, that is with all arguments set to NULL. - * Username, userid, password and realm can be set later using specific methods. + * Username, userid, password, realm and domain can be set later using specific methods. + * At the end, username and passwd (or ha1) are required. + * @param username the username that needs to be authenticated + * @param userid the userid used for authenticating (use NULL if you don't know what it is) + * @param passwd the password in clear text + * @param ha1 the ha1-encrypted password if password is not given in clear text. + * @param realm the authentication domain (which can be larger than the sip domain. Unfortunately many SIP servers don't use this parameter. + * @param domain the SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain. + * @return a #LinphoneAuthInfo. linphone_auth_info_destroy() must be used to destroy it when no longer needed. The LinphoneCore makes a copy of LinphoneAuthInfo + * passed through linphone_core_add_auth_info(). **/ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain){ LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1); @@ -344,11 +352,10 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) 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,info->domain); + 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; diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index d43bc4878..b3a7cfc78 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -284,6 +284,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even 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; @@ -305,15 +306,12 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); if (op->callbacks.process_response_event) { - /*handle authorization*/ switch (response_code) { - case 200: { + case 200: break; - } case 401: - case 407:{ - + case 407: /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ @@ -327,7 +325,10 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even sal_process_authentication(op); return; } - } + break; + case 403: + if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info); + break; } op->callbacks.process_response_event(op,event); } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index f22530892..30bede48a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -81,10 +81,8 @@ void sal_op_cancel_authentication(SalOp *h){ return ; } -int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ - *realm=op->auth_info?op->auth_info->realm:NULL; - *username=op->auth_info?op->auth_info->username:NULL; - return 0; +SalAuthInfo * sal_op_get_auth_requested(SalOp *op){ + return op->auth_info; } belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index a611af029..c02546019 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -63,6 +63,8 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); + if (status_code==403) + op->base.root->callbacks.auth_failure(op,op->auth_info); } } } diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 64f818683..40db6458e 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -129,7 +129,7 @@ int main(int argc, char *argv[]){ } LinphoneAuthInfo *info; if (password!=NULL){ - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } diff --git a/coreapi/help/notify.c b/coreapi/help/notify.c index 0055346ee..58775b044 100644 --- a/coreapi/help/notify.c +++ b/coreapi/help/notify.c @@ -129,7 +129,7 @@ int main(int argc, char *argv[]){ } LinphoneAuthInfo *info; if (password!=NULL){ - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } diff --git a/coreapi/help/registration.c b/coreapi/help/registration.c index 6ed93e70d..70ab4f4ca 100644 --- a/coreapi/help/registration.c +++ b/coreapi/help/registration.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]){ } LinphoneAuthInfo *info; if (password!=NULL){ - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index dd34e49fe..a353d862e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -963,9 +963,9 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig %p is not known by LinphoneCore (programming error?)",cfg); return; } - lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg); + lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,cfg); /* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */ - lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg); + lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,cfg); cfg->deletion_date=ms_time(NULL); if (cfg->state==LinphoneRegistrationOk){ /* this will unREGISTER */ diff --git a/gtk/main.c b/gtk/main.c index fbe8dd698..6aabf98c5 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1039,8 +1039,7 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *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); - linphone_auth_info_set_domain(info,domain); + 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); diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index 6b596dcc3..afb543a85 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -430,7 +430,7 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page } gchar domain[128]; g_snprintf(domain, sizeof(domain), "\"%s\"", creator->domain + 4); - LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, domain); + LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, NULL, domain); linphone_core_add_auth_info(linphone_gtk_get_core(),info); g_free(username); diff --git a/include/sal/sal.h b/include/sal/sal.h index 51bb2dcac..98c89d8c2 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -481,7 +481,7 @@ void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); -int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username); +SalAuthInfo * sal_op_get_auth_requested(SalOp *h); const char *sal_op_get_from(const SalOp *op); const SalAddress *sal_op_get_from_address(const SalOp *op); const char *sal_op_get_to(const SalOp *op); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 740d02f4a..6be3bd70b 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -78,7 +78,7 @@ void auth_info_requested(LinphoneCore *lc, const char *realm, const char *userna ,realm); counters = get_stats(lc); counters->number_of_auth_info_requested++; - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + 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*/ } diff --git a/tester/register_tester.c b/tester/register_tester.c index 1ee2dc453..adf3197a8 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -104,7 +104,7 @@ static void register_with_refresh_base_3(LinphoneCore* lc if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { if (!linphone_core_get_auth_info_list(lc)) { CU_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized); - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + 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*/ } } @@ -148,7 +148,7 @@ 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); /*create authentication structure from identity*/ + 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*/ @@ -228,7 +228,7 @@ static void simple_tls_register(){ 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); /*create authentication structure from identity*/ + 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*/ @@ -244,7 +244,7 @@ static void ha1_authenticated_register(){ 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); /*create authentication structure from identity*/ + 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; @@ -321,7 +321,7 @@ static void authenticated_register_with_wrong_credentials(){ LinphoneCoreManager *mgr; stats* counters; LCSipTransports transport = {5070,5070,0,5071}; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain); /*create authentication structure from identity*/ + 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); From e407f70c14871d4ca5f1bc7b90a0d4c45cd7ddc3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 6 Nov 2013 16:36:43 +0100 Subject: [PATCH 831/909] Fix: in tunnel mode, linphone wasn't unregistering at exit. --- coreapi/TunnelManager.cc | 20 +++----------------- coreapi/linphonecall.c | 15 ++++++++------- coreapi/linphonecore.c | 20 ++++++++++++++------ 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index e6063878a..efac8fbb0 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -274,20 +274,9 @@ void TunnelManager::processTunnelEvent(const Event &ev){ ms_message("Tunnel is up, registering now"); linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall); linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories); -#ifdef USE_BELLESIP + sal_enable_tunnel(mCore->sal, mTunnelClient); -#else - 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); -#endif + //register if (lProxy) { linphone_proxy_config_done(lProxy); @@ -343,7 +332,6 @@ void TunnelManager::enable(bool isEnable) { mReady=false; linphone_core_set_rtp_transport_factories(mCore,NULL); -#ifdef USE_BELLESIP sal_disable_tunnel(mCore->sal); // Set empty transports to force the setting of regular transport, otherwise it is not applied LCSipTransports lTransport; @@ -352,9 +340,7 @@ void TunnelManager::enable(bool isEnable) { lTransport.tls_port = 0; lTransport.dtls_port = 0; linphone_core_set_sip_transports(mCore, &lTransport); -#else - eXosip_transport_hook_register(NULL); -#endif + //Restore transport and firewall policy linphone_core_set_sip_transports(mCore, &mRegularTransport); linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 695050ea4..7c24bbbd4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -413,7 +413,6 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) { } static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ - LinphonePresenceModel *model; int port_offset; int min_port, max_port; @@ -425,12 +424,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; - if (call->core->calls==NULL){ - /*there were no call, and now there is a call, send an on-the-phone presence notification automatically*/ - model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); - linphone_core_send_presence(call->core,model); - linphone_presence_model_unref(model); - } + linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ @@ -731,6 +725,13 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const linphone_call_set_terminated(call); } if (cstate == LinphoneCallConnected) { + if (ms_list_size(lc->calls)==1){ + LinphonePresenceModel *model; + /*there were no call, and now there is a call, send an on-the-phone presence notification automatically*/ + model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); + linphone_core_send_presence(call->core,model); + linphone_presence_model_unref(model); + } call->log->status=LinphoneCallSuccess; call->media_start_time=time(NULL); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9ac7e8220..556154422 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5423,12 +5423,13 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up); lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok); - for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); linphone_proxy_config_edit(cfg); /* to unregister */ } + + ms_message("Unregistration started."); for (i=0;i<20&&still_registered;i++){ still_registered=FALSE; @@ -5450,6 +5451,15 @@ void sip_config_uninit(LinphoneCore *lc) ms_list_free(lc->auth_info); lc->auth_info=NULL; + /*now that we are unregisted, we no longer need the tunnel.*/ +#ifdef TUNNEL_ENABLED + if (lc->tunnel) { + linphone_tunnel_destroy(lc->tunnel); + lc->tunnel=NULL; + ms_message("Tunnel destroyed."); + } +#endif + sal_reset_transports(lc->sal); sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ sal_iterate(lc->sal); /*make sure event are purged*/ @@ -5550,6 +5560,7 @@ static void codecs_config_uninit(LinphoneCore *lc) void ui_config_uninit(LinphoneCore* lc) { + ms_message("Destroying friends."); if (lc->friends){ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_destroy); ms_list_free(lc->friends); @@ -5559,6 +5570,7 @@ void ui_config_uninit(LinphoneCore* lc) linphone_presence_model_unref(lc->presence_model); lc->presence_model = NULL; } + ms_message("Destroying friends done."); } /** @@ -5590,8 +5602,6 @@ static void linphone_core_uninit(LinphoneCore *lc) ms_usleep(50000); } - - 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"); @@ -5601,9 +5611,7 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->previewstream=NULL; } #endif -#ifdef TUNNEL_ENABLED - if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); -#endif + ms_event_queue_destroy(lc->msevq); lc->msevq=NULL; /* save all config */ From 55fedeb6b79b8ea7a8b53e34f0f09eff6dcaa738 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 6 Nov 2013 16:31:24 +0100 Subject: [PATCH 832/909] fix crash in case of 488 --- coreapi/callbacks.c | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ecd9f18a0..0af4f2e72 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -647,7 +647,6 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); break; - case SalReasonNotAcceptable: case SalReasonRequestPending: /*restore previous state, the application will decide to resubmit the action if relevant*/ call->reason=linphone_reason_from_sal(sr); From 8199ed773c7333d9b6edfa98f004126a81655fb6 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 6 Nov 2013 16:45:13 +0100 Subject: [PATCH 833/909] add -Qunused-argument for clang --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 90191ab53..f68d1b850 100644 --- a/configure.ac +++ b/configure.ac @@ -601,7 +601,7 @@ AC_ARG_ENABLE(strict, STRICT_OPTIONS="-Wall " if test "$strictness" = "yes" ; then - STRICT_OPTIONS="$STRICT_OPTIONS -Werror" + STRICT_OPTIONS="$STRICT_OPTIONS -Werror -Qunused-arguments" CFLAGS="$CFLAGS -fno-strict-aliasing" fi From 062db87ed53b9aed434ee33f9939c0249c5987c1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 6 Nov 2013 17:07:19 +0100 Subject: [PATCH 834/909] Revert "add -Qunused-argument for clang" This reverts commit 8199ed773c7333d9b6edfa98f004126a81655fb6. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f68d1b850..90191ab53 100644 --- a/configure.ac +++ b/configure.ac @@ -601,7 +601,7 @@ AC_ARG_ENABLE(strict, STRICT_OPTIONS="-Wall " if test "$strictness" = "yes" ; then - STRICT_OPTIONS="$STRICT_OPTIONS -Werror -Qunused-arguments" + STRICT_OPTIONS="$STRICT_OPTIONS -Werror" CFLAGS="$CFLAGS -fno-strict-aliasing" fi From 6c4f1da92bae91bf95ece40326ae0cf70c4273fd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 7 Nov 2013 14:32:53 +0100 Subject: [PATCH 835/909] update ortp to fix conflict with gettimeofday defined both in ortp and tunnel. update documentation --- README.mingw | 4 ---- coreapi/misc.c | 4 ++-- oRTP | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/README.mingw b/README.mingw index e60a1e335..39b41d3df 100644 --- a/README.mingw +++ b/README.mingw @@ -65,10 +65,6 @@ WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del t you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu. Kill it. Don't know what it is, but once killed, windows runs normally. -#Compile and install tunnel (optional, available under proprietary licensing) - -cd tunnel && ./autogen.sh && ./configure --prefix=/usr --enable-shared --disable-static && make && make install - #Build linphone itself: #run autogen.sh after a git checkout or update diff --git a/coreapi/misc.c b/coreapi/misc.c index b9a027d6e..7d9b70b3f 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -528,7 +528,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ } got_audio=FALSE; got_video=FALSE; - gettimeofday(&init,NULL); + ortp_gettimeofday(&init,NULL); do{ int id; @@ -561,7 +561,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ cone_video=TRUE; got_video=TRUE; } - gettimeofday(&cur,NULL); + ortp_gettimeofday(&cur,NULL); elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); if (elapsed>2000) { ms_message("Stun responses timeout, going ahead."); diff --git a/oRTP b/oRTP index 120e58e2c..b5d1414e6 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 120e58e2c12d608ecb7a2f0c4ae91768cb1862a0 +Subproject commit b5d1414e63b21c83eb8e26988a3fe423ff8fc3b3 From a47914c4c1adb524aa4516b2bdaf8c837692d06d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 8 Nov 2013 15:16:34 +0100 Subject: [PATCH 836/909] Added MSISAC compatibility for Android --- build/android/Android.mk | 6 ++++++ coreapi/linphonecore_jni.cc | 10 ++++++++++ mediastreamer2 | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index f88c0e117..235056c54 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -148,6 +148,12 @@ LOCAL_CFLAGS += -DHAVE_SILK LOCAL_STATIC_LIBRARIES += libmssilk endif +ifeq ($(BUILD_WEBRTC_ISAC),1) +LOCAL_CFLAGS += -DHAVE_ISAC +LOCAL_STATIC_LIBRARIES += libwebrtc_isacfix_neon +LOCAL_STATIC_LIBRARIES += libwebrtc_spl libwebrtc_isacfix libmsisac +endif + ifeq ($(BUILD_G729),1) LOCAL_CFLAGS += -DHAVE_G729 LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729 diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b44c61c1a..efc5df7a6 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -48,6 +48,9 @@ extern "C" void libmssilk_init(); #ifdef HAVE_G729 extern "C" void libmsbcg729_init(); #endif +#ifdef HAVE_ISAC +extern "C" void libmsisac_init(); +#endif #endif /*ANDROID*/ @@ -717,11 +720,16 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* #ifdef HAVE_G729 libmsbcg729_init(); #endif +#ifdef HAVE_ISAC + libmsisac_init(); +#endif + jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable ,userConfig ,factoryConfig ,ldata); + if (userConfig) env->ReleaseStringUTFChars(juserConfig, userConfig); if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig); return nativePtr; @@ -4342,6 +4350,8 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getSendFmtp(JNI const char *fmtp=pt->send_fmtp; return fmtp ? env->NewStringUTF(fmtp) : NULL; } + + diff --git a/mediastreamer2 b/mediastreamer2 index 9a9268544..3433e47bc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9a92685445683036958df701d2e07078119415b9 +Subproject commit 3433e47bc8ed15b2800bbd448f6d22f79285e66d From 7f69d68dabee74ebd3b9dff3179d91564ac2a653 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 8 Nov 2013 15:31:00 +0100 Subject: [PATCH 837/909] Update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index b5d1414e6..e96c55df4 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b5d1414e63b21c83eb8e26988a3fe423ff8fc3b3 +Subproject commit e96c55df4436db74656d5feedf3e8fd12adb74e4 From 5fb5c55eb0c59c47a91c083486d6e1218983a3fa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 8 Nov 2013 19:05:08 +0100 Subject: [PATCH 838/909] add new test to check what happens if a calls gets rejected because of incompatible media types. restore oRTP --- coreapi/callbacks.c | 21 ++++++++------------- oRTP | 2 +- tester/call_tester.c | 38 +++++++++++++++++++++++++++++++++++++- tester/presence_tester.c | 2 +- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 0af4f2e72..a256122c7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -666,7 +666,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de case LinphoneCallResuming: ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); call->reason=linphone_reason_from_sal(sr); - linphone_call_set_state(call, call->prevstate,msg); + linphone_call_set_state(call, call->prevstate,details); return; default: break; /*nothing to do*/ @@ -678,19 +678,14 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de #ifdef BUILD_UPNP linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - - if (sr == SalReasonDeclined) { - call->reason=LinphoneReasonDeclined; + + call->reason=linphone_reason_from_sal(sr); + if (sr==SalReasonDeclined){ linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - } else if (sr == SalReasonNotFound) { - call->reason=LinphoneReasonNotFound; - linphone_call_set_state(call,LinphoneCallError,"User not found."); - } else if (sr == SalReasonBusy) { - call->reason=LinphoneReasonBusy; - linphone_call_set_state(call,LinphoneCallError,"User is busy."); - linphone_core_play_named_tone(lc,LinphoneToneBusy); - } else { - linphone_call_set_state(call,LinphoneCallError,msg); + }else{ + linphone_call_set_state(call,LinphoneCallError,details); + if (sr==SalReasonBusy) + linphone_core_play_named_tone(lc,LinphoneToneBusy); } if (referer){ diff --git a/oRTP b/oRTP index e96c55df4..b5d1414e6 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit e96c55df4436db74656d5feedf3e8fd12adb74e4 +Subproject commit b5d1414e63b21c83eb8e26988a3fe423ff8fc3b3 diff --git a/tester/call_tester.c b/tester/call_tester.c index 38133ee11..267d2050e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -345,6 +345,40 @@ static void cancelled_call(void) { linphone_core_manager_destroy(pauline); } +static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime){ + const MSList *elem=linphone_core_get_audio_codecs(lc); + PayloadType *pt; + + for(;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + linphone_core_enable_payload_type(lc,pt,FALSE); + } + pt=linphone_core_find_payload_type(lc,mime,-1,-1); + CU_ASSERT_PTR_NOT_NULL_FATAL(pt); + linphone_core_enable_payload_type(lc,pt,TRUE); +} + +static void call_failed_because_of_codecs(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* out_call; + + disable_all_codecs_except_one(marie->lc,"pcmu"); + disable_all_codecs_except_one(pauline->lc,"pcma"); + out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + /*flexisip will retain the 415 until the "urgent reply" timeout arrives.*/ + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,6000)); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonMedia); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; @@ -416,7 +450,8 @@ static void early_declined_call(void) { out_call = linphone_core_invite(pauline->lc,"marie"); linphone_call_ref(out_call); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1)); + /*wait until flexisip transfers the busy...*/ + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,33000)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); /* FIXME http://git.linphone.org/mantis/view.php?id=757 @@ -1419,6 +1454,7 @@ test_t call_tests[] = { { "Early cancelled call", early_cancelled_call}, { "Call with DNS timeout", call_with_dns_time_out }, { "Cancelled ringing call", cancelled_ringing_call }, + { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, { "Call with media relay", call_with_media_relay}, { "Simple call compatibility mode", simple_call_compatibility_mode }, diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 3df002b8f..d3d0f5fce 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -336,7 +336,7 @@ static void presence_information(void) { test_t presence_tests[] = { { "Simple Subscribe", simple_subscribe }, { "Simple Publish", simple_publish }, - { "Call with Presence", call_with_presence }, + { "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 }, From e316b02b88f0872ef37bb90a71e8da2723b7dfc1 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 8 Nov 2013 14:54:55 +0100 Subject: [PATCH 839/909] answer 481 in case of CANCEL received for an establshed dialog --- coreapi/bellesip_sal/sal_op_call.c | 5 +++++ tester/presence_tester.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 80173e95d..8a7037491 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -475,6 +475,11 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) { resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); + } else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) { + /*call leg does not exist because 200ok already sent*/ + belle_sip_server_transaction_send_response( server_transaction + ,sal_op_create_response_from_request(op,req,481)); + } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); diff --git a/tester/presence_tester.c b/tester/presence_tester.c index d3d0f5fce..9f3f009f1 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -235,8 +235,8 @@ static void call_with_presence(void) { CU_ASSERT_TRUE(subscribe_to_callee_presence(pauline,marie)); CU_ASSERT_TRUE(call(marie,pauline)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone,1); - CU_ASSERT_EQUAL(pauline->stat.number_of_LinphonePresenceActivityOnThePhone,1); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnThePhone,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityOnThePhone,1)); reset_counters(&marie->stat); reset_counters(&pauline->stat); From 95c3e2b2e8f5a5dc336ff668f797cf78360a2f6c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 12 Nov 2013 10:27:45 +0100 Subject: [PATCH 840/909] add -Qunused-arguments option to clang --- configure.ac | 29 ++++++++++++++++++++++++++--- tools/Makefile.am | 3 +-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 90191ab53..2ebc0d7bb 100644 --- a/configure.ac +++ b/configure.ac @@ -35,9 +35,17 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) +case $target in + *apple-darwin*) + AC_PROG_CXX(["xcrun clang++" g++]) + AC_PROG_CC(["xcrun clang" gcc]) + ;; + *) + AC_PROG_CC + AC_PROG_CXX + ;; +esac AC_ISC_POSIX -AC_PROG_CC -AC_PROG_CXX AC_C_INLINE AC_HEADER_STDC AM_PROG_CC_C_O @@ -73,6 +81,9 @@ case $target in esac + + + AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) @@ -598,8 +609,20 @@ AC_ARG_ENABLE(strict, [strictness=yes] ) -STRICT_OPTIONS="-Wall " +STRICT_OPTIONS="-Wall" +#for clang + +LDFLAGS_SAV=$LDFLAGS +LDFLAGS="$LDFLAGS -Qunused-arguments -Wall -Werror" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], + [[]])] + , [cc_option_q_allowed=yes] + , [cc_option_q_allowed=no]) +LD_FLAGS=$LDFLAGS_SAV +if test $cc_option_q_allowed = "yes"; then + STRICT_OPTIONS="$STRICT_OPTIONS -Qunused-arguments" +fi if test "$strictness" = "yes" ; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror" CFLAGS="$CFLAGS -fno-strict-aliasing" diff --git a/tools/Makefile.am b/tools/Makefile.am index d0e6d350a..6fa7fadb4 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,8 +2,7 @@ AM_CPPFLAGS=\ -I$(top_srcdir) \ - -I$(top_srcdir)/coreapi \ - -I$(top_srcdir)/exosip + -I$(top_srcdir)/coreapi COMMON_CFLAGS=\ -DIN_LINPHONE \ From 3cadf36e003d23859cfea7f7eb8f2e79397c88ab Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 12 Nov 2013 21:37:09 +0100 Subject: [PATCH 841/909] fix configure script. It is not allowed to call AC_PROG_CC and AC_PROG_CXX conditionally. Configure aborts shortly. --- configure.ac | 14 ++++---------- coreapi/linphonecore.c | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 2ebc0d7bb..f24f05b1c 100644 --- a/configure.ac +++ b/configure.ac @@ -35,16 +35,10 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) -case $target in - *apple-darwin*) - AC_PROG_CXX(["xcrun clang++" g++]) - AC_PROG_CC(["xcrun clang" gcc]) - ;; - *) - AC_PROG_CC - AC_PROG_CXX - ;; -esac + +AC_PROG_CXX(["xcrun clang++" g++]) +AC_PROG_CC(["xcrun clang" gcc]) + AC_ISC_POSIX AC_C_INLINE AC_HEADER_STDC diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 556154422..0cae988d5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5048,9 +5048,9 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { static MSVideoSizeDef supported_resolutions[]={ { { MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H } , "1080p" }, - { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, + { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, From 866dc475a75f8462bc08e333d3ebb1b34e8006cd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 13 Nov 2013 09:47:14 +0100 Subject: [PATCH 842/909] fix compilation on windows --- configure.ac | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index f24f05b1c..b1a4df656 100644 --- a/configure.ac +++ b/configure.ac @@ -607,16 +607,12 @@ STRICT_OPTIONS="-Wall" #for clang -LDFLAGS_SAV=$LDFLAGS -LDFLAGS="$LDFLAGS -Qunused-arguments -Wall -Werror" -AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], - [[]])] - , [cc_option_q_allowed=yes] - , [cc_option_q_allowed=no]) -LD_FLAGS=$LDFLAGS_SAV -if test $cc_option_q_allowed = "yes"; then - STRICT_OPTIONS="$STRICT_OPTIONS -Qunused-arguments" -fi +case $CC in + *clang*) + STRICT_OPTIONS="$STRICT_OPTIONS -Qunused-arguments" + ;; +esac + if test "$strictness" = "yes" ; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror" CFLAGS="$CFLAGS -fno-strict-aliasing" From 0138897ef049fbf124b9a324592877bfe47349b2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 14 Nov 2013 14:53:15 +0100 Subject: [PATCH 843/909] Fix JNI method LpConfig_GetString --- coreapi/linphonecore_jni.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index efc5df7a6..a0e212c26 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3254,20 +3254,20 @@ extern "C" jstring Java_org_linphone_core_LpConfigImpl_getString(JNIEnv *env, jo jstring section, jstring key, jstring defaultValue) { const char *csection = env->GetStringUTFChars(section, NULL); const char *ckey = env->GetStringUTFChars(key, NULL); - const char *cvalue; - if (defaultValue == NULL) { - cvalue = NULL; - } else { - cvalue = env->GetStringUTFChars(defaultValue, 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 returnValue ? env->NewStringUTF(returnValue) : NULL; + + 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) { From 927ae4ec958618be11bb0fcd8cb7eb8807af360c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Nov 2013 17:24:51 +0100 Subject: [PATCH 844/909] doc fixes --- coreapi/linphonecore.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0cae988d5..df4be1090 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1033,14 +1033,13 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){ /** * Sets maximum available download bandwidth - * - * @ingroup media_parameters - * * This is IP bandwidth, in kbit/s. * This information is used signaled to other parties during * calls (within SDP messages) so that the remote end can have * sufficient knowledge to properly configure its audio & video * codec output bitrate to not overflow available bandwidth. + * + * @ingroup media_parameters * * @param lc the LinphoneCore object * @param bw the bandwidth in kbits/s, 0 for infinite @@ -1052,9 +1051,6 @@ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ /** * Sets maximum available upload bandwidth - * - * @ingroup media_parameters - * * This is IP bandwidth, in kbit/s. * This information is used by liblinphone together with remote * side available bandwidth signaled in SDP messages to properly @@ -1062,6 +1058,7 @@ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ * * @param lc the LinphoneCore object * @param bw the bandwidth in kbits/s, 0 for infinite + * @ingroup media_parameters */ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ lc->net_conf.upload_bw=bw; @@ -1070,11 +1067,8 @@ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ /** * Retrieve the maximum available download bandwidth. - * - * @ingroup media_parameters - * * This value was set by linphone_core_set_download_bandwidth(). - * + * @ingroup media_parameters **/ int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ return lc->net_conf.download_bw; @@ -1082,11 +1076,8 @@ int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ /** * Retrieve the maximum available upload bandwidth. - * - * @ingroup media_parameters - * * This value was set by linphone_core_set_upload_bandwidth(). - * + * @ingroup media_parameters **/ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; From 8cda14a43dd7092e49e9480eff4031200ebe5066 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Nov 2013 17:32:21 +0100 Subject: [PATCH 845/909] add opus in win32 packaging, update ms2 --- linphone-deps.filelist | 1 + mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 0d3949825..79731801d 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -16,3 +16,4 @@ ./bin/libtasn1-3.dll ./bin/libsqlite3-0.dll ./bin/libzrtpcpp.dll +./bin/libopus-0.dll diff --git a/mediastreamer2 b/mediastreamer2 index 3433e47bc..a3c366b6b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3433e47bc8ed15b2800bbd448f6d22f79285e66d +Subproject commit a3c366b6b5639f5c844ddbcd1d1f205ca7d8c22c From d447704d15116739389c4e0903b48708bb381d21 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Nov 2013 22:12:09 +0100 Subject: [PATCH 846/909] add "encoding" field to LinphoneContent --- coreapi/bellesip_sal/sal_op_impl.c | 13 ++++++++++++- coreapi/info.c | 5 +++++ coreapi/linphonecore.h | 1 + include/sal/sal.h | 1 + tester/eventapi_tester.c | 8 ++++---- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 30bede48a..02cb90a1f 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -540,6 +540,7 @@ const char *sal_op_get_remote_contact(const SalOp *op){ 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, @@ -547,6 +548,10 @@ void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){ 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)); + } } } @@ -555,23 +560,29 @@ 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; } - memset(salbody,0,sizeof(SalBody)); return FALSE; } + void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) { op->privacy=privacy; } diff --git a/coreapi/info.c b/coreapi/info.c index 539855ab8..ff7ff3c93 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -45,6 +45,7 @@ struct _LinphoneInfoMessage{ static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ SET_STRING(obj,type,ref->type); SET_STRING(obj,subtype,ref->subtype); + SET_STRING(obj,encoding,ref->encoding); if (obj->data) { ms_free(obj->data); obj->data=NULL; @@ -61,11 +62,13 @@ void linphone_content_uninit(LinphoneContent * obj){ if (obj->type) ms_free(obj->type); if (obj->subtype) ms_free(obj->subtype); if (obj->data) ms_free(obj->data); + if (obj->encoding) ms_free(obj->encoding); } LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ SET_STRING(obj,type,ref->type); SET_STRING(obj,subtype,ref->subtype); + SET_STRING(obj,encoding,ref->encoding); if (obj->data) { ms_free(obj->data); obj->data=NULL; @@ -84,6 +87,7 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons obj->type=(char*)ref->type; obj->subtype=(char*)ref->subtype; obj->data=(void*)ref->data; + obj->encoding=(char*)ref->encoding; obj->size=ref->size; return obj; } @@ -96,6 +100,7 @@ SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ body->subtype=lc->subtype; body->data=lc->data; body->size=lc->size; + body->encoding=lc->encoding; return body; } return NULL; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index af64a7887..9ba12e8e8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -114,6 +114,7 @@ struct _LinphoneContent{ char *subtype; /**lc); lcs=ms_list_append(lcs,pauline->lc); @@ -123,7 +123,7 @@ static void subscribe_test_declined(void) { static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t test_refreshing) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content; + LinphoneContent content={0}; LinphoneEvent *lev; int expires= test_refreshing ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); @@ -184,7 +184,7 @@ static void subscribe_test_refreshed(void){ static void publish_test_with_args(bool_t refresh){ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneContent content; + LinphoneContent content={0}; LinphoneEvent *lev; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); From c97a7a6704a1db46aec9e1e755603b6255029890 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 14 Nov 2013 22:16:22 +0100 Subject: [PATCH 847/909] remove some exosip related files --- coreapi/sal_eXosip2.c | 2692 -------------------------------- coreapi/sal_eXosip2.h | 104 -- coreapi/sal_eXosip2_presence.c | 829 ---------- coreapi/sal_eXosip2_sdp.c | 618 -------- 4 files changed, 4243 deletions(-) delete mode 100644 coreapi/sal_eXosip2.c delete mode 100644 coreapi/sal_eXosip2.h delete mode 100644 coreapi/sal_eXosip2_presence.c delete mode 100644 coreapi/sal_eXosip2_sdp.c diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c deleted file mode 100644 index aca1caacf..000000000 --- a/coreapi/sal_eXosip2.c +++ /dev/null @@ -1,2692 +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_append_stack_string_to_user_agent(Sal *ctx) { - /* Not implemented for eXosip */ -} - -void sal_use_session_timers(Sal *ctx, int expires){ - ctx->session_expires=expires; -} - -void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ctx->one_matching_codec=one_matching_codec; -} - -MSList *sal_get_pending_auths(Sal *sal){ - return ms_list_copy(sal->pending_auths); -} - -void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ctx->double_reg=enabled; -} - -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ - ctx->expire_old_contact=enabled; -} - -void sal_use_dates(Sal *ctx, bool_t enabled){ - ctx->add_dates=enabled; -#ifdef EXOSIP_OPT_REGISTER_WITH_DATE - { - int tmp=enabled; - eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp); - } -#else - if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option."); -#endif -} - -void sal_use_rport(Sal *ctx, bool_t use_rports){ - ctx->use_rports=use_rports; -} -void sal_use_101(Sal *ctx, bool_t use_101){ - ctx->use_101=use_101; -} - -void sal_set_root_ca(Sal* ctx, const char* rootCa) { - if (ctx->rootCa) - ms_free(ctx->rootCa); - ctx->rootCa = ms_strdup(rootCa); - set_tls_options(ctx); -} - -const char *sal_get_root_ca(Sal* ctx) { - return ctx->rootCa; -} - -void sal_verify_server_certificates(Sal *ctx, bool_t verify){ - ctx->verify_server_certs=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE - eXosip_tls_verify_certificate(verify); -#endif -} - -void sal_verify_server_cn(Sal *ctx, bool_t verify){ - ctx->verify_server_cn=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CN - eXosip_tls_verify_cn(verify); -#endif -} - -static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){ - osip_via_t *via=NULL; - osip_generic_param_t *param=NULL; - const char *rport=NULL; - - *rportval=5060; - *received=NULL; - osip_message_get_via(msg,0,&via); - if (!via) { - ms_warning("extract_received_rport(): no via."); - return -1; - } - - *transport = sal_transport_parse(via->protocol); - - if (via->port && via->port[0]!='\0') - *rportval=atoi(via->port); - - osip_via_param_get_byname(via,"rport",¶m); - if (param) { - rport=param->gvalue; - if (rport && rport[0]!='\0') *rportval=atoi(rport); - *received=via->host; - } - param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param) *received=param->gvalue; - - if (rport==NULL && *received==NULL){ - ms_warning("extract_received_rport(): no rport and no received parameters."); - return -1; - } - return 0; -} - -static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ - int sdplen; - char clen[10]; - char *sdp=NULL; - sdp_message_to_str(msg,&sdp); - sdplen=strlen(sdp); - snprintf(clen,sizeof(clen),"%i",sdplen); - osip_message_set_body(sip,sdp,sdplen); - osip_message_set_content_type(sip,"application/sdp"); - osip_message_set_content_length(sip,clen); - osip_free(sdp); -} - -static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ - sdp_message_t *msg=media_description_to_sdp(desc); - if (msg==NULL) { - ms_error("Fail to print sdp message !"); - return; - } - set_sdp(sip,msg); - sdp_message_free(msg); -} - -static void sdp_process(SalOp *h){ - ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); - if (h->result){ - sal_media_description_unref(h->result); - } - h->result=sal_media_description_new(); - if (h->sdp_offering){ - offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); - }else{ - int i; - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - } - offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result); - /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. - It should contains media parameters constraint from the remote offer, not our response*/ - strcpy(h->result->addr,h->base.remote_media->addr); - h->result->bandwidth=h->base.remote_media->bandwidth; - - for(i=0;iresult->n_active_streams;++i){ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } - } - } - -} - -int sal_call_is_offerer(const SalOp *h){ - return h->sdp_offering; -} - -int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ - if (desc) - sal_media_description_ref(desc); - if (h->base.local_media) - sal_media_description_unref(h->base.local_media); - h->base.local_media=desc; - if (h->base.remote_media){ - /*case of an incoming call where we modify the local capabilities between the time - * the call is ringing and it is accepted (for example if you want to accept without video*/ - /*reset the sdp answer so that it is computed again*/ - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - return 0; -} - -int sal_call(SalOp *h, const char *from, const char *to){ - int err; - const char *route; - osip_message_t *invite=NULL; - osip_call_id_t *callid; - sal_op_set_from(h,from); - sal_op_set_to(h,to); - sal_exosip_fix_route(h); - - h->terminated = FALSE; - - route = sal_op_get_route(h); - err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call"); - if (err!=0){ - ms_error("Could not create call. Error %d (from=%s to=%s route=%s)", - err, from, to, route); - return -1; - } - osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(invite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(invite, "Session-expires", "200"); - osip_message_set_supported(invite, "timer"); - } - sal_exosip_add_custom_headers(invite,h->base.custom_headers); - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(invite,h->base.local_media); - }else h->sdp_offering=FALSE; - if (h->replaces){ - osip_message_set_header(invite,"Replaces",h->replaces); - if (h->referred_by) - osip_message_set_header(invite,"Referred-By",h->referred_by); - } - - eXosip_lock(); - err=eXosip_call_send_initial_invite(invite); - eXosip_unlock(); - h->cid=err; - if (err<0){ - ms_error("Fail to send invite ! Error code %d", err); - return -1; - }else{ - char *tmp=NULL; - callid=osip_message_get_call_id(invite); - osip_call_id_to_str(callid,&tmp); - h->base.call_id=ms_strdup(tmp); - osip_free(tmp); - sal_add_call(h->base.root,h); - } - return 0; -} - -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - osip_message_t *msg; - - /*if early media send also 180 and 183 */ - if (early_media){ - msg=NULL; - eXosip_lock(); - eXosip_call_build_answer(h->tid,183,&msg); - if (msg){ - sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - eXosip_call_send_answer(h->tid,183,msg); - } - eXosip_unlock(); - }else{ - eXosip_lock(); - eXosip_call_send_answer(h->tid,180,NULL); - eXosip_unlock(); - } - return 0; -} - -int sal_call_accept(SalOp * h){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - /* sends a 200 OK */ - int err=eXosip_call_build_answer(h->tid,200,&msg); - if (err<0 || msg==NULL){ - ms_error("Fail to build answer for call: err=%i",err); - return -1; - } - if (h->base.root->session_expires!=0){ - if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); - } - - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - - if (h->base.local_media){ - /*this is the case where we received an invite without SDP*/ - if (h->sdp_offering) { - set_sdp_from_desc(msg,h->base.local_media); - }else{ - if (h->sdp_answer==NULL) sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - }else{ - ms_error("You are accepting a call but not defined any media capabilities !"); - } - eXosip_call_send_answer(h->tid,200,msg); - return 0; -} - -int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){ - if (reason==SalReasonBusy){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,486,NULL); - eXosip_unlock(); - } - else if (reason==SalReasonTemporarilyUnavailable){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,480,NULL); - eXosip_unlock(); - }else if (reason==SalReasonDoNotDisturb){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,600,NULL); - eXosip_unlock(); - }else if (reason==SalReasonMedia){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,415,NULL); - eXosip_unlock(); - }else if (redirect!=NULL && reason==SalReasonRedirect){ - osip_message_t *msg; - int code; - if (strstr(redirect,"sip:")!=0) code=302; - else code=380; - eXosip_lock(); - eXosip_call_build_answer(h->tid,code,&msg); - osip_message_set_contact(msg,redirect); - eXosip_call_send_answer(h->tid,code,msg); - eXosip_unlock(); - }else sal_call_terminate(h); - return 0; -} - -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - return h->base.remote_media; -} - -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - if (h->base.local_media && h->base.remote_media && !h->result){ - sdp_process(h); - } - return h->result; -} - -int sal_call_set_referer(SalOp *h, SalOp *refered_call){ - if (refered_call->replaces) - h->replaces=ms_strdup(refered_call->replaces); - if (refered_call->referred_by) - h->referred_by=ms_strdup(refered_call->referred_by); - return 0; -} - -static int send_notify_for_refer(int did, const char *sipfrag){ - osip_message_t *msg; - eXosip_lock(); - eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Could not build NOTIFY for refer."); - return -1; - } - osip_message_set_content_type(msg,"message/sipfrag"); - osip_message_set_header(msg,"Event","refer"); - osip_message_set_body(msg,sipfrag,strlen(sipfrag)); - eXosip_call_send_request(did,msg); - eXosip_unlock(); - return 0; -} - -/* currently only support to notify trying and 200Ok*/ -int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){ - if (newcall==NULL){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - else if (newcall->cid!=-1){ - if (newcall->did==-1){ - /* not yet established*/ - if (!newcall->terminated){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - }else{ - if (!newcall->terminated){ - if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){ - /* we need previous notify transaction to complete, so buffer the request for later*/ - h->sipfrag_pending="SIP/2.0 200 Ok\r\n"; - } - } - } - } - return 0; -} - -int sal_ping(SalOp *op, const char *from, const char *to){ - osip_message_t *options=NULL; - - sal_op_set_from(op,from); - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - - eXosip_options_build_request (&options, sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (options){ - if (op->base.root->session_expires!=0){ - osip_message_set_header(options, "Session-expires", "200"); - osip_message_set_supported(options, "timer"); - } - sal_add_other(sal_op_get_sal(op),op,options); - return eXosip_options_send_request(options); - } - return -1; -} - -int sal_call_refer(SalOp *h, const char *refer_to){ - osip_message_t *msg=NULL; - int err=0; - eXosip_lock(); - eXosip_call_build_refer(h->did,refer_to, &msg); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - osip_message_t *msg=NULL; - char referto[256]={0}; - int err=0; - eXosip_lock(); - if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){ - ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did); - eXosip_unlock(); - return -1; - } - eXosip_call_build_refer(h->did,referto, &msg); - osip_message_set_header(msg,"Referred-By",h->base.from); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - int cid; - eXosip_lock(); - cid=eXosip_call_find_by_replaces(h->replaces); - eXosip_unlock(); - if (cid>0){ - SalOp *ret=sal_find_call(h->base.root,cid); - return ret; - } - } - return NULL; -} - -int sal_call_send_dtmf(SalOp *h, char dtmf){ - osip_message_t *msg=NULL; - char dtmf_body[128]; - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf); - osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); - osip_message_set_content_type(msg,"application/dtmf-relay"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - } - eXosip_unlock(); - return 0; -} - -static void push_auth_to_exosip(const SalAuthInfo *info){ - const char *userid; - if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; - else userid=info->userid; - ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm); - eXosip_add_authentication_info (info->username,userid, - info->password, NULL,info->realm); -} -/* - * Just for symmetry ;-) - */ -static void pop_auth_from_exosip() { - eXosip_clear_authentication_info(); -} - -int sal_call_terminate(SalOp *h){ - int err; - if (h == NULL) return -1; - if (h->auth_info) push_auth_to_exosip(h->auth_info); - eXosip_lock(); - err=eXosip_call_terminate(h->cid,h->did); - eXosip_unlock(); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - if (err!=0){ - ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did); - } - h->terminated=TRUE; - return 0; -} - -void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ - bool_t terminating=FALSE; - if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) { - terminating=TRUE; - } - if (h->terminated && !terminating) return; - - if (h->pending_auth){ - push_auth_to_exosip(info); - - /*FIXME exosip does not take into account this update register message*/ - /* - if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) { - - }; - */ - update_contact_from_response(h,h->pending_auth->response); - eXosip_lock(); - eXosip_default_action(h->pending_auth); - eXosip_unlock(); - ms_message("eXosip_default_action() done"); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - - if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/ - h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/ - } -} -void sal_op_cancel_authentication(SalOp *h) { - if (h->rid >0) { - sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure"); - } else if (h->cid >0) { - sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0); - } else { - ms_warning("Auth failure not handled"); - } - -} -static void set_network_origin(SalOp *op, osip_message_t *req){ - const char *received=NULL; - int rport=5060; - char origin[64]={0}; - SalTransport transport; - if (extract_received_rport(req,&received,&rport,&transport)!=0){ - osip_via_t *via=NULL; - char *tmp; - osip_message_get_via(req,0,&via); - received=osip_via_get_host(via); - tmp=osip_via_get_port(via); - if (tmp) rport=atoi(tmp); - } - if (transport != SalTransportUDP) { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); - } else { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); - } - __sal_op_set_network_origin(op,origin); -} - -static void set_remote_ua(SalOp* op, osip_message_t *req){ - if (op->base.remote_ua==NULL){ - osip_header_t *h=NULL; - osip_message_get_user_agent(req,0,&h); - if (h){ - op->base.remote_ua=ms_strdup(h->hvalue); - } - } -} - -static void set_remote_contact(SalOp* op, osip_message_t *req){ - if (op->base.remote_contact==NULL){ - osip_contact_t *h=NULL; - osip_message_get_contact(req,0,&h); - if (h){ - char *tmp=NULL; - osip_contact_to_str(h,&tmp); - __sal_op_set_remote_contact(op,tmp); - osip_free(tmp); - } - } -} - -static void set_replaces(SalOp *op, osip_message_t *req){ - osip_header_t *h=NULL; - - if (op->replaces){ - ms_free(op->replaces); - op->replaces=NULL; - } - osip_message_header_get_byname(req,"replaces",0,&h); - if (h){ - if (h->hvalue && h->hvalue[0]!='\0'){ - op->replaces=ms_strdup(h->hvalue); - } - } -} - -static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ - if (ev->cid>0){ - return sal_find_call(sal,ev->cid); - } - if (ev->rid>0){ - return sal_find_register(sal,ev->rid); - } - if (ev->sid>0){ - return sal_find_out_subscribe(sal,ev->sid); - } - if (ev->nid>0){ - return sal_find_in_subscribe(sal,ev->nid); - } - if (ev->response) return sal_find_other(sal,ev->response); - else if (ev->request) return sal_find_other(sal,ev->request); - return NULL; -} - -static void inc_new_call(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - osip_from_t *from,*to; - osip_call_info_t *call_info; - char *tmp=NULL; - sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - - osip_call_id_t *callid=osip_message_get_call_id(ev->request); - - osip_call_id_to_str(callid,&tmp); - op->base.call_id=ms_strdup(tmp); - osip_free(tmp); - - set_network_origin(op,ev->request); - set_remote_contact(op,ev->request); - set_remote_ua(op,ev->request); - set_replaces(op,ev->request); - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - }else op->sdp_offering=TRUE; - - from=osip_message_get_from(ev->request); - to=osip_message_get_to(ev->request); - osip_from_to_str(from,&tmp); - sal_op_set_from(op,tmp); - osip_free(tmp); - osip_from_to_str(to,&tmp); - sal_op_set_to(op,tmp); - osip_free(tmp); - - osip_message_get_call_info(ev->request,0,&call_info); - if(call_info) - { - osip_call_info_to_str(call_info,&tmp); - if( strstr(tmp,"answer-after=") != NULL) - { - op->auto_answer_asked=TRUE; - ms_message("The caller asked to automatically answer the call(Emergency?)\n"); - } - osip_free(tmp); - } - - op->tid=ev->tid; - op->cid=ev->cid; - op->did=ev->did; - sal_add_call(op->base.root,op); - sal->callbacks.call_received(op); -} - -static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("Reinvite for non-existing operation !"); - return; - } - op->reinvite=TRUE; - op->tid=ev->tid; - sdp=eXosip_get_sdp_info(ev->request); - if (op->base.remote_media){ - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=NULL; - } - if (op->result){ - sal_media_description_unref(op->result); - op->result=NULL; - } - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - - }else { - op->sdp_offering=TRUE; - } - sal->callbacks.call_updating(op); -} - -static void handle_ack(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("ack for non-existing call !"); - return; - } - if (op->terminated) { - ms_warning("ack for terminated call, ignoring"); - return; - } - - if (op->sdp_offering){ - sdp=eXosip_get_sdp_info(ev->ack); - if (sdp){ - if (op->base.remote_media) - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_process(op); - sdp_message_free(sdp); - } - } - if (op->reinvite){ - op->reinvite=FALSE; - } - sal->callbacks.call_ack(op); -} - -static void update_contact_from_response(SalOp *op, osip_message_t *response){ - const char *received; - int rport; - SalTransport transport; - if (extract_received_rport(response,&received,&rport,&transport)==0){ - const char *contact=sal_op_get_contact(op); - if (!contact){ - /*no contact given yet, use from instead*/ - contact=sal_op_get_from(op); - } - if (contact){ - SalAddress *addr=sal_address_new(contact); - char *tmp; - sal_address_set_domain(addr,received); - sal_address_set_port_int(addr,rport); - if (transport!=SalTransportUDP) - sal_address_set_transport(addr,transport); - tmp=sal_address_as_string(addr); - ms_message("Contact address updated to %s",tmp); - sal_op_set_contact(op,tmp); - sal_address_destroy(addr); - ms_free(tmp); - } - } -} - -static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been canceled."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return -1; - } - if (ev->did>0) - op->did=ev->did; - op->tid=ev->tid; - - /* update contact if received and rport are set by the server - note: will only be used by remote for next INVITE, if any...*/ - update_contact_from_response(op,ev->response); - return 0; -} - -static void call_ringing(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - SalOp *op=find_op(sal,ev); - if (call_proceeding(sal, ev)==-1) return; - - set_remote_ua(op,ev->response); - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - sal->callbacks.call_ringing(op); -} - -static void call_accepted(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - osip_message_t *msg=NULL; - SalOp *op=find_op(sal,ev); - const char *contact; - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - - op->did=ev->did; - set_remote_ua(op,ev->response); - set_remote_contact(op,ev->response); - - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - eXosip_call_build_ack(ev->did,&msg); - if (msg==NULL) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - contact=sal_op_get_contact(op); - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - if (op->sdp_answer){ - set_sdp(msg,op->sdp_answer); - sdp_message_free(op->sdp_answer); - op->sdp_answer=NULL; - } - eXosip_call_send_ack(ev->did,msg); - sal->callbacks.call_accepted(op); -} - -static void call_terminated(Sal *sal, eXosip_event_t *ev){ - char *from=NULL; - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("Call terminated for already closed call ?"); - return; - } - if (ev->request){ - osip_from_to_str(ev->request->from,&from); - } - sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op)); - if (from) osip_free(from); - op->terminated=TRUE; -} - -static void call_released(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No op associated to this call_released()"); - return; - } - if (!op->terminated){ - /* no response received so far */ - call_failure(sal,ev); - } - sal->callbacks.call_released(op); -} - -static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){ - const char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authenticate_t *prx_auth; - osip_www_authenticate_t *www_auth; - - *username=osip_uri_get_username(resp->from->url); - prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); - www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authenticate_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_www_authenticate_get_realm(www_auth); - - if (prx_realm){ - *realm=prx_realm; - }else if (www_realm){ - *realm=www_realm; - }else{ - return -1; - } - return 0; -} - -static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){ - osip_authorization_t *auth=NULL; - osip_proxy_authorization_t *prx_auth=NULL; - - *username=osip_uri_get_username(msg->from->url); - osip_message_get_authorization(msg, 0, &auth); - if (auth){ - *realm=osip_authorization_get_realm(auth); - return 0; - } - osip_message_get_proxy_authorization(msg,0,&prx_auth); - if (prx_auth){ - *realm=osip_proxy_authorization_get_realm(prx_auth); - return 0; - } - return -1; -} - -static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ - if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0; - if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0; - return -1; -} - -int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ - if (op->pending_auth){ - return get_auth_data(op->pending_auth,realm,username); - } - return -1; -} - -static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication !"); - return TRUE; - } - if (get_auth_data(ev,&realm,&username)==0){ - if (op->pending_auth!=NULL){ - eXosip_event_free(op->pending_auth); - op->pending_auth=ev; - }else{ - op->pending_auth=ev; - sal_add_pending_auth(sal,op); - } - - sal->callbacks.auth_requested(op,realm,username); - return FALSE; - } - return TRUE; -} - -static void authentication_ok(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication_ok!"); - return ; - } - if (op->pending_auth){ - eXosip_event_free(op->pending_auth); - sal_remove_pending_auth(sal,op); - op->pending_auth=NULL; - } - if (get_auth_data(ev,&realm,&username)==0){ - sal->callbacks.auth_success(op,realm,username); - } -} - -static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - int code=0; - char* computedReason=NULL; - const char *reason=NULL; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - - - op=(SalOp*)find_op(sal,ev); - - if (op==NULL) { - ms_warning("Call failure reported for a closed call, ignored."); - return TRUE; - } - - if (ev->response){ - code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - osip_header_t *h=NULL; - if (!osip_message_header_get_byname( ev->response - ,"Reason" - ,0 - ,&h)) { - computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h)); - reason = computedReason; - - } - } - switch(code) - { - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 400: - error=SalErrorUnknown; - break; - case 404: - error=SalErrorFailure; - sr=SalReasonNotFound; - break; - case 415: - error=SalErrorFailure; - sr=SalReasonMedia; - break; - case 422: - eXosip_default_action(ev); - return TRUE; - break; - case 480: - error=SalErrorFailure; - sr=SalReasonTemporarilyUnavailable; - break; - case 486: - error=SalErrorFailure; - sr=SalReasonBusy; - break; - case 487: - break; - case 600: - error=SalErrorFailure; - sr=SalReasonDoNotDisturb; - break; - case 603: - error=SalErrorFailure; - sr=SalReasonDeclined; - break; - default: - if (code>0){ - error=SalErrorFailure; - sr=SalReasonUnknown; - }else error=SalErrorNoResponse; - } - op->terminated=TRUE; - sal->callbacks.call_failure(op,error,sr,reason,code); - if (computedReason != NULL){ - ms_free(computedReason); - } - return TRUE; -} - -/* Request remote side to send us VFU */ -void sal_call_send_vfu_request(SalOp *h){ - osip_message_t *msg=NULL; - char info_body[] = - "" - "" - " " - " " - " " - " " - " " - ""; - - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - osip_message_set_body(msg,info_body,strlen(info_body)); - osip_message_set_content_type(msg,"application/media_control+xml"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - ms_message("Sending VFU request !"); - } - eXosip_unlock(); -} - -static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media control xml received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL && - strstr(body->body,"picture_fast_update")){ - osip_message_t *ans=NULL; - ms_message("Receiving VFU request !"); - if (sal->callbacks.vfu_request){ - sal->callbacks.vfu_request(op); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - return; - } - } - /*in all other cases we must say it is not implemented.*/ - { - osip_message_t *ans=NULL; - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } -} - -static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media dtmf relay received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL){ - osip_message_t *ans=NULL; - const char *name=strstr(body->body,"Signal"); - if (name==NULL) name=strstr(body->body,"signal"); - if (name==NULL) { - ms_warning("Could not extract the dtmf name from the SIP INFO."); - }else{ - char tmp[2]; - name+=strlen("signal"); - if (sscanf(name," = %1s",tmp)==1){ - ms_message("Receiving dtmf %s via SIP INFO.",tmp); - if (sal->callbacks.dtmf_received != NULL) - sal->callbacks.dtmf_received(op, tmp[0]); - } - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } -} - -static void fill_options_answer(osip_message_t *options){ - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); -} - -static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){ - osip_header_t *h=NULL; - osip_message_t *ans=NULL; - ms_message("Receiving REFER request !"); - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - - if (h){ - osip_from_t *from=NULL; - char *tmp; - osip_from_init(&from); - - if (osip_from_parse(from,h->hvalue)==0){ - if (op ){ - osip_uri_header_t *uh=NULL; - osip_header_t *referred_by=NULL; - osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh); - if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){ - ms_message("Found replaces in Refer-To"); - if (op->replaces){ - ms_free(op->replaces); - } - op->replaces=ms_strdup(uh->gvalue); - } - osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by); - if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){ - if (op->referred_by) - ms_free(op->referred_by); - op->referred_by=ms_strdup(referred_by->hvalue); - } - } - osip_uri_header_freelist(&from->url->url_headers); - osip_from_to_str(from,&tmp); - sal->callbacks.refer_received(sal,op,tmp); - osip_free(tmp); - osip_from_free(from); - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,202,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,202,ans); - eXosip_unlock(); - } - else - { - ms_warning("cannot do anything with the refer without destination\n"); - } -} - -static void process_notify(Sal *sal, eXosip_event_t *ev){ - osip_header_t *h=NULL; - char *from=NULL; - SalOp *op=find_op(sal,ev); - osip_message_t *ans=NULL; - - ms_message("Receiving NOTIFY request !"); - osip_from_to_str(ev->request->from,&from); - osip_message_header_get_byname(ev->request,"Event",0,&h); - if(h){ - osip_body_t *body=NULL; - //osip_content_type_t *ct=NULL; - osip_message_get_body(ev->request,0,&body); - //ct=osip_message_get_content_type(ev->request); - if (h->hvalue && strncasecmp(h->hvalue,"refer",strlen("refer"))==0){ - /*special handling of refer events*/ - if (body && body->body){ - osip_message_t *msg; - osip_message_init(&msg); - if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){ - int code=osip_message_get_status_code(msg); - if (code==100){ - sal->callbacks.notify_refer(op,SalReferTrying); - }else if (code==200){ - sal->callbacks.notify_refer(op,SalReferSuccess); - }else if (code>=400){ - sal->callbacks.notify_refer(op,SalReferFailed); - } - } - osip_message_free(msg); - } - }else{ - /*generic handling*/ - sal->callbacks.notify(op,from,h->hvalue); - } - } - /*answer that we received the notify*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - osip_free(from); -} - -static void call_message_new(Sal *sal, eXosip_event_t *ev){ - osip_message_t *ans=NULL; - if (ev->request){ - if (MSG_IS_INFO(ev->request)){ - osip_content_type_t *ct; - ct=osip_message_get_content_type(ev->request); - if (ct && ct->subtype){ - if (strcmp(ct->subtype,"media_control+xml")==0) - process_media_control_xml(sal,ev); - else if (strcmp(ct->subtype,"dtmf-relay")==0) - process_dtmf_relay(sal,ev); - else { - ms_message("Unhandled SIP INFO."); - /*send an "Not implemented" answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } - }else{ - /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } - }else if(MSG_IS_MESSAGE(ev->request)){ - /* SIP messages could be received into call */ - text_received(sal, ev); - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - }else if(MSG_IS_REFER(ev->request)){ - SalOp *op=find_op(sal,ev); - - ms_message("Receiving REFER request !"); - process_refer(sal,op,ev); - }else if(MSG_IS_NOTIFY(ev->request)){ - process_notify(sal,ev); - }else if (MSG_IS_OPTIONS(ev->request)){ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans){ - fill_options_answer(ans); - eXosip_call_send_answer(ev->tid,200,ans); - } - eXosip_unlock(); - } - }else ms_warning("call_message_new: No request ?"); -} - -static void inc_update(Sal *sal, eXosip_event_t *ev){ - osip_message_t *msg=NULL; - ms_message("Processing incoming UPDATE"); - eXosip_lock(); - eXosip_message_build_answer(ev->tid,200,&msg); - if (msg!=NULL) - eXosip_message_send_answer(ev->tid,200,msg); - eXosip_unlock(); -} - -static bool_t comes_from_local_if(osip_message_t *msg){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - const char *host; - host=osip_via_get_host(via); - if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ - osip_generic_param_t *param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param==NULL) return TRUE; - if (param->gvalue && - (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ - return TRUE; - } - } - } - return FALSE; -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static int utc_offset() { - time_t ref = 24 * 60 * 60L; - struct tm * timeptr; - int gmtime_hours; - - /* get the local reference time for Jan 2, 1900 00:00 UTC */ - timeptr = localtime(&ref); - gmtime_hours = timeptr->tm_hour; - - /* if the local time is the "day before" the UTC, subtract 24 hours - from the hours to get the UTC offset */ - if (timeptr->tm_mday < 2) gmtime_hours -= 24; - - return gmtime_hours; -} - -time_t mktime_utc(struct tm *timeptr) { - return mktime(timeptr) + utc_offset() * 3600; -} - -static void text_received(Sal *sal, eXosip_event_t *ev){ - osip_body_t *body=NULL; - char *from=NULL,*msg=NULL; - osip_content_type_t* content_type; - osip_uri_param_t* external_body_url; - char unquoted_external_body_url [256]; - int external_body_size=0; - SalMessage salmsg; - char message_id[256]={0}; - osip_header_t *date=NULL; - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - SalOp *op=sal_op_new(sal); - - osip_message_get_date(ev->request,0,&date); - if(date!=NULL){ - int i,j; - sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2, - &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec); - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=0; - }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent."); - - content_type= osip_message_get_content_type(ev->request); - if (!content_type) { - ms_error("Could not get message because no content type"); - return; - } - osip_from_to_str(ev->request->from,&from); - if (content_type->type - && strcmp(content_type->type, "text")==0 - && content_type->subtype - && strcmp(content_type->subtype, "plain")==0 ) { - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - osip_free(from); - return; - } - msg=body->body; - }else if (content_type->type - && strcmp(content_type->type, "message")==0 - && content_type->subtype - && strcmp(content_type->subtype, "external-body")==0 ) { - - osip_content_type_param_get_byname(content_type, "URL", &external_body_url); - /*remove both first and last character*/ - strncpy(unquoted_external_body_url - ,&external_body_url->gvalue[1] - ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); - unquoted_external_body_url[external_body_size-1]='\0'; - } else { - ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); - osip_free(from); - return; - } - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number); - - salmsg.from=from; - salmsg.text=msg; - salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; - salmsg.message_id=message_id; - salmsg.time=date!=NULL ? mktime_utc(&ret) : time(NULL); - sal->callbacks.text_received(op,&salmsg); - sal_op_release(op); - osip_free(from); -} - -static void other_request(Sal *sal, eXosip_event_t *ev){ - ms_message("in other_request"); - if (ev->request==NULL) return; - if (strcmp(ev->request->sip_method,"MESSAGE")==0){ - text_received(sal,ev); - eXosip_message_send_answer(ev->tid,200,NULL); - }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ - osip_message_t *options=NULL; - eXosip_options_build_answer(ev->tid,200,&options); - fill_options_answer(options); - eXosip_options_send_answer(ev->tid,200,options); - }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ - ms_message("Receiving REFER request !"); - if (comes_from_local_if(ev->request)) { - process_refer(sal,NULL,ev); - }else ms_warning("Ignored REFER not coming from this local loopback interface."); - }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ - inc_update(sal,ev); - }else { - char *tmp=NULL; - size_t msglen=0; - osip_message_to_str(ev->request,&tmp,&msglen); - if (tmp){ - ms_message("Unsupported request received:\n%s",tmp); - osip_free(tmp); - } - /*answer with a 501 Not implemented*/ - eXosip_message_send_answer(ev->tid,501,NULL); - } -} - -static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - osip_free(via->port); - via->port=osip_strdup(port); - osip_free(via->host); - via->host=osip_strdup(ip); - } -} - - -static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) { - osip_contact_t *ctt=NULL; - const char *received; - int rport; - SalTransport transport; - char port[20]; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - osip_message_get_contact(request,0,&ctt); - if (ctt == NULL) { - ms_warning("fix_message_contact(): no contact to update"); - return FALSE; - } - if (expire_last_contact){ - osip_contact_t *oldct=NULL,*prevct; - osip_generic_param_t *param=NULL; - osip_contact_clone(ctt,&oldct); - while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){ - osip_contact_free(prevct); - osip_list_remove(&request->contacts,1); - } - osip_list_add(&request->contacts,oldct,1); - osip_contact_param_get_byname(oldct,"expires",¶m); - if (param){ - if (param->gvalue) osip_free(param->gvalue); - param->gvalue=osip_strdup("0"); - }else{ - osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0")); - } - } - if (ctt->url->host!=NULL){ - osip_free(ctt->url->host); - } - ctt->url->host=osip_strdup(received); - if (ctt->url->port!=NULL){ - osip_free(ctt->url->port); - } - snprintf(port,sizeof(port),"%i",rport); - ctt->url->port=osip_strdup(port); - if (op->masquerade_via) masquerade_via(request,received,port); - - if (transport != SalTransportUDP) { - sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); - } - return TRUE; -} - -static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ - osip_contact_t *ctt=NULL; - SalAddress* ori_contact_address=NULL; - const char *received; - int rport; - SalTransport transport; - char* tmp; - osip_message_t *msg=NULL; - Sal* sal=op->base.root; - int i=0; - bool_t found_valid_contact=FALSE; - bool_t from_request=FALSE; - - if (sal->double_reg==FALSE ) return FALSE; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - do{ - ctt=NULL; - osip_message_get_contact(last_answer,i,&ctt); - if (!from_request && ctt==NULL) { - osip_message_get_contact(orig_request,0,&ctt); - from_request=TRUE; - } - if (ctt){ - osip_contact_to_str(ctt,&tmp); - ori_contact_address = sal_address_new(tmp); - - /*check if contact is up to date*/ - if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 - && sal_address_get_port_int(ori_contact_address) == rport - && sal_address_get_transport(ori_contact_address) == transport) { - if (!from_request){ - ms_message("Register response has up to date contact, doing nothing."); - }else { - ms_warning("Register response does not have up to date contact, but last request had." - "Stupid registrar detected, giving up."); - } - found_valid_contact=TRUE; - } - osip_free(tmp); - sal_address_destroy(ori_contact_address); - }else break; - i++; - }while(!found_valid_contact); - if (!found_valid_contact) - ms_message("Contact do not match, resending register."); - else return FALSE; - - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Fail to create a contact updated register."); - return FALSE; - } - if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) { - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - ms_message("Resending new register with updated contact"); - update_contact_from_response(op,last_answer); - return TRUE; - } else { - ms_warning("Fail to send updated register."); - eXosip_unlock(); - return FALSE; - } - eXosip_unlock(); - return FALSE; -} - -static void registration_success(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_register(sal,ev->rid); - osip_header_t *h=NULL; - bool_t registered; - if (op==NULL){ - ms_error("Receiving register response for unknown operation"); - return; - } - osip_message_get_expires(ev->request,0,&h); - if (h!=NULL && atoi(h->hvalue)!=0){ - registered=TRUE; - if (!register_again_with_updated_contact(op,ev->request,ev->response)){ - sal->callbacks.register_success(op,registered); - } - }else { - sal->callbacks.register_success(op,FALSE); - } -} - -static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ - int status_code=0; - const char *reason=NULL; - SalOp *op=sal_find_register(sal,ev->rid); - SalReason sr=SalReasonUnknown; - SalError se=SalErrorUnknown; - - if (op==NULL){ - ms_error("Receiving register failure for unknown operation"); - return TRUE; - } - if (ev->response){ - status_code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - } - switch(status_code){ - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 423: /*interval too brief*/ - {/*retry with greater interval */ - osip_header_t *h=NULL; - osip_message_t *msg=NULL; - osip_message_header_get_byname(ev->response,"min-expires",0,&h); - if (h && h->hvalue && h->hvalue[0]!='\0'){ - int val=atoi(h->hvalue); - if (val>op->expires) - op->expires=val; - }else op->expires*=2; - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - } - break; - case 606: /*Not acceptable, workaround for proxies that don't like private addresses - in vias, such as ekiga.net - On the opposite, freephonie.net bugs when via are masqueraded. - */ - op->masquerade_via=TRUE; - default: - /* if contact is up to date, process the failure, otherwise resend a new register with - updated contact first, just in case the faillure is due to incorrect contact */ - if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response)) - return TRUE; /*we are retrying with an updated contact*/ - if (status_code==403){ - se=SalErrorFailure; - sr=SalReasonForbidden; - }else if (status_code==0){ - se=SalErrorNoResponse; - } - sal->callbacks.register_failure(op,se,sr,reason); - } - return TRUE; -} - -static void other_request_reply(Sal *sal,eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("other_request_reply(): Receiving response to unknown request."); - return; - } - if (ev->response){ - ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request)); - update_contact_from_response(op,ev->response); - if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0) - sal->callbacks.ping_reply(op); - } - if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) { - /*out of call message acknolegment*/ - SalTextDeliveryStatus status=SalTextDeliveryFailed; - if (ev->response){ - if (ev->response->status_code<200){ - status=SalTextDeliveryInProgress; - }else if (ev->response->status_code<300 && ev->response->status_code>=200){ - status=SalTextDeliveryDone; - } - } - sal->callbacks.text_delivery_update(op,status); - } -} - -static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (ev->response){ - if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){ - if (op->sipfrag_pending){ - send_notify_for_refer(op->did,op->sipfrag_pending); - op->sipfrag_pending=NULL; - } - } - } -} - -static bool_t process_event(Sal *sal, eXosip_event_t *ev){ - ms_message("linphone process event get a message %d\n",ev->type); - switch(ev->type){ - case EXOSIP_CALL_ANSWERED: - ms_message("CALL_ANSWERED\n"); - call_accepted(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_CLOSED: - case EXOSIP_CALL_CANCELLED: - ms_message("CALL_CLOSED or CANCELLED\n"); - call_terminated(sal,ev); - break; - case EXOSIP_CALL_TIMEOUT: - case EXOSIP_CALL_NOANSWER: - ms_message("CALL_TIMEOUT or NOANSWER\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_REQUESTFAILURE: - case EXOSIP_CALL_GLOBALFAILURE: - case EXOSIP_CALL_SERVERFAILURE: - ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_RELEASED: - ms_message("CALL_RELEASED\n"); - call_released(sal, ev); - break; - case EXOSIP_CALL_INVITE: - ms_message("CALL_NEW\n"); - inc_new_call(sal,ev); - break; - case EXOSIP_CALL_REINVITE: - handle_reinvite(sal,ev); - break; - case EXOSIP_CALL_ACK: - ms_message("CALL_ACK"); - handle_ack(sal,ev); - break; - case EXOSIP_CALL_REDIRECTED: - ms_message("CALL_REDIRECTED"); - eXosip_default_action(ev); - break; - case EXOSIP_CALL_PROCEEDING: - ms_message("CALL_PROCEEDING"); - call_proceeding(sal,ev); - break; - case EXOSIP_CALL_RINGING: - ms_message("CALL_RINGING"); - call_ringing(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_NEW: - ms_message("EXOSIP_CALL_MESSAGE_NEW"); - call_message_new(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: - if (ev->response && - (ev->response->status_code==407 || ev->response->status_code==401)){ - return process_authentication(sal,ev); - } - break; - case EXOSIP_CALL_MESSAGE_ANSWERED: - ms_message("EXOSIP_CALL_MESSAGE_ANSWERED "); - process_in_call_reply(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_IN_SUBSCRIPTION_NEW "); - sal_exosip_subscription_recv(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_RELEASED: - ms_message("CALL_SUBSCRIPTION_NEW "); - sal_exosip_in_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_UPDATE: - ms_message("CALL_SUBSCRIPTION_UPDATE"); - break; - case EXOSIP_SUBSCRIPTION_NOTIFY: - ms_message("CALL_SUBSCRIPTION_NOTIFY"); - sal_exosip_notify_recv(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did); - sal_exosip_subscription_answered(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_CLOSED: - ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /**< announce a request failure */ - if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ - return process_authentication(sal,ev); - } - case EXOSIP_SUBSCRIPTION_SERVERFAILURE: - case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_REGISTRATION_FAILURE: - ms_message("REGISTRATION_FAILURE\n"); - return registration_failure(sal,ev); - break; - case EXOSIP_REGISTRATION_SUCCESS: - authentication_ok(sal,ev); - registration_success(sal,ev); - break; - case EXOSIP_MESSAGE_NEW: - other_request(sal,ev); - break; - case EXOSIP_MESSAGE_PROCEEDING: - case EXOSIP_MESSAGE_ANSWERED: - case EXOSIP_MESSAGE_REDIRECTED: - case EXOSIP_MESSAGE_SERVERFAILURE: - case EXOSIP_MESSAGE_GLOBALFAILURE: - other_request_reply(sal,ev); - break; - case EXOSIP_MESSAGE_REQUESTFAILURE: - case EXOSIP_NOTIFICATION_REQUESTFAILURE: - if (ev->response) { - switch (ev->response->status_code) { - case 407: - case 401: - return process_authentication(sal,ev); - case 412: { - eXosip_automatic_action (); - return 1; - } - } - } - other_request_reply(sal,ev); - break; - default: - ms_message("Unhandled exosip event ! %i",ev->type); - break; - } - return TRUE; -} - -int sal_iterate(Sal *sal){ - eXosip_event_t *ev; - while((ev=eXosip_event_wait(0,0))!=NULL){ - if (process_event(sal,ev)) - eXosip_event_free(ev); - } -#ifdef HAVE_EXOSIP_TRYLOCK - if (eXosip_trylock()==0){ - eXosip_automatic_refresh(); - eXosip_unlock(); - }else{ - ms_warning("eXosip_trylock busy."); - } -#else - eXosip_lock(); - eXosip_automatic_refresh(); - eXosip_unlock(); -#endif - return 0; -} - -static void register_set_contact(osip_message_t *msg, const char *contact){ - osip_uri_param_t *param = NULL; - osip_contact_t *ct=NULL; - char *line=NULL; - /*we get the line parameter choosed by exosip, and add it to our own contact*/ - osip_message_get_contact(msg,0,&ct); - if (ct!=NULL){ - osip_uri_uparam_get_byname(ct->url, "line", ¶m); - if (param && param->gvalue) - line=osip_strdup(param->gvalue); - } - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - osip_message_get_contact(msg,0,&ct); - osip_uri_uparam_add(ct->url,osip_strdup("line"),line); -} - -void sal_message_add_route(osip_message_t *msg, const char *proxy){ - osip_route_t *route; - - osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free); - - osip_route_init(&route); - if (osip_route_parse(route,proxy)==0){ - osip_uri_param_t *lr_param = NULL; - osip_uri_uparam_get_byname(route->url, "lr", &lr_param); - if (lr_param == NULL){ - osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL); - } - osip_list_add(&msg->routes,route,0); - return; - } - osip_route_free(route); -} - - -int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - - sal_op_set_route(h,proxy); - if (h->rid==-1){ - SalAddress *from_parsed=sal_address_new(from); - char domain[256]; - char *uri, *domain_ptr = NULL; - if (from_parsed==NULL) { - ms_warning("sal_register() bad from %s",from); - return -1; - } - /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of - using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */ - uri = sal_address_as_string_uri_only(from_parsed); - if (uri) domain_ptr = strchr(uri, '@'); - if (domain_ptr) { - snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1); - } else { - snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed)); - } - if (uri) ms_free(uri); - sal_address_destroy(from_parsed); - eXosip_lock(); - h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg); - if (msg){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,proxy); - sal_add_register(h->base.root,h); - }else{ - ms_error("Could not build initial register."); - eXosip_unlock(); - return -1; - } - }else{ - eXosip_lock(); - eXosip_register_build_register(h->rid,expires,&msg); - sal_message_add_route(msg,proxy); - } - if (msg){ - eXosip_register_send_register(h->rid,msg); - } - eXosip_unlock(); - h->expires=expires; - return (msg != NULL) ? 0 : -1; -} - -int sal_register_refresh(SalOp *op, int expires){ - osip_message_t *msg=NULL; - const char *contact=sal_op_get_contact(op); - - if (op->rid==-1){ - ms_error("Unexistant registration context, not possible to refresh."); - return -1; - } -#ifdef HAVE_EXOSIP_TRYLOCK - { - int tries=0; - /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever. - * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take - * the exosip lock in a non blocking way, and give up if it takes too long*/ - while (eXosip_trylock()!=0){ - ms_usleep(100000); - tries++; - if (tries>30) {/*after 3 seconds, give up*/ - ms_warning("Could not obtain exosip lock in a reasonable time, giving up."); - return -1; - } - } - } -#else - eXosip_lock(); -#endif - eXosip_register_build_register(op->rid,expires,&msg); - if (msg!=NULL){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,sal_op_get_route(op)); - eXosip_register_send_register(op->rid,msg); - }else ms_error("Could not build REGISTER refresh message."); - eXosip_unlock(); - return (msg != NULL) ? 0 : -1; -} - - -int sal_unregister(SalOp *h){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_register_build_register(h->rid,0,&msg); - if (msg) eXosip_register_send_register(h->rid,msg); - else ms_warning("Could not build unREGISTER !"); - eXosip_unlock(); - return 0; -} - -SalAddress * sal_address_new(const char *uri){ - osip_from_t *from; - osip_from_init(&from); - - // Remove front spaces - while (uri[0]==' ') { - uri++; - } - - if (osip_from_parse(from,uri)!=0){ - osip_from_free(from); - return NULL; - } - if (from->displayname!=NULL && from->displayname[0]=='"'){ - char *unquoted=osip_strdup_without_quote(from->displayname); - osip_free(from->displayname); - from->displayname=unquoted; - } - return (SalAddress*)from; -} - -SalAddress * sal_address_clone(const SalAddress *addr){ - osip_from_t *ret=NULL; - osip_from_clone((osip_from_t*)addr,&ret); - return (SalAddress*)ret; -} - -#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL ) - -const char *sal_address_get_scheme(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->scheme); -} - -const char *sal_address_get_display_name(const SalAddress* addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->displayname); -} - -const char *sal_address_get_username(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->username); -} - -const char *sal_address_get_domain(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->host); -} - -void sal_address_set_display_name(SalAddress *addr, const char *display_name){ - osip_from_t *u=(osip_from_t*)addr; - if (u->displayname!=NULL){ - osip_free(u->displayname); - u->displayname=NULL; - } - if (display_name!=NULL && display_name[0]!='\0'){ - u->displayname=osip_strdup(display_name); - } -} - -void sal_address_set_username(SalAddress *addr, const char *username){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->username!=NULL){ - osip_free(uri->url->username); - uri->url->username=NULL; - } - if (username) - uri->url->username=osip_strdup(username); -} - -void sal_address_set_domain(SalAddress *addr, const char *host){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->host!=NULL){ - osip_free(uri->url->host); - uri->url->host=NULL; - } - if (host) - uri->url->host=osip_strdup(host); -} - -void sal_address_set_port(SalAddress *addr, const char *port){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->port!=NULL){ - osip_free(uri->url->port); - uri->url->port=NULL; - } - if (port) - uri->url->port=osip_strdup(port); -} - -void sal_address_set_port_int(SalAddress *uri, int port){ - char tmp[12]; - if (port==5060){ - /*this is the default, special case to leave the port field blank*/ - sal_address_set_port(uri,NULL); - return; - } - snprintf(tmp,sizeof(tmp),"%i",port); - sal_address_set_port(uri,tmp); -} - -void sal_address_clean(SalAddress *addr){ - osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params); - osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params); -} - -char *sal_address_as_string(const SalAddress *u){ - char *tmp,*ret; - osip_from_t *from=(osip_from_t *)u; - char *old_displayname=NULL; - /* hack to force use of quotes around the displayname*/ - if (from->displayname!=NULL - && from->displayname[0]!='"'){ - old_displayname=from->displayname; - from->displayname=osip_enquote(from->displayname); - } - osip_from_to_str(from,&tmp); - if (old_displayname!=NULL){ - ms_free(from->displayname); - from->displayname=old_displayname; - } - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} - -char *sal_address_as_string_uri_only(const SalAddress *u){ - char *tmp=NULL,*ret; - osip_uri_to_str(((osip_from_t*)u)->url,&tmp); - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} -void sal_address_set_param(SalAddress *u,const char* name,const char* value) { - osip_uri_param_t *param=NULL; - osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,¶m); - if (param == NULL){ - osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL); - } else { - osip_free(param->gvalue); - param->gvalue=value ? osip_strdup(value) : NULL; - } - -} - -void sal_address_destroy(SalAddress *u){ - osip_from_free((osip_from_t*)u); -} - -void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { - ctx->tcp_tls_keepalive = enabled; -} - -void sal_set_keepalive_period(Sal *ctx,unsigned int value) { - switch (ctx->transport) { - case SalTransportUDP: - ctx->keepalive_period = value; - break; - case SalTransportTCP: - case SalTransportTLS: - if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value; - else ctx->keepalive_period = -1; - break; - default: - break; - } - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period); -} -unsigned int sal_get_keepalive_period(Sal *ctx) { - return ctx->keepalive_period; -} - -const char * sal_address_get_port(const SalAddress *addr) { - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->port); -} - -int sal_address_get_port_int(const SalAddress *uri) { - const char* port = sal_address_get_port(uri); - if (port != NULL) { - return atoi(port); - } else { - return 5060; - } -} -SalTransport sal_address_get_transport(const SalAddress* addr) { - const osip_from_t *u=(const osip_from_t*)addr; - osip_uri_param_t *transport_param=NULL; - osip_uri_uparam_get_byname(u->url,"transport",&transport_param); - if (transport_param == NULL){ - return SalTransportUDP; - } else { - return sal_transport_parse(transport_param->gvalue); - } -} -void sal_address_set_transport(SalAddress* addr,SalTransport transport) { - sal_address_set_param(addr, "transport", sal_transport_to_string(transport)); -} - -/* sends a reinvite. Local media description may have changed by application since call establishment*/ -int sal_call_update(SalOp *h, const char *subject){ - int err=0; - osip_message_t *reinvite=NULL; - - eXosip_lock(); - if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){ - eXosip_unlock(); - return -1; - } - eXosip_unlock(); - osip_message_set_subject(reinvite,subject); - osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(reinvite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(reinvite, "Session-expires", "200"); - osip_message_set_supported(reinvite, "timer"); - } - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(reinvite,h->base.local_media); - }else h->sdp_offering=FALSE; - eXosip_lock(); - err = eXosip_call_send_request(h->did, reinvite); - eXosip_unlock(); - return err; -} - -void sal_reuse_authorization(Sal *ctx, bool_t value) { - ctx->reuse_authorization=value; -} - -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){ - MSList *elem=(MSList*)ch; - for (;elem!=NULL;elem=elem->next){ - SalCustomHeader *it=(SalCustomHeader*)elem; - osip_message_set_header(msg,it->header_name,it->header_value); - } -} - -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){ - int i=0; - osip_header_t *header; - SalCustomHeader *ret=NULL; - - while((header=osip_list_get(&msg->headers,i))!=NULL){ - ret=sal_custom_header_append(ret,header->hname,header->hvalue); - i++; - } - return ret; -} - diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h deleted file mode 100644 index e00dd64d9..000000000 --- a/coreapi/sal_eXosip2.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef sal_exosip2_h -#define sal_exosip2_h - -#include "sal.h" -#include - - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); -int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); - -struct Sal{ - SalCallbacks callbacks; - SalTransport transport; - MSList *calls; /*MSList of SalOp */ - MSList *registers;/*MSList of SalOp */ - MSList *out_subscribes;/*MSList of SalOp */ - MSList *in_subscribes;/*MSList of SalOp */ - MSList *pending_auths;/*MSList of SalOp */ - MSList *other_transactions; /*MSList of SalOp */ - int running; - int session_expires; - int keepalive_period; - void *up; /*user pointer*/ - char* rootCa; /* File _or_ folder containing root CA */ - int dscp; - bool_t one_matching_codec; - bool_t double_reg; - bool_t use_rports; - bool_t use_101; - bool_t reuse_authorization; - bool_t verify_server_certs; - bool_t verify_server_cn; - bool_t expire_old_contact; - bool_t add_dates; - bool_t tcp_tls_keepalive; -}; - -struct SalOp{ - SalOpBase base; - int cid; - int did; - int tid; - int rid; - int sid; - int nid; - int expires; - SalMediaDescription *result; - sdp_message_t *sdp_answer; - eXosip_event_t *pending_auth; - osip_call_id_t *call_id; /*used for out of calls transaction in order - to retrieve the operation when receiving a response*/ - char *replaces; - char *referred_by; - const SalAuthInfo *auth_info; - const char *sipfrag_pending; - bool_t supports_session_timers; - bool_t sdp_offering; - bool_t reinvite; - bool_t masquerade_via; - bool_t auto_answer_asked; - bool_t terminated; -}; - -void sal_remove_out_subscribe(Sal *sal, SalOp *op); -void sal_remove_in_subscribe(Sal *sal, SalOp *op); -void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request); - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); -void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev); -SalOp * sal_find_out_subscribe(Sal *sal, int sid); -SalOp * sal_find_in_subscribe(Sal *sal, int nid); -void sal_exosip_fix_route(SalOp *op); -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch); -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg); - -void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)); - -void sal_message_add_route(osip_message_t *msg, const char *proxy); - -#endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c deleted file mode 100644 index c99a48793..000000000 --- a/coreapi/sal_eXosip2_presence.c +++ /dev/null @@ -1,829 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - - -#include "sal_eXosip2.h" - -typedef enum { - PIDF = 0, - RFCxxxx = 1, - MSOLDPRES = 2 -} presence_type_t; - -/* - * REVISIT: this static variable forces every dialog to use the same presence description type depending - * on what is received on a single dialog... - */ -static presence_type_t presence_style = PIDF; - -SalOp * sal_find_out_subscribe(Sal *sal, int sid){ - const MSList *elem; - SalOp *op; - for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->sid==sid) return op; - } - ms_message("No op for sid %i",sid); - return NULL; -} - -static void sal_add_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_append(sal->out_subscribes,op); -} - -void sal_remove_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_remove(sal->out_subscribes,op); -} - -SalOp * sal_find_in_subscribe(Sal *sal, int nid){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->nid==nid) return op; - } - return NULL; -} - -static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->call_id && osip_call_id_match(op->call_id,call_id)==0) - return op; - } - return NULL; -} - -static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){ - osip_call_id_clone(subs->call_id,&op->call_id); - sal->in_subscribes=ms_list_append(sal->in_subscribes,op); -} - -void sal_remove_in_subscribe(Sal *sal, SalOp *op){ - sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static void msg_add_current_date(osip_message_t *msg){ - char tmp[64]={0}; - time_t curtime=time(NULL); - struct tm *ret; -#ifndef WIN32 - struct tm gmt; - ret=gmtime_r(&curtime,&gmt); -#else - ret=gmtime(&curtime); -#endif - /*cannot use strftime because it is locale dependant*/ - snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", - days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); - osip_message_replace_header(msg,"Date",tmp); -} - - -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ - osip_message_t *sip=NULL; - - if(op->cid == -1) - { - /* we are not currently in communication with the destination */ - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (sip!=NULL){ - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - sal_add_other(op->base.root,op,sip); - eXosip_message_send_request(sip); - }else{ - ms_error("Could not build MESSAGE request !"); - } - eXosip_unlock(); - } - else - { - /* we are currently in communication with the destination */ - eXosip_lock(); - //First we generate an INFO message to get the current call_id and a good cseq - eXosip_call_build_request(op->did,"MESSAGE",&sip); - if(sip == NULL) - { - ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?"); - eXosip_unlock(); - return -1; - } - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - eXosip_call_send_request(op->did,sip); - eXosip_unlock(); - } - return 0; -} - -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { - return sal_message_send(op,from,to,"text/plain",msg); -} -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ - osip_message_t *msg=NULL; - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), - sal_op_get_route(op),"presence",600); - if (msg==NULL){ - ms_error("Could not build subscribe request to %s",to); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - op->sid=eXosip_subscribe_send_initial_request(msg); - eXosip_unlock(); - if (op->sid==-1){ - osip_message_free(msg); - return -1; - } - sal_add_out_subscribe(op->base.root,op); - return 0; -} - -int sal_unsubscribe(SalOp *op){ - osip_message_t *msg=NULL; - if (op->did==-1){ - ms_error("cannot unsubscribe, no dialog !"); - return -1; - } - eXosip_lock(); - eXosip_subscribe_build_refresh_request(op->did,&msg); - if (msg){ - osip_message_set_expires(msg,"0"); - eXosip_subscribe_send_refresh_request(op->did,msg); - }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i", - op->sid,op->did); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_accept(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_answer(op->tid,202,&msg); - if (msg==NULL){ - ms_error("Fail to build answer to subscribe."); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - eXosip_insubscription_send_answer(op->tid,202,msg); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_decline(SalOp *op){ - eXosip_lock(); - eXosip_insubscription_send_answer(op->tid,401,NULL); - eXosip_unlock(); - return 0; -} - -static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info, - char *buf, size_t buflen, presence_type_t ptype) { - switch (ptype) { - case RFCxxxx: { - /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - case MSOLDPRES: { - /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence - * so messages format has been taken from Communigate that can send notify - * requests with this schema - */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */ - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceOnVacation) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"Out to lunch \n" -"\n" -"", -contact_info, contact_info); - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"closed\n" -"%s\n" -"\n" -"\n", contact_info, contact_info); - } - break; - } - } // switch - -} - -static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) -{ - char buf[1000]; - char *contact_info; - - osip_from_t *from=NULL; - from=osip_message_get_from(notify); - osip_uri_to_str(from->url,&contact_info); - - mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); - - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, - presence_style ? "application/xpidf+xml" : "application/pidf+xml"); - - osip_free(contact_info); -} - - -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ - osip_message_t *msg=NULL; - eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE; - if (op->nid==-1){ - ms_warning("Cannot notify, subscription was closed."); - return -1; - } - - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,identity); - add_presence_body(msg,status); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("could not create notify for incoming subscription."); - eXosip_unlock(); - return 0; -} - -int sal_notify_close(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - osip_message_set_contact(msg,identity); - add_presence_body(msg,SalPresenceOffline); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("sal_notify_close(): could not create notify for incoming subscription" - " did=%i, nid=%i",op->did,op->nid); - eXosip_unlock(); - return 0; -} - -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){ - osip_message_t *pub; - int i; - char buf[1024]; - const char *route=sal_op_get_route(op); - - mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - - i = eXosip_build_publish(&pub,to, from, NULL, "presence", "600", - presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); - if (i<0){ - ms_warning("Failed to build publish request."); - return -1; - } - if (route) - sal_message_add_route(pub,route); - - eXosip_lock(); - i = eXosip_publish(pub, to); /* should update the sip-if-match parameter - from sip-etag from last 200ok of PUBLISH */ - eXosip_unlock(); - if (i<0){ - ms_message("Failed to send publish request."); - return -1; - } - sal_add_other(sal_op_get_sal(op),op,pub); - return 0; -} - -static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - char *tmp; - op->did=ev->did; - op->tid=ev->tid; - op->nid=ev->nid; - osip_from_to_str(ev->request->from,&tmp); - sal_op_set_from(op,tmp); - ms_free(tmp); - osip_from_to_str(ev->request->to,&tmp); - sal_op_set_to(op,tmp); - ms_free(tmp); - sal_add_in_subscribe(sal,op,ev->request); - sal->callbacks.subscribe_received(op,sal_op_get_from(op)); -} - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are - recognized as new incoming subscribes*/ - SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id); - if (op){ - osip_header_t *h; - osip_message_header_get_byname(ev->request,"expires",0,&h); - if (h && h->hvalue && atoi(h->hvalue)==0){ - ms_warning("This susbscribe is not a new one but terminates an old one."); - ev->did=op->did; - ev->nid=op->nid; - sal_exosip_subscription_closed(sal,ev); - }else { - osip_message_t *msg=NULL; - ms_warning("Probably a refresh subscribe"); - eXosip_lock(); - eXosip_insubscription_build_answer(ev->tid,202,&msg); - eXosip_insubscription_send_answer(ev->tid,202,msg); - eXosip_unlock(); - } - }else _sal_exosip_subscription_recv(sal,ev); -} - -void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - char *tmp; - osip_from_t *from=NULL; - osip_body_t *body=NULL; - SalPresenceStatus estatus=SalPresenceOffline; - - ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); - - if (op==NULL){ - ms_error("No operation related to this notify !"); - return; - } - if (ev->request==NULL) return; - - from=ev->request->from; - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("No body in NOTIFY"); - return; - } - osip_from_to_str(from,&tmp); - if (strstr(body->body,"pending")!=NULL){ - estatus=SalPresenceOffline; - }else if (strstr(body->body,"busy")!=NULL){ - estatus=SalPresenceBusy; - }else if (strstr(body->body,"berightback")!=NULL - || strstr(body->body,"in-transit")!=NULL ){ - estatus=SalPresenceBerightback; - }else if (strstr(body->body,"away")!=NULL - || strstr(body->body,"idle")){ - estatus=SalPresenceAway; - }else if (strstr(body->body,"onthephone")!=NULL - || strstr(body->body,"on-the-phone")!=NULL){ - estatus=SalPresenceOnthephone; - }else if (strstr(body->body,"outtolunch")!=NULL - || strstr(body->body,"lunch") != 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 if(strstr(body->body,"vacation") != NULL) { - estatus = SalPresenceOnVacation; - }else{ - estatus=SalPresenceOffline; - } - ms_message("We are notified that %s has online status %i",tmp,estatus); - if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - ms_message("And outgoing subscription terminated by remote."); - } - sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL); - - /* try to detect presence message style used by server, - * and switch our presence messages to servers style */ - if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) { - presence_style = RFCxxxx; - } else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) { - presence_style = MSOLDPRES; - } - - osip_free(tmp); -} - -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription answered but no associated op !"); - return; - } - op->did=ev->did; -} - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_in_subscribe(sal,ev->nid); - char *tmp; - if (op==NULL){ - ms_error("Incoming subscription closed but no associated op !"); - return; - } - - - sal_remove_in_subscribe(sal,op); - op->nid=-1; - op->did=-1; - if (ev->request){ - osip_from_to_str(ev->request->from,&tmp); - sal->callbacks.subscribe_closed(op,tmp); - osip_free(tmp); - } -} - -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription closed but no associated op !"); - return; - } - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - sal->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); -} - - diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c deleted file mode 100644 index 54865aab6..000000000 --- a/coreapi/sal_eXosip2_sdp.c +++ /dev/null @@ -1,618 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - - -#include "ortp/port.h" -#include "ortp/b64.h" -#include "ortp/ortp_srtp.h" -#include "sal.h" -#include - -#define keywordcmp(key,b) strcmp(key,b) - -#ifdef FOR_LATER - -static char *make_relay_session_id(const char *username, const char *relay){ - /*ideally this should be a hash of the parameters with a random part*/ - char tmp[128]; - int s1=(int)random(); - int s2=(int)random(); - long long int res=((long long int)s1)<<32 | (long long int) s2; - void *src=&res; - b64_encode(src, sizeof(long long int), tmp, sizeof(tmp)); - return osip_strdup(tmp); -} - - -static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){ - - if (relay) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-addr"),osip_strdup(relay)); - if (relay_session_id) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-session-id"), osip_strdup(relay_session_id)); -} - -#endif - -static char * int_2char(int a){ - char *p=osip_malloc(16); - snprintf(p,16,"%i",a); - return p; -} - -/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ -static const char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field) -{ - int i,tmppt=0,scanned=0; - char *tmp; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1 || nb==2 ){ - if (pt==tmppt){ - tmp=attr->a_att_value+scanned; - if (strlen(tmp)>0) - return tmp; - } - }else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); - } - } - return NULL; -} - -#ifdef FOR_LATER -/* return the value of attr "field" */ -static const char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field) -{ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - return attr->a_att_value; - } - } - return NULL; -} -#endif - -static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ - int i,ret; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("ptime",attr->a_att_field)==0){ - int nb = sscanf(attr->a_att_value,"%i",&ret); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1){ - return ret; - }else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value); - } - } - return 0; -} - -static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("sendrecv",attr->a_att_field)==0){ - return SalStreamSendRecv; - }else if (keywordcmp("sendonly",attr->a_att_field)==0){ - return SalStreamSendOnly; - }else if (keywordcmp("recvonly",attr->a_att_field)==0){ - return SalStreamRecvOnly; - }else if (keywordcmp("inactive",attr->a_att_field)==0){ - return SalStreamInactive; - } - } - return SalStreamSendRecv; -} - -static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) -{ - sdp_message_t *local; - int inet6; - char sessid[16]; - char sessver[16]; - const char *rtp_addr = desc->addr; - - snprintf(sessid,16,"%i",desc->session_id); - snprintf(sessver,16,"%i",desc->session_ver); - sdp_message_init (&local); - if (strchr(desc->addr,':')!=NULL){ - inet6=1; - }else inet6=0; - sdp_message_v_version_set (local, osip_strdup ("0")); - sdp_message_o_origin_set (local, osip_strdup (desc->username), - osip_strdup (sessid), osip_strdup (sessver), - osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), - osip_strdup (desc->addr)); - sdp_message_s_name_set (local, osip_strdup ("Talk")); - /* Do not set the c= line to 0.0.0.0 if there is an ICE session. */ - if((desc->ice_ufrag[0] != '\0') || !sal_media_description_has_dir (desc,SalStreamSendOnly)) - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - else - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL); - } - sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ice_completed == TRUE) sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - - return local; -} - - -static bool_t is_known_rtpmap(const PayloadType *pt){ - switch(payload_type_get_number(pt)){ - case 0: - case 8: - case 3: - case 34: - return TRUE; - } - return FALSE; -} - -static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, bool_t strip_well_known_rtpmaps) -{ - char attr[256]; - sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt))); - - if (!strip_well_known_rtpmaps || !is_known_rtpmap(pt)){ - if (pt->channels>1) - snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate,pt->channels); - else - snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate); - sdp_message_a_attribute_add (msg, line, - osip_strdup ("rtpmap"), osip_strdup(attr)); - } - - if (pt->recv_fmtp != NULL) - { - snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp); - sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"), - osip_strdup(attr)); - } -} - -static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - const SalIceCandidate *candidate; - int nb; - int i; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { - candidate = &desc->ice_candidates[i]; - if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; - nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", - candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - if (candidate->raddr[0] != '\0') { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - } - sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); - } -} - -static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - char *ptr = buffer; - const SalIceRemoteCandidate *candidate; - int offset = 0; - int i; - - buffer[0] = '\0'; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { - candidate = &desc->ice_remote_candidates[i]; - if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { - offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); - if (offset < 0) { - ms_error("Cannot add ICE remote-candidates attribute!"); - return; - } - ptr += offset; - } - } - if (buffer[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); -} - -static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ - const char *mt=NULL; - const MSList *elem; - const char *rtp_addr; - const char *rtcp_addr; - const char *dir="sendrecv"; - int rtp_port; - int rtcp_port; - bool_t strip_well_known_rtpmaps; - bool_t different_rtp_and_rtcp_addr; - - switch (desc->type) { - case SalAudio: - mt="audio"; - break; - case SalVideo: - mt="video"; - break; - case SalOther: - mt=desc->typeother; - break; - } - rtp_addr=desc->rtp_addr; - rtcp_addr=desc->rtcp_addr; - rtp_port=desc->rtp_port; - rtcp_port=desc->rtcp_port; - - if (desc->proto == SalProtoRtpSavp) { - int i; - - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/SAVP")); - - /* add crypto lines */ - for(i=0; icrypto[i].algo) { - case AES_128_SHA1_80: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_80", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_SHA1_32: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_32", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_NO_AUTH: - ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); - break; - case NO_CIPHER_SHA1_80: - ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); - break; - default: - i = SAL_CRYPTO_ALGO_MAX; - } - } - - } else { - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/AVP")); - - } - - /*only add a c= line within the stream description if address are differents*/ - if (rtp_addr[0]!='\0' && strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ - bool_t inet6; - if (strchr(rtp_addr,':')!=NULL){ - inet6=TRUE; - }else inet6=FALSE; - sdp_message_c_connection_add (msg, lineno, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), - int_2char(desc->ptime)); - strip_well_known_rtpmaps=ms_list_size(desc->payloads)>5; - if (desc->payloads){ - for(elem=desc->payloads;elem!=NULL;elem=elem->next){ - add_payload(msg, lineno, (PayloadType*)elem->data,strip_well_known_rtpmaps); - } - }else{ - /* to comply with SDP we cannot have an empty payload type number list */ - /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ - sdp_message_m_payload_add (msg,lineno, int_2char (0)); - } - switch(desc->dir){ - case SalStreamSendRecv: - /*dir="sendrecv";*/ - dir=NULL; - break; - case SalStreamRecvOnly: - dir="recvonly"; - break; - case SalStreamSendOnly: - dir="sendonly"; - break; - case SalStreamInactive: - dir="inactive"; - break; - } - if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - if (rtp_port != 0) { - different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); - if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { - if (different_rtp_and_rtcp_addr == TRUE) { - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); - } else { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); - } - } - } - if (desc->ice_completed == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("nortpproxy"), osip_strdup("yes")); - } - if (desc->ice_mismatch == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); - } else { - if (desc->rtp_port != 0) { - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - add_ice_candidates(msg, lineno, desc); - add_ice_remote_candidates(msg, lineno, desc); - } - } -} - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ - int i; - sdp_message_t *msg=create_generic_sdp(desc); - for(i=0;in_total_streams;++i){ - add_line(msg,i,&desc->streams[i]); - } - return msg; -} - -static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ - if (rtpmap==NULL){ - PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt)); - if (refpt){ - pt->mime_type=ms_strdup(refpt->mime_type); - pt->clock_rate=refpt->clock_rate; - }else{ - ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.", - payload_type_get_number(pt)); - return -1; - } - }else{ - char *mime=ms_strdup(rtpmap); - char *p=strchr(mime,'/'); - if (p){ - char *chans; - *p='\0'; - p++; - chans=strchr(p,'/'); - if (chans){ - *chans='\0'; - chans++; - pt->channels=atoi(chans); - }else pt->channels=1; - pt->clock_rate=atoi(p); - } - pt->mime_type=mime; - } - return 0; -} - -int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ - int i,j; - const char *mtype,*proto,*rtp_port,*rtp_addr,*number; - const char *sess; - sdp_bandwidth_t *sbw=NULL; - sdp_attribute_t *attr; - int nb_ice_candidates; - - /* Get session information. */ - sess = sdp_message_o_sess_id_get(msg); - if (sess) desc->session_id = strtoul(sess, NULL, 10); - sess = sdp_message_o_sess_version_get(msg); - if (sess) desc->session_ver = strtoul(sess, NULL, 10); - - rtp_addr=sdp_message_c_addr_get (msg, -1, 0); - if (rtp_addr) - strncpy(desc->addr,rtp_addr,sizeof(desc->addr)); - for(j=0;(sbw=sdp_message_bandwidth_get(msg,-1,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth); - } - - /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ - for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { - if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_ufrag, attr->a_att_value, sizeof(desc->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_pwd, attr->a_att_value, sizeof(desc->ice_pwd)); - } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { - desc->ice_lite = TRUE; - } - } - - desc->n_active_streams = 0; - - /* for each m= line */ - for (i=0; !sdp_message_endof_media (msg, i) && istreams[i]; - nb_ice_candidates = 0; - - memset(stream,0,sizeof(*stream)); - mtype = sdp_message_m_media_get(msg, i); - proto = sdp_message_m_proto_get (msg, i); - rtp_port = sdp_message_m_port_get(msg, i); - stream->proto=SalProtoUnknown; - if (proto){ - if (strcasecmp(proto,"RTP/AVP")==0) - stream->proto=SalProtoRtpAvp; - else if (strcasecmp(proto,"RTP/SAVP")==0){ - stream->proto=SalProtoRtpSavp; - } - } - rtp_addr = sdp_message_c_addr_get (msg, i, 0); - if (rtp_addr != NULL) - strncpy(stream->rtp_addr,rtp_addr,sizeof(stream->rtp_addr)); - if (rtp_port) - stream->rtp_port=atoi(rtp_port); - if (stream->rtp_port > 0) - desc->n_active_streams++; - - stream->ptime=_sdp_message_get_a_ptime(msg,i); - if (strcasecmp("audio", mtype) == 0){ - stream->type=SalAudio; - }else if (strcasecmp("video", mtype) == 0){ - stream->type=SalVideo; - }else { - stream->type=SalOther; - strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1); - } - for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); - } - stream->dir=_sdp_message_get_mline_dir(msg,i); - /* for each payload type */ - for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ - const char *rtpmap,*fmtp; - int ptn=atoi(number); - PayloadType *pt=payload_type_new(); - payload_type_set_number(pt,ptn); - /* get the rtpmap associated to this codec, if any */ - rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); - if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){ - /* get the fmtp, if any */ - fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); - payload_type_set_send_fmtp(pt,fmtp); - stream->payloads=ms_list_append(stream->payloads,pt); - ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, - pt->send_fmtp ? pt->send_fmtp : ""); - } - } - - /* Get media specific RTCP attribute */ - stream->rtcp_port = stream->rtp_port + 1; - snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); - for (j = 0; ((attr = sdp_message_attribute_get(msg, i, j)) != NULL); j++) { - if ((keywordcmp("rtcp", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - char tmp[256]; - int nb = sscanf(attr->a_att_value, "%d IN IP4 %s", &stream->rtcp_port, tmp); - if (nb == 1) { - /* SDP rtcp attribute only contains the port */ - } else if (nb == 2) { - strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); - } else { - ms_warning("sdp has a strange a= line (%s) nb=%i", attr->a_att_value, nb); - } - } - } - - /* read crypto lines if any */ - if (stream->proto == SalProtoRtpSavp) { - int k, valid_count = 0; - - memset(&stream->crypto, 0, sizeof(stream->crypto)); - for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){ - char tmp[256], tmp2[256]; - if (keywordcmp("crypto",attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value, "%d %255s inline:%255s", - &stream->crypto[valid_count].tag, - tmp, - tmp2); - ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - tmp2); - if (nb == 3) { - if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_80") == 0) - stream->crypto[valid_count].algo = AES_128_SHA1_80; - else if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_32") == 0) - stream->crypto[valid_count].algo = AES_128_SHA1_32; - else { - ms_warning("Failed to parse crypto-algo: '%s'", tmp); - stream->crypto[valid_count].algo = 0; - } - if (stream->crypto[valid_count].algo) { - strncpy(stream->crypto[valid_count].master_key, tmp2, 41); - stream->crypto[valid_count].master_key[40] = '\0'; - ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - stream->crypto[valid_count].master_key); - valid_count++; - } - } else { - ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); - } - } - } - ms_message("Found: %d valid crypto lines", valid_count); - } - - /* Get ICE candidate attributes if any */ - for (j = 0; (attr = sdp_message_attribute_get(msg, i, j)) != NULL; j++) { - if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; - int nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", - candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, - candidate->type, candidate->raddr, &candidate->rport); - if ((nb == 6) || (nb == 8)) nb_ice_candidates++; - else memset(candidate, 0, sizeof(*candidate)); - } else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceRemoteCandidate candidate; - unsigned int componentID; - int offset; - char *ptr = attr->a_att_value; - while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { - if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { - SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; - strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); - remote_candidate->port = candidate.port; - } - ptr += offset; - if (ptr[offset] == ' ') ptr += 1; - } - } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_ufrag, attr->a_att_value, sizeof(stream->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_pwd, attr->a_att_value, sizeof(stream->ice_pwd)); - } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { - stream->ice_mismatch = TRUE; - } - } - } - desc->n_total_streams=i; - return 0; -} From 43671928eda1b88fae41adae5feae67b39c9c8b3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 15 Nov 2013 14:50:13 +0100 Subject: [PATCH 848/909] fix macos bundle generation to take into account things from /usr/local/lib and also only embed versionned dylib and .so ( because the .so link is transformed into a real file in the package) --- build/macos/linphone.bundle | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 6985bfb29..780b73e1c 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -15,7 +15,8 @@ /opt/local ${env:LINPHONE_INSTALL_PREFIX} ${env:MS2_PLUGINS_INSTALL_PREFIX} - /opt/local + + /usr/local + 100000 3600 @@ -15,13 +16,13 @@ center-on-parent dialog - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -91,7 +92,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 + 6 2 @@ -112,6 +113,8 @@ sip: False False + True + True 1 @@ -140,6 +143,9 @@ sip: False False + True + True + 1 @@ -148,19 +154,6 @@ 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Route (optional): - right - - - 2 - 3 - - True @@ -168,12 +161,14 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True 1 2 - 2 - 3 + 4 + 5 @@ -185,24 +180,26 @@ right - 3 - 4 + 2 + 3 True True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True adjustment1 1 2 - 3 - 4 + 2 + 3 @@ -210,12 +207,12 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Contact params: + Contact params (optional): right - 4 - 5 + 5 + 6 @@ -228,15 +225,53 @@ True False False + True + True 1 2 + 5 + 6 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Route (optional): + right + + 4 5 - + + + True + False + Transport + + + 3 + 4 + + + + + True + False + + + + 1 + 2 + 3 + 4 + + True diff --git a/include/sal/sal.h b/include/sal/sal.h index 99b04fba8..6374e2a08 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -85,12 +85,9 @@ const char *sal_address_get_display_name(const SalAddress* addr); const char *sal_address_get_display_name_unquoted(const SalAddress *addr); const char *sal_address_get_username(const SalAddress *addr); const char *sal_address_get_domain(const SalAddress *addr); -#ifdef USE_BELLESIP int sal_address_get_port(const SalAddress *addr); -#else -const char * sal_address_get_port(const SalAddress *addr); -int sal_address_get_port_int(const SalAddress *addr); -#endif +bool_t sal_address_is_secure(const SalAddress *addr); + SalTransport sal_address_get_transport(const SalAddress* addr); const char* sal_address_get_transport_name(const SalAddress* addr); @@ -479,6 +476,7 @@ void sal_signing_key_delete(SalSigningKey *key); void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure); int sal_unlisten_ports(Sal *ctx); +int sal_transport_available(Sal *ctx, SalTransport t); void sal_set_dscp(Sal *ctx, int dscp); int sal_reset_transports(Sal *ctx); ortp_socket_t sal_get_socket(Sal *ctx); diff --git a/tester/tester_hosts b/tester/tester_hosts index de1edc48c..b7056b863 100644 --- a/tester/tester_hosts +++ b/tester/tester_hosts @@ -1 +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 +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 From 8ffa2c38fee890450f05e9704fc02f4fb52ba066 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 1 Dec 2013 21:43:13 +0100 Subject: [PATCH 886/909] finish to implement multi transport in gtk app. fix malloc/free mismatch --- coreapi/bellesip_sal/sal_address_impl.c | 10 +++- gtk/propertybox.c | 63 +++++++++++++++++++++---- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 4d124e140..91c2d91c8 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -129,13 +129,19 @@ void sal_address_clean(SalAddress *addr){ } char *sal_address_as_string(const SalAddress *addr){ - return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)addr,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); } char *sal_address_as_string_uri_only(const SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)uri,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); } void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 638f9955c..a3bcc4145 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -652,6 +652,8 @@ static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType cho 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(); @@ -660,13 +662,15 @@ static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType cho gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"markup",0,NULL); } - 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)){ + 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,"TLS",-1); + 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); @@ -686,6 +690,31 @@ static void update_proxy_transport(GtkWidget *w){ } } +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))); } @@ -723,15 +752,33 @@ void linphone_gtk_proxy_cancel(GtkButton *button){ void linphone_gtk_proxy_ok(GtkButton *button){ GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); gboolean was_editing=TRUE; + if (!cfg){ was_editing=FALSE; cfg=linphone_proxy_config_new(); } linphone_proxy_config_set_identity(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")))); - linphone_proxy_config_set_server_addr(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")))); + if (linphone_proxy_config_set_server_addr(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))))==0){ + if (index!=-1){ + /*make sure transport was added to proxy address*/ + LinphoneTransportType tport=(LinphoneTransportType)index; + 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_set_contact_parameters(cfg, From 52226a4b993d9f48614d5f4cc5ec6dc8206fc283 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 1 Dec 2013 22:03:24 +0100 Subject: [PATCH 887/909] GTK app: enable TLS transport if tls is requested on a proxy config. --- coreapi/linphonecore.c | 4 ---- gtk/propertybox.c | 14 +++++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 33e7be9c3..9bafb93da 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2412,11 +2412,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA if (transport){ SalAddress *route=sal_address_new(NULL); sal_address_set_domain(route,sal_address_get_domain((SalAddress*)dest)); -#ifdef USE_BELLESIP sal_address_set_port(route,sal_address_get_port((SalAddress*)dest)); -#else - sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)dest)); -#endif sal_address_set_transport_name(route,transport); ret=ms_list_append(ret,route); } diff --git a/gtk/propertybox.c b/gtk/propertybox.c index a3bcc4145..c4dcd72ae 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -750,9 +750,11 @@ void linphone_gtk_proxy_cancel(GtkButton *button){ } void linphone_gtk_proxy_ok(GtkButton *button){ + LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); + LinphoneTransportType tport=(LinphoneTransportType)index; gboolean was_editing=TRUE; if (!cfg){ @@ -765,7 +767,6 @@ void linphone_gtk_proxy_ok(GtkButton *button){ gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))))==0){ if (index!=-1){ /*make sure transport was added to proxy address*/ - LinphoneTransportType tport=(LinphoneTransportType)index; LinphoneAddress *laddr=linphone_address_new(linphone_proxy_config_get_addr(cfg)); if (laddr){ if (linphone_address_get_transport(laddr)!=tport){ @@ -792,6 +793,17 @@ void linphone_gtk_proxy_ok(GtkButton *button){ linphone_proxy_config_enable_register(cfg, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); + + /* check if tls was asked but is not enabled in transport configuration*/ + if (tport==LinphoneTransportTls){ + LCSipTransports tports; + linphone_core_get_sip_transports(lc,&tports); + if (tports.tls_port==LC_SIP_TRANSPORT_DISABLED){ + tports.tls_port=LC_SIP_TRANSPORT_RANDOM; + } + linphone_core_set_sip_transports(lc,&tports); + } + if (was_editing){ if (linphone_proxy_config_done(cfg)==-1) return; From 7ee0e18910b91dabfab8a6fe1050b41374dffa52 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 1 Dec 2013 22:14:14 +0100 Subject: [PATCH 888/909] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 75514ad53..68d27760a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 75514ad53cdda45632d35a474a2810e78b19997e +Subproject commit 68d27760a3d84df7818de0015f5bc01d31bf06af From 19acd4a53a5fc325d3163b5396149739a928294e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 2 Dec 2013 15:53:04 +0100 Subject: [PATCH 889/909] align rootca path for android --- tester/liblinphone_tester.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 6be3bd70b..3c0fe9635 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -107,11 +107,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); sal_enable_test_features(lc->sal,TRUE); -#ifndef ANDROID snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cacert.pem", path); -#else - snprintf(rootcapath, sizeof(rootcapath), "%s/cacert.pem", path); -#endif linphone_core_set_root_ca(lc,rootcapath); sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); @@ -525,6 +521,7 @@ void cunit_android_trace_handler(int level, const char *fmt, va_list args) { jclass cls = (*env)->GetObjectClass(env, current_obj); jmethodID method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V"); (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString); + (*env)->DeleteLocalRef(env,javaString); } JNIEXPORT From 682c461550ac87007eb0dd302c09628540827c82 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 3 Dec 2013 11:26:09 +0100 Subject: [PATCH 890/909] make sure liblinphone_tester_run_tests return value is acurate --- tester/liblinphone_tester.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 465e4c925..f3e0c7280 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -331,7 +331,7 @@ void liblinphone_tester_uninit(void) { int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { int i; - + int ret; /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); @@ -366,8 +366,9 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) } } + ret=CU_get_number_of_tests_failed()!=0; CU_cleanup_registry(); - return CU_get_error(); + return ret; } #ifdef ANDROID From 308d7076bc606218e0ced1d8158793e0129f99bc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 10:50:09 +0100 Subject: [PATCH 891/909] Include patch from linphone web version. --- Makefile.am | 26 +++---- configure.ac | 12 +++- console/linphonec.c | 2 +- coreapi/Makefile.am | 15 ++++ gtk+-2.24.8.filelist | 155 +++++++++++++++++++++++++++++++++++++++++ gtk/Makefile.am | 2 +- linphone-deps.filelist | 2 + m4/ld-output-def.m4 | 29 ++++++++ mediastreamer2 | 2 +- oRTP | 2 +- 10 files changed, 230 insertions(+), 17 deletions(-) create mode 100644 gtk+-2.24.8.filelist create mode 100644 m4/ld-output-def.m4 diff --git a/Makefile.am b/Makefile.am index 02accc6ad..a5bdf24f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,7 +37,7 @@ SDK_EXCLUDED= \ GTK_PREFIX=/ GTK_THEME=Outcrop -GTK_FILELIST=gtk+-2.22.1.filelist +GTK_FILELIST=gtk+-2.24.8.filelist GTK_FILELIST_PATH=$(abs_top_srcdir)/$(GTK_FILELIST) LINPHONEDEPS_FILELIST=linphone-deps.filelist WINBINDIST_FILES=`cat $(abs_top_srcdir)/$(LINPHONEDEPS_FILELIST)` @@ -101,31 +101,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) diff --git a/configure.ac b/configure.ac index b1a4df656..d48a32dc5 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to LIBLINPHONE_SO_VERSION=$LIBLINPHONE_SO_CURRENT:$LIBLINPHONE_SO_REVISION:$LIBLINPHONE_SO_AGE +AC_SUBST(LIBLINPHONE_SO_CURRENT, $LIBLINPHONE_SO_CURRENT) AC_SUBST(LIBLINPHONE_SO_VERSION, $LIBLINPHONE_SO_VERSION) AC_SUBST(LINPHONE_VERSION) @@ -36,6 +37,8 @@ AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) +gl_LD_OUTPUT_DEF + AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) @@ -61,6 +64,7 @@ case $target in GUI_FLAGS="-mwindows" CONSOLE_FLAGS="-mconsole" mingw_found=yes + AC_CHECK_TOOL(WINDRES, windres) ;; armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " @@ -145,7 +149,7 @@ else 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) @@ -803,6 +807,12 @@ else ],[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 diff --git a/console/linphonec.c b/console/linphonec.c index a453e374b..4385dbb09 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -1075,7 +1075,7 @@ linphonec_initialize_readline() rl_attempted_completion_function = linephonec_readline_completion; /* printf("Readline initialized.\n"); */ - setlinebuf(stdout); + setlinebuf(stdout); return 0; } diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b6ed2ec32..ec0250fa8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -82,6 +82,21 @@ endif liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined +if HAVE_LD_OUTPUT_DEF +liblinphone_la_LDFLAGS += -Wl,--output-def,liblinphone-$(LIBLINPHONE_SO_CURRENT).def +defexecdir = $(libdir) +defexec_DATA = liblinphone-$(LIBLINPHONE_SO_CURRENT).def +CLEANFILES = $(defexec_DATA) + +liblinphone-$(LIBLINPHONE_SO_CURRENT).def: liblinphone.la + +if BUILD_WIN32 +defexec_DATA += liblinphone-$(LIBLINPHONE_SO_CURRENT).lib +liblinphone-$(LIBLINPHONE_SO_CURRENT).lib: liblinphone-$(LIBLINPHONE_SO_CURRENT).def liblinphone.la + $(DLLTOOL) --dllname liblinphone-$(LIBLINPHONE_SO_CURRENT).dll --input-def liblinphone-$(LIBLINPHONE_SO_CURRENT).def --output-lib $@ liblinphone.la +endif +endif + liblinphone_la_LIBADD= \ $(SIPSTACK_LIBS) \ $(MEDIASTREAMER_LIBS) \ diff --git a/gtk+-2.24.8.filelist b/gtk+-2.24.8.filelist new file mode 100644 index 000000000..4779780b1 --- /dev/null +++ b/gtk+-2.24.8.filelist @@ -0,0 +1,155 @@ +bin +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/libffi-5.dll +bin/libfontconfig-1.dll +bin/libfreetype-6.dll +bin/libintl-8.dll +bin/libgailutil-18.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/libiconv-2.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/libpixman-1-0.dll +bin/libpng15-15.dll +bin/libxml2-2.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/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/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/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/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/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/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/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/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/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/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/themes +share/themes/Default +share/themes/Default/gtk-2.0-key +share/themes/Default/gtk-2.0-key/gtkrc +share/themes/Emacs +share/themes/Emacs/gtk-2.0-key +share/themes/Emacs/gtk-2.0-key/gtkrc +share/themes/MS-Windows +share/themes/MS-Windows/gtk-2.0 +share/themes/MS-Windows/gtk-2.0/gtkrc +share/themes/Raleigh +share/themes/Raleigh/gtk-2.0 +share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk/Makefile.am b/gtk/Makefile.am index ba965b69a..b80527de0 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -61,7 +61,7 @@ linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \ if BUILD_WIN32 linphone.res: $(LINPHONE_ICO_RC_FILE) $(LINPHONE_ICO_FILE) - windres $(srcdir)/$(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res + $(WINDRES) $(srcdir)/$(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res linphone_LDADD+=linphone.res -lwininet linphone_LDFLAGS=-Wl,--export-all-symbols -mwindows diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 79731801d..53bab22af 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -1,4 +1,6 @@ ./bin/avcodec-53.dll +./bin/libspeex-1.dll +./bin/libspeexdsp-1.dll ./bin/avutil-51.dll ./bin/libeay32.dll ./bin/ssleay32.dll diff --git a/m4/ld-output-def.m4 b/m4/ld-output-def.m4 new file mode 100644 index 000000000..2dc6bf520 --- /dev/null +++ b/m4/ld-output-def.m4 @@ -0,0 +1,29 @@ +# ld-output-def.m4 serial 2 +dnl Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Simon Josefsson + +# gl_LD_OUTPUT_DEF() +# ------------- +# Check if linker supports -Wl,--output-def and define automake +# conditional HAVE_LD_OUTPUT_DEF if it is. +AC_DEFUN([gl_LD_OUTPUT_DEF], +[ + AC_CACHE_CHECK([if gcc/ld supports -Wl,--output-def], + [gl_cv_ld_output_def], + [if test "$enable_shared" = no; then + gl_cv_ld_output_def="not needed, shared libraries are disabled" + else + gl_ldflags_save=$LDFLAGS + LDFLAGS="-Wl,--output-def,conftest.def" + AC_LINK_IFELSE([AC_LANG_PROGRAM([])], + [gl_cv_ld_output_def=yes], + [gl_cv_ld_output_def=no]) + rm -f conftest.def + LDFLAGS="$gl_ldflags_save" + fi]) + AM_CONDITIONAL([HAVE_LD_OUTPUT_DEF], test "x$gl_cv_ld_output_def" = "xyes") +]) diff --git a/mediastreamer2 b/mediastreamer2 index 8deb23a1b..57cc62904 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8deb23a1b03e343b753d2e896347453ada72e4df +Subproject commit 57cc62904c856c6822a9b3fb83133f80abd81cf6 diff --git a/oRTP b/oRTP index b5d1414e6..509516fb4 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b5d1414e63b21c83eb8e26988a3fe423ff8fc3b3 +Subproject commit 509516fb447d8355496ae3850777aa214f60e048 From 8eeeabbb21f77e609518baab271044077403446d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 14:29:27 +0100 Subject: [PATCH 892/909] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 57cc62904..9e7ea53dc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 57cc62904c856c6822a9b3fb83133f80abd81cf6 +Subproject commit 9e7ea53dca1ae7447d320b37b14dd4d58e0f67fe diff --git a/oRTP b/oRTP index 509516fb4..bb43f9fcd 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 509516fb447d8355496ae3850777aa214f60e048 +Subproject commit bb43f9fcd2325bdf44e9a244cc4502b7d5de71d9 From ae2b1a0f751f69c344f672010fa4feca1f5c4781 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 15:44:44 +0100 Subject: [PATCH 893/909] Remove -fpermissive option as clang is used now on Mac OS X platforms. --- tools/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/Makefile.am b/tools/Makefile.am index 5ef2535ad..c0b064953 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -11,8 +11,7 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) -#-fpermissive to workaround a g++ bug on macos 32bit SDK. -AM_CXXFLAGS=$(LIBXML2_CFLAGS) -fpermissive $(STRICT_OPTIONS) +AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc From 61c1e587ab74c7b3bc5b275596032c3331c2f8e2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 09:02:29 +0100 Subject: [PATCH 894/909] improve test reliability for rctp --- coreapi/linphonecall.c | 3 ++- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 8 ++++++-- tester/images/nowebcamCIF.jpg | Bin 0 -> 14247 bytes tester/liblinphone_tester.c | 7 +++++-- tester/sounds/hello8000.wav | Bin 0 -> 180268 bytes tester/sounds/oldphone.wav | Bin 0 -> 312300 bytes tester/sounds/ringback.wav | Bin 0 -> 24620 bytes 9 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 tester/images/nowebcamCIF.jpg create mode 100644 tester/sounds/hello8000.wav create mode 100644 tester/sounds/oldphone.wav create mode 100644 tester/sounds/ringback.wav diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a952865ab..59ad78c19 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2282,7 +2282,8 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (media_stream_get_up_bw(as)*1e-3) : 0; call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (media_stream_get_down_bw(vs)*1e-3) : 0; call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (media_stream_get_up_bw(vs)*1e-3) : 0; - ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", + ms_message("bandwidth usage for call [%p]: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", + call, call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth, call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth , call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth, diff --git a/mediastreamer2 b/mediastreamer2 index 9e7ea53dc..d90b00711 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9e7ea53dca1ae7447d320b37b14dd4d58e0f67fe +Subproject commit d90b00711f794814fe670c846ca162704df883c7 diff --git a/oRTP b/oRTP index bb43f9fcd..fcc51caa1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit bb43f9fcd2325bdf44e9a244cc4502b7d5de71d9 +Subproject commit fcc51caa15def815189a388e878877a5354850e6 diff --git a/tester/call_tester.c b/tester/call_tester.c index 8e5c952f7..ab8c5f8c0 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -103,7 +103,7 @@ static void check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); - for (i=0; i<12 /*=6s*/; i++) { + for (i=0; i<24 /*=12s need at least one exchange of SR to maybe 10s*/; i++) { if (linphone_call_get_audio_stats(c1)->round_trip_delay >0.0 && linphone_call_get_audio_stats(c2)->round_trip_delay >0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c1)) || linphone_call_get_video_stats(c1)->round_trip_delay>0.0) @@ -133,7 +133,11 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr stats initial_caller=caller_mgr->stat; stats initial_callee=callee_mgr->stat; bool_t result=FALSE; - + char hellopath[256]; + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (callee_mgr->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(callee_mgr->lc,hellopath); if (!caller_params){ CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); }else{ diff --git a/tester/images/nowebcamCIF.jpg b/tester/images/nowebcamCIF.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ab8bdc2ace897259946d67357523a6c9796cd3a GIT binary patch literal 14247 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, dnsuserhostspath); - sprintf(ringpath, "%s/%s", path, "oldphone.wav"); - sprintf(ringbackpath, "%s/%s", path, "ringback.wav"); + snprintf(ringpath,sizeof(ringpath), "%s/sounds/oldphone.wav",path); + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/ringback.wav", path); linphone_core_set_ring(lc, ringpath); linphone_core_set_ringback(lc, ringbackpath); + snprintf(nowebcampath, sizeof(nowebcampath), "%s/images/nowebcamCIF.jpg", path); + linphone_core_set_static_picture(lc,nowebcampath); return lc; } diff --git a/tester/sounds/hello8000.wav b/tester/sounds/hello8000.wav new file mode 100644 index 0000000000000000000000000000000000000000..b787b202eef3cad48a4635a2006dd65f3f137383 GIT binary patch literal 180268 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%0D3RI3!Nk#}GqF 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

hSTNb?Yi~Gy^op3Enq+6$7mk?k3g9@>li;*-K?Q zrdBqc^smzIWhh2oYp-$BtY>fa?ACkwa|YJvcb#SCut;m;JF5*f_9N`f*kl_l+j;Ei zrTpf?iD#UFL8F|}+L#jA7`m3xHls`MM!1@Jka>E?9_|#OUwxN8&DWJ)n2Uim@dGoZ zW{%JPT8_-g6}(^CR&Z*@q2O2}yPe;hVW{R$R;pWC|HxO#d%)AzE^5{`&RY}R8~BiA zoq1Mw>ks>or>;8DZDMtcsG)_S?vVoEhW-%ohZ?^}_T5Ig@ z7Iz%>qLPVgGhNIa%JxC_DoK@m_1#I~ry1))?agOcQ^(-;i=&VHg?i4r&bvkPD&y&! z|J;uEJX4a?u;-3b4lC*-cLL}l-#h=A)g$ME(?V+_$BZL}5t$z<8|)IS7oKju>*k_M z^ftJW^VFK&Zh;yJy)&&y%APzR^VBTi%()Zx`Fg2q%_8C5;oeB|P2(z3(bY)vm0A|&Hj;|;f9f|ks^^Jk(QB`;dbGv zk$;VmcDlPuxv1^~TV$BGvwusRl2|HfS#qnCx>+71?Fmfq7E+g54UC>he2=O1c&Z_&}txtAQN%*ytIq z7#VGBq8nPL2DhgB4ZJ=s-hUm|lR2K-SmzH|D|be*Uh26`oGn&c>s#jbXOXv!EAWEl zHHsRoB2ywOj5+4}_E+vy<)E5MFaMX`g}%Ij-{O`gOwKed`RmMaNqOVm^(AXX=)b9K zwJ>jliy^!3M}7=XG}nMCam&3$FJ5z2#(}I)>sc{MD^JOSwsvo0od)f4U&{YHd8YTm^hh{nG=D;(H}7PfAT5oK!9Tfp3>q z#N7c_%p|jYjGx)5n$&9|$%-&3z!SP>?=iFnGNfKyXc+2h&k{tebnNoNpP z4~I>~92!{;7V7LszsRS?5+m7IY3wlfffPK*^M*Q0Tdp_o-lE$4iN8Qxo`g}EdL@6C zyfN{gzzXjsWuU!-K9;S94vJ{8$kNc7P%~p5HRm%u3#rZh1JAHG|G1V;j0;ooFnrCcHpB@~_c?XU0AlMWGi)*M&f4*mo8n0i_ z7wR8?J~zVmb|5`|VbcDTU$W%PJSm~L|B<@d830qzRr8I=f59&^B58BdDx17we zi!5iSI!`^ns(ZATpj`i;b@dhvv`VOxJUr{J>_f6%&$Kp>RnO%f#yYBJ4hlETn4UKG z)sa_AGd3EQJ58&=DtgDa)3?vpK5#PbYM_YkHEpQd)w~-1KHMPEFw!=3H~nJTH)*-k zn}pVyH^43f&ChOQCQ_UKqhov8f{OJz=yM0PmA*sqX-Q?WrswFHvwN073Hf}zmHXBn z_?0Gy|4IKQb>+)oYL<-uB193rTlmkv{i_1k1N-8h#y^fL>1zyH!GDo^up4y`H;yz2 z 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 literal 0 HcmV?d00001 From f1fd223cf39bc94597bfcc56f512ba077aa2e90c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 12:39:36 +0100 Subject: [PATCH 895/909] fix call tester to use file instead of capture card for callee --- tester/call_tester.c | 53 ++++++++------------------------------------ 1 file changed, 9 insertions(+), 44 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index ab8c5f8c0..e09a20e81 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -213,50 +213,8 @@ static void simple_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCore* lc_marie=marie->lc; - LinphoneCore* lc_pauline=pauline->lc; - stats* stat_marie=&marie->stat; - stats* stat_pauline=&pauline->stat; - LinphoneProxyConfig* proxy; - LinphoneAddress* identity; - - - linphone_core_invite(lc_marie,"pauline"); - - CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); - - linphone_core_get_default_proxy(lc_marie,&proxy); - CU_ASSERT_PTR_NOT_NULL (proxy); - identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(lc_pauline)); - if (linphone_core_get_current_call_remote_address(lc_pauline)) { - CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); - linphone_address_destroy(identity); - - linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); - /*just to sleep*/ - wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); - - check_rtcp(marie,pauline); - - linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); - } - linphone_core_destroy(marie->lc); - marie->lc=NULL; - CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallReleased,1); - linphone_core_destroy(pauline->lc); - pauline->lc=NULL; - CU_ASSERT_EQUAL(stat_pauline->number_of_LinphoneCallReleased,1); + CU_ASSERT_TRUE(call(pauline,marie)); + check_rtcp(marie,pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -1076,6 +1034,7 @@ static void early_media_call_forking(void) { LinphoneCall *marie2_call; LinphoneCall *pauline_call; int dummy=0; + char hellopath[256]; pol.automatically_accept=1; pol.automatically_initiate=1; @@ -1088,6 +1047,12 @@ static void early_media_call_forking(void) { linphone_core_enable_video(marie1->lc,TRUE,TRUE); linphone_core_set_video_policy(marie1->lc,&pol); + + /*use playfile for marie1 to avoid locking on capture card*/ + linphone_core_use_files (marie1->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(marie1->lc,hellopath); + linphone_core_enable_video(marie2->lc,TRUE,TRUE); linphone_core_set_video_policy(marie2->lc,&pol); From 265650e7b75d885cfe4aa8cc4f99ce427a023b81 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Dec 2013 12:47:45 +0100 Subject: [PATCH 896/909] Revert "Remove -fpermissive option as clang is used now on Mac OS X platforms." This reverts commit ae2b1a0f751f69c344f672010fa4feca1f5c4781. --- tools/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/Makefile.am b/tools/Makefile.am index c0b064953..5ef2535ad 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -11,7 +11,8 @@ COMMON_CFLAGS=\ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) -AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) +#-fpermissive to workaround a g++ bug on macos 32bit SDK. +AM_CXXFLAGS=$(LIBXML2_CFLAGS) -fpermissive $(STRICT_OPTIONS) EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc From 6f598c840ee27e98228eb38886398d44b303eeeb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 14:07:06 +0100 Subject: [PATCH 897/909] fix early media call forking to avoid capture card sharing between parties --- tester/call_tester.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index e09a20e81..58c72ad20 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1034,7 +1034,8 @@ static void early_media_call_forking(void) { LinphoneCall *marie2_call; LinphoneCall *pauline_call; int dummy=0; - char hellopath[256]; + char ringbackpath[256]; + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); pol.automatically_accept=1; pol.automatically_initiate=1; @@ -1047,17 +1048,18 @@ static void early_media_call_forking(void) { linphone_core_enable_video(marie1->lc,TRUE,TRUE); linphone_core_set_video_policy(marie1->lc,&pol); - /*use playfile for marie1 to avoid locking on capture card*/ linphone_core_use_files (marie1->lc,TRUE); - snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); - linphone_core_set_play_file(marie1->lc,hellopath); + linphone_core_set_play_file(marie1->lc,ringbackpath); linphone_core_enable_video(marie2->lc,TRUE,TRUE); linphone_core_set_video_policy(marie2->lc,&pol); linphone_core_set_audio_port_range(marie2->lc,40200,40300); linphone_core_set_video_port_range(marie2->lc,40400,40500); + /*use playfile for marie2 to avoid locking on capture card*/ + linphone_core_use_files (marie2->lc,TRUE); + linphone_core_set_play_file(marie2->lc,ringbackpath); lcs=ms_list_append(lcs,marie1->lc); From d8bd9caceb8deadefbf07fc06ba2e09eeb140bf4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 22:04:33 +0100 Subject: [PATCH 898/909] fix clang detection, MS2:fix upnp version detection with clang --- .cproject | 3 ++- configure.ac | 8 ++++---- mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.cproject b/.cproject index 51c77f8e9..8a879f8a7 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + @@ -35,6 +35,7 @@ + diff --git a/configure.ac b/configure.ac index d48a32dc5..5c6700d5f 100644 --- a/configure.ac +++ b/configure.ac @@ -36,12 +36,12 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) - -gl_LD_OUTPUT_DEF - +dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) +gl_LD_OUTPUT_DEF + AC_ISC_POSIX AC_C_INLINE AC_HEADER_STDC @@ -67,7 +67,7 @@ case $target in AC_CHECK_TOOL(WINDRES, windres) ;; armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) - CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " + CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 " ios_found=yes ;; x86_64-apple-darwin*|i686-apple-darwin*) diff --git a/mediastreamer2 b/mediastreamer2 index d90b00711..69a7cce94 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d90b00711f794814fe670c846ca162704df883c7 +Subproject commit 69a7cce94756f9e5af3fae9fbd941817c4731f49 From e67a8737dded8c49e46a929aaa018d5913d76764 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Dec 2013 14:52:57 +0100 Subject: [PATCH 899/909] Add configuration to enable/disable DNS SRV resolution. --- coreapi/bellesip_sal/sal_impl.c | 6 ++++++ coreapi/linphonecore.c | 12 ++++++++++++ coreapi/linphonecore.h | 16 ++++++++++++++++ include/sal/sal.h | 2 ++ 4 files changed, 36 insertions(+) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index abff14e99..7f55d453c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -704,6 +704,12 @@ void sal_set_dns_timeout(Sal* sal,int timeout) { int sal_get_dns_timeout(const Sal* sal) { return belle_sip_stack_get_dns_timeout(sal->stack); } +void sal_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); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9bafb93da..a2f1def5c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -499,6 +499,8 @@ static void net_config_read (LinphoneCore *lc) /*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)); @@ -1069,6 +1071,16 @@ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw); } +void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) { + sal_enable_dns_srv(lc->sal, enable); + if (linphone_core_ready(lc)) + lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0); +} + +bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) { + return sal_dns_srv_enabled(lc->sal); +} + /** * Retrieve the maximum available download bandwidth. * This value was set by linphone_core_set_download_bandwidth(). diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 317f01875..b9c9a5030 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1364,6 +1364,22 @@ LINPHONE_PUBLIC void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime) LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *lc); +/** + * Enable or disable DNS SRV resolution. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable DNS SRV resolution, FALSE to disable it. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether DNS SRV resolution is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if DNS SRV resolution is enabled, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc); + /* returns a MSList of PayloadType */ LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); diff --git a/include/sal/sal.h b/include/sal/sal.h index 6374e2a08..655613661 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -685,6 +685,8 @@ bool_t sal_nat_helper_enabled(Sal *sal); LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); LINPHONE_PUBLIC int sal_get_dns_timeout(const Sal* sal); +LINPHONE_PUBLIC void sal_enable_dns_srv(Sal *sal, bool_t enable); +LINPHONE_PUBLIC bool_t sal_dns_srv_enabled(const Sal *sal); LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); From eb70e7067b81a0f895714daabdee80dc1eee7ed2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 5 Dec 2013 16:47:36 +0100 Subject: [PATCH 900/909] add make test target --- po/POTFILES.skip | 1 + tester/Makefile.am | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/po/POTFILES.skip b/po/POTFILES.skip index e254f124a..6b9ad1b55 100755 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -47,3 +47,4 @@ mediastreamer2/src/videofilters/winvideods.c mediastreamer2/src/videofilters/winvideo2.c mediastreamer2/src/videofilters/x11video.c mediastreamer2/src/voip/ice.c +build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs diff --git a/tester/Makefile.am b/tester/Makefile.am index b501f15fb..e81c85d97 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,10 +1,10 @@ -EXTRA_DIST=pauline_rc laure_rc marie_rc marie_no_sdp_rc +EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ + pauline_rc pauline_wild_rc tester_hosts sounds images certificates if BUILD_CUNIT_TESTS noinst_PROGRAMS=liblinphone_tester -TESTS=$(noinst_PROGRAMS) liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ setup_tester.c \ @@ -29,4 +29,12 @@ AM_LDFLAGS=$(CUNIT_LIBS) AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) +test: liblinphone_tester + ./liblinphone_tester --config $(abs_srcdir) + +else + +test: + @echo "CUnit must be installed to be able to run the tests!" + endif From 5ea937f787bf15c8166bffa3b0bdd6730c21ecc3 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 5 Dec 2013 18:00:33 +0100 Subject: [PATCH 901/909] Fix compilation issue in console.c for Mac --- console/commands.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/console/commands.c b/console/commands.c index c4e70ba02..ba2f1dc3c 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2109,7 +2109,13 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){ memset(voice,0,sizeof(voice)); sscanf(args,"%63s",voice); sentence=args+strlen(voice); + +#ifdef __APPLE__ + wavfile=mktemp("/tmp/linphonec-espeak-XXXXXX"); +#else wavfile=tempnam("/tmp/","linphonec-espeak-"); +#endif + snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile); file=popen(cl,"w"); if (file==NULL){ From 2fa2ab9056e98f0664fce05f88590015231a2571 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 6 Dec 2013 10:21:57 +0100 Subject: [PATCH 902/909] update ms2 (bugfix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 69a7cce94..11eb5f602 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 69a7cce94756f9e5af3fae9fbd941817c4731f49 +Subproject commit 11eb5f6021a145a8b2f0a65ba409814acfda0f01 From ead96f8ecbcaf2f2c7845dc588aa910dec156d94 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 6 Dec 2013 13:46:32 +0100 Subject: [PATCH 903/909] give more time to tester for being registered --- tester/liblinphone_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 24a4c5350..1df32f237 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -205,7 +205,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f else proxy_count=0; - while (mgr->stat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { + while (mgr->stat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { linphone_core_iterate(mgr->lc); ms_usleep(100000); } From 2058b0cd210fad744e2f8f7789a7738f264575aa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 6 Dec 2013 18:22:03 +0100 Subject: [PATCH 904/909] update ms2 (android bugfix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 11eb5f602..6920f363d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 11eb5f6021a145a8b2f0a65ba409814acfda0f01 +Subproject commit 6920f363d8f6db7c98f6dc471a045f43e4f26200 From a610adecf47d9c2d0719d8d4bee8e0777ae71e58 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 12:19:13 +0100 Subject: [PATCH 905/909] add supported header --- coreapi/bellesip_sal/sal_impl.c | 1 + coreapi/bellesip_sal/sal_impl.h | 2 ++ coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 23 ++++++++++++++--------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7f55d453c..37384f3e9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -857,6 +857,7 @@ int sal_create_uuid(Sal*ctx, char *uuid, size_t len){ belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_request_t* req, int code ) { belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code); belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),sal_make_supported_header(sal)); return resp; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 371153ea5..4ae34095b 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -157,4 +157,6 @@ bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody); SalReason sal_reason_to_sip_code(SalReason r); +belle_sip_header_t * sal_make_supported_header(Sal *sal); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index b434a1c38..a286001b2 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -647,7 +647,7 @@ int sal_call_accept(SalOp*h){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow())); if (h->base.root->session_expires!=0){ if (h->supports_session_timers) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 4c6a1091a..49fa7c5f8 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -111,6 +111,10 @@ belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ return contact_header; } +belle_sip_header_t * sal_make_supported_header(Sal *sal){ + return belle_sip_header_create("Supported","replaces, outbound"); +} + belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_from_t* from_header; belle_sip_header_to_t* to_header; @@ -133,16 +137,16 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); req=belle_sip_request_create( - req_uri, - method, - belle_sip_provider_create_call_id(prov), - belle_sip_header_cseq_create(20,method), - from_header, - to_header, - belle_sip_header_via_new(), - 70); + 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) { + 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)); } @@ -162,6 +166,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header)); } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),sal_make_supported_header(op->base.root)); return req; } From 21447a20b2bea6242c45daaa780b0a829ec8767c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 12:26:49 +0100 Subject: [PATCH 906/909] add privacy api in java. --- coreapi/linphonecore_jni.cc | 22 +++++++++++++++++++ .../org/linphone/core/LinphoneCallParams.java | 12 ++++++++++ .../linphone/core/LinphoneProxyConfig.java | 13 +++++++++++ .../linphone/core/LinphoneCallParamsImpl.java | 12 ++++++++++ .../core/LinphoneProxyConfigImpl.java | 11 ++++++++++ 5 files changed, 70 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index fa583f144..65438fc19 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2568,6 +2568,20 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption linphone_call_params_set_media_encryption((LinphoneCallParams*)cp,(LinphoneMediaEncryption)jmenc); } +extern "C" jint Java_org_linphone_core_LinphoneCallParamsImpl_getPrivacy(JNIEnv* env + ,jobject thiz + ,jlong cp + ) { + return (jint)linphone_call_params_get_privacy((LinphoneCallParams*)cp); +} + +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setPrivacy(JNIEnv* env + ,jobject thiz + ,jlong cp + ,jint privacy) { + linphone_call_params_set_privacy((LinphoneCallParams*)cp,privacy); +} + extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_audioBandwidth(JNIEnv *env, jobject thiz, jlong lcp, jint bw){ linphone_call_params_set_audio_bandwidth_limit((LinphoneCallParams*)lcp, bw); } @@ -2719,6 +2733,14 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getExpires(JNIEnv return linphone_proxy_config_get_expires((LinphoneProxyConfig *) ptr); } +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setPrivacy(JNIEnv* env,jobject thiz,jlong ptr,jint privacy) { + linphone_proxy_config_set_privacy((LinphoneProxyConfig *) ptr, (int) privacy); +} + +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPrivacy(JNIEnv* env,jobject thiz,jlong ptr) { + return linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr); +} + extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { return (jint)linphone_call_get_duration((LinphoneCall *) ptr); } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index b6d5ef33d..530cf63b9 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -93,4 +93,16 @@ public interface LinphoneCallParams { * @return value for the header, or null if it doesn't exist. */ String getCustomHeader(String name); + + /** + * Set the privacy for the call. + * @param privacy_mask a or'd int of values defined in interface {@link org.linphone.core.Privacy} + */ + void setPrivacy(int privacy_mask); + + /** + * Get the privacy mask requested for this call. + * @return the privacy mask as defined in interface {@link org.linphone.core.Privacy} + */ + int getPrivacy(); } diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index f06df31b9..8a5da47a8 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -152,6 +152,19 @@ public interface LinphoneProxyConfig { */ int getExpires(); + /** + * Set the privacy for all calls or chat sessions using the identity exposed by this LinphoneProxyConfig + * @param privacy_mask a or'd int of values defined in interface {@link org.linphone.core.Privacy} + */ + void setPrivacy(int privacy_mask); + + /** + * Get the privacy mask requested for this proxy config. + * @return the privacy mask as defined in interface {@link org.linphone.core.Privacy} + */ + int getPrivacy(); + + /** * Sets parameters for the contact * @param parameters to add diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index 83cc95f54..aaafe9186 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -106,5 +106,17 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public String getCustomHeader(String name) { return getCustomHeader(nativePtr,name); } + + private native void setPrivacy(long nativePtr, int mask); + @Override + public void setPrivacy(int privacy_mask) { + setPrivacy(nativePtr,privacy_mask); + } + + private native int getPrivacy(long nativePtr); + @Override + public int getPrivacy() { + return getPrivacy(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index b2e019cb4..dfa9c5170 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -176,4 +176,15 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public Reason getError() { return Reason.fromInt(getReason(nativePtr)); } + private native void setPrivacy(long nativePtr, int mask); + @Override + public void setPrivacy(int privacy_mask) { + setPrivacy(nativePtr,privacy_mask); + } + + private native int getPrivacy(long nativePtr); + @Override + public int getPrivacy() { + return getPrivacy(nativePtr); + } } From b9f614744fcb1dfa6628f6a0b8f45b6406522bd8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 13:19:46 +0100 Subject: [PATCH 907/909] fix crash in gtk app when updating sip ports call linphone_call_fix_parameters() when INVITEs and reINVITEs, but not during early-media --- coreapi/callbacks.c | 8 ++++++-- coreapi/linphonecall.c | 3 --- coreapi/linphonecore.c | 4 +++- coreapi/private.h | 2 +- gtk/propertybox.c | 4 +++- tester/call_tester.c | 1 + 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4c931cc33..da674aac6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -391,7 +391,10 @@ static void call_accepted(SalOp *op){ } } } - linphone_core_update_streams (lc,call,md); + linphone_core_update_streams(lc,call,md); + /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again + * further in the call, for example during pause,resume, conferencing reINVITEs*/ + linphone_call_fix_call_parameters(call); if (!call->current_params.in_conference) lc->current_call=call; linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running"); @@ -440,8 +443,9 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ linphone_call_update_remote_session_id_and_ver(call); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) + if (md && !sal_media_description_empty(md)){ linphone_core_update_streams(lc,call,md); + } } static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 59ad78c19..908157e48 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1909,9 +1909,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } - /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again - * further in the call, for example during pause,resume, conferencing reINVITEs*/ - linphone_call_fix_call_parameters(call); if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { ice_session_start_connectivity_checks(call->ice_session); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a2f1def5c..e36410d09 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3087,8 +3087,10 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) + if (md && !sal_media_description_empty(md)){ linphone_core_update_streams (lc,call,md); + linphone_call_fix_call_parameters(call); + } linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index e4ddd59c0..37ff460ae 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -341,7 +341,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag void linphone_core_play_tone(LinphoneCore *lc); void linphone_call_init_stats(LinphoneCallStats *stats, int type); - +void linphone_call_fix_call_parameters(LinphoneCall *call); void linphone_call_init_audio_stream(LinphoneCall *call); void linphone_call_init_video_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index c4dcd72ae..dd6424dac 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1132,15 +1132,17 @@ static void port_config_free(PortConfigCtx *ctx){ g_free(ctx); } -static void apply_transports(PortConfigCtx *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; + g_message("new transports: %i, %i, %i",(int)tp.udp_port,(int)tp.tcp_port,(int)tp.tls_port); linphone_core_set_sip_transports(lc,&tp); g_object_set_data(G_OBJECT(mw),"port_config",NULL); + return FALSE; } static void transport_changed(GtkWidget *parameters){ diff --git a/tester/call_tester.c b/tester/call_tester.c index 58c72ad20..b166cb86e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -885,6 +885,7 @@ static void simple_conference(void) { marie_call_laure=linphone_core_get_current_call(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure); linphone_core_add_to_conference(marie->lc,marie_call_laure); CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); From 55af0b6aa58ed9b9a78c97f0a2667fa2a64b6df7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 14:01:02 +0100 Subject: [PATCH 908/909] fix transport selection for outgoing messages when the proxy config selected has sips. --- coreapi/linphonecore.c | 16 +++++----------- gtk/propertybox.c | 1 - 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e36410d09..5698d2272 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2417,18 +2417,12 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA ret=ms_list_append(ret,sal_address_clone((SalAddress*)srv_route)); } if (ret==NULL){ - /*still no route, so try to build a route from proxy transport + identity host, - *in order to force using the transport required for this proxy, if any.*/ + /*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)); - const char *transport=sal_address_get_transport_name(proxy_addr); - if (transport){ - SalAddress *route=sal_address_new(NULL); - sal_address_set_domain(route,sal_address_get_domain((SalAddress*)dest)); - sal_address_set_port(route,sal_address_get_port((SalAddress*)dest)); - sal_address_set_transport_name(route,transport); - ret=ms_list_append(ret,route); - } - sal_address_destroy(proxy_addr); + 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; } diff --git a/gtk/propertybox.c b/gtk/propertybox.c index dd6424dac..8579fc2f4 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1139,7 +1139,6 @@ static gboolean apply_transports(PortConfigCtx *ctx){ linphone_core_get_sip_transports(lc,&tp); tp.udp_port=ctx->tp.udp_port; tp.tcp_port=ctx->tp.tcp_port; - g_message("new transports: %i, %i, %i",(int)tp.udp_port,(int)tp.tcp_port,(int)tp.tls_port); linphone_core_set_sip_transports(lc,&tp); g_object_set_data(G_OBJECT(mw),"port_config",NULL); return FALSE; From 12f8197d47604c84338a5341cdae5ce9b8a6f97b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 17:09:16 +0100 Subject: [PATCH 909/909] updated for latest gtk+2 bundle --- Makefile.am | 2 +- README.mingw | 12 ++--- gen-gtkfilelist.sh | 2 - gtk+-2.24.8.filelist | 125 +++++++++++++++++++++++++++++-------------- 4 files changed, 93 insertions(+), 48 deletions(-) diff --git a/Makefile.am b/Makefile.am index a5bdf24f8..e9403361f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -113,7 +113,7 @@ other-cherrypick: /mingw/bin/libintl-8.dll \ /mingw/bin/libiconv-2.dll \ /mingw/bin/pthreadGC2.dll \ - $(INSTALLDIR_WITH_PREFIX)/bin/. \ + $(INSTALLDIR_WITH_PREFIX)/bin/. ;\ fi diff --git a/README.mingw b/README.mingw index 39b41d3df..cb1f60c01 100644 --- a/README.mingw +++ b/README.mingw @@ -26,7 +26,7 @@ Download lastest linphone-deps-win32 zip from http://download.savannah.gnu.org/releases-noredirect/linphone/misc using your browser. -Download lastest gtk+2 win32 bundle from http://www.gtk.org +Download lastest gtk+-2.24.10 win32 _bundle_ from http://www.gtk.org Install all these three package in /: @@ -70,14 +70,14 @@ Kill it. Don't know what it is, but once killed, windows runs normally. ./autogen.sh -./configure --prefix=/opt/linphone --enable-shared --disable-static +./configure --prefix=/usr --enable-shared --disable-static #note: in order to use the tunnel, append --enable-tunnel to the configure line above. #compile: make -#now install to /opt/linphone, required for compilation of plugins. +#now install to /usr, required for compilation of plugins. make install @@ -96,7 +96,7 @@ make setup.exe #build plugins cd mediastreamer2/plugins/msx264 ./autogen.sh -PKG_CONFIG_PATH=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static +PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static #make a binary zip of this plugin make zip #or make an installer @@ -105,7 +105,7 @@ make setup.exe #the buddylookup plugin enables lookup of buddies in a remote database using xml-rpc over http/https. cd coreapi/plugins/buddylookup ./autogen.sh -PKG_CONFIG_PATH=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static +PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static make #make a binary zip of this plugin make zip @@ -129,7 +129,7 @@ libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these 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) diff --git a/gen-gtkfilelist.sh b/gen-gtkfilelist.sh index 15a5b8812..095c4979c 100755 --- a/gen-gtkfilelist.sh +++ b/gen-gtkfilelist.sh @@ -16,7 +16,6 @@ find share/locale/hu find share/locale/it find share/locale/ja find share/locale/nb -find share/locale/nb_NO find share/locale/nl find share/locale/pl find share/locale/pt @@ -24,7 +23,6 @@ find share/locale/pt_BR find share/locale/ru find share/locale/sr find share/locale/sv -find share/locale/zh find share/locale/zh_CN find share/locale/zh_TW find share/themes diff --git a/gtk+-2.24.8.filelist b/gtk+-2.24.8.filelist index 4779780b1..019823eae 100644 --- a/gtk+-2.24.8.filelist +++ b/gtk+-2.24.8.filelist @@ -1,15 +1,15 @@ 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/libffi-5.dll bin/libfontconfig-1.dll -bin/libfreetype-6.dll -bin/libintl-8.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 @@ -18,14 +18,11 @@ 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/libiconv-2.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/libpixman-1-0.dll -bin/libpng15-15.dll -bin/libxml2-2.dll +bin/libpng14-14.dll bin/zlib1.dll lib/gtk-2.0 lib/gtk-2.0/2.10.0 @@ -37,6 +34,9 @@ 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 @@ -45,30 +45,6 @@ etc/gtk-2.0/gtk.immodules etc/gtk-2.0/im-multipress.conf etc/pango etc/pango/pango.modules -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/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/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/cs share/locale/cs/LC_MESSAGES share/locale/cs/LC_MESSAGES/atk10.mo @@ -77,6 +53,14 @@ 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 @@ -85,6 +69,21 @@ 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 @@ -108,6 +107,14 @@ 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 @@ -124,14 +131,14 @@ 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/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/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 @@ -140,6 +147,46 @@ share/locale/pt_BR/LC_MESSAGES/gettext-runtime.mo share/locale/pt_BR/LC_MESSAGES/glib20.mo share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo share/locale/pt_BR/LC_MESSAGES/gtk20.mo +share/locale/ru +share/locale/ru/LC_MESSAGES +share/locale/ru/LC_MESSAGES/atk10.mo +share/locale/ru/LC_MESSAGES/gdk-pixbuf.mo +share/locale/ru/LC_MESSAGES/gettext-runtime.mo +share/locale/ru/LC_MESSAGES/glib20.mo +share/locale/ru/LC_MESSAGES/gtk20-properties.mo +share/locale/ru/LC_MESSAGES/gtk20.mo +share/locale/sr +share/locale/sr/LC_MESSAGES +share/locale/sr/LC_MESSAGES/atk10.mo +share/locale/sr/LC_MESSAGES/gdk-pixbuf.mo +share/locale/sr/LC_MESSAGES/gettext-runtime.mo +share/locale/sr/LC_MESSAGES/glib20.mo +share/locale/sr/LC_MESSAGES/gtk20-properties.mo +share/locale/sr/LC_MESSAGES/gtk20.mo +share/locale/sv +share/locale/sv/LC_MESSAGES +share/locale/sv/LC_MESSAGES/atk10.mo +share/locale/sv/LC_MESSAGES/gdk-pixbuf.mo +share/locale/sv/LC_MESSAGES/gettext-runtime.mo +share/locale/sv/LC_MESSAGES/glib20.mo +share/locale/sv/LC_MESSAGES/gtk20-properties.mo +share/locale/sv/LC_MESSAGES/gtk20.mo +share/locale/zh_CN +share/locale/zh_CN/LC_MESSAGES +share/locale/zh_CN/LC_MESSAGES/atk10.mo +share/locale/zh_CN/LC_MESSAGES/gdk-pixbuf.mo +share/locale/zh_CN/LC_MESSAGES/gettext-runtime.mo +share/locale/zh_CN/LC_MESSAGES/glib20.mo +share/locale/zh_CN/LC_MESSAGES/gtk20-properties.mo +share/locale/zh_CN/LC_MESSAGES/gtk20.mo +share/locale/zh_TW +share/locale/zh_TW/LC_MESSAGES +share/locale/zh_TW/LC_MESSAGES/atk10.mo +share/locale/zh_TW/LC_MESSAGES/gdk-pixbuf.mo +share/locale/zh_TW/LC_MESSAGES/gettext-runtime.mo +share/locale/zh_TW/LC_MESSAGES/glib20.mo +share/locale/zh_TW/LC_MESSAGES/gtk20-properties.mo +share/locale/zh_TW/LC_MESSAGES/gtk20.mo share/themes share/themes/Default share/themes/Default/gtk-2.0-key